Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 81
- Log:
Now handles HTTP 3xx responses from CVSweb, turning them into
Rails redirections. Searches for modules work much better as
a result.
- Author:
- adh
- Date:
- Tue Aug 08 23:05:57 +0100 2006
- Size:
- 4800 Bytes
1 | class RcvswebController < ApplicationController |
2 | |
3 | # All routes lead to the 'run' method, which invokes CVSweb based |
4 | # on the request URL and embeds the result in a View. |
5 | |
6 | def run |
7 | |
8 | # Get the request URI in a way that works for FCGI and regular |
9 | # CGI, at least for LightTPD. Strip off the PATH_PREFIX (location |
10 | # of the Rails application) if present. |
11 | |
12 | uri = @request.env['REQUEST_URI'].dup |
13 | uri.slice!(PATH_PREFIX + '/') |
14 | |
15 | # Split off the query string section, if there is one. |
16 | |
17 | (path_info, query) = uri.split('?') |
18 | |
19 | # The CGI script expects certain variables to be set up in a |
20 | # certain way. "Slow" CGI does this but FastCGI does not because |
21 | # the script executes under a different process environment |
22 | # entirely, without the benefit of server-set variables. We must |
23 | # therefore emulate the required environment by setting system |
24 | # variables before executing the CVSweb script. |
25 | |
26 | command = '' |
27 | needed = %w( |
28 | HTTP_USER_AGENT HTTP_ACCEPT_ENCODING |
29 | MOD_PERL PATH_INFO |
30 | SCRIPT_NAME SCRIPT_FILENAME |
31 | QUERY_STRING |
32 | ) |
33 | |
34 | needed.each do |key| |
35 | |
36 | # Override certain items where we know we want a particular |
37 | # result, else use a server-set value if there is one. |
38 | |
39 | case key |
40 | when 'SCRIPT_NAME' |
41 | value = PATH_PREFIX |
42 | when 'SCRIPT_FILENAME' |
43 | value = "#{RAILS_ROOT}/public/dispatch.cgi" |
44 | when 'PATH_INFO' |
45 | value = path_info || '' |
46 | value = '/' + value unless (value[0] == '/') |
47 | when 'QUERY_STRING' |
48 | value = query |
49 | else |
50 | value = @request.env[key] || '' |
51 | end |
52 | |
53 | # Add the variable initialisation statement to the command string. |
54 | |
55 | command += "#{key}=\"#{value}\" " |
56 | |
57 | end # From needed.each |
58 | |
59 | # Add the CVSweb command to the command string and execute it. |
60 | # We have to put this in an instance variable rather than a |
61 | # temporary variable as otherwise send_data doesn't work... |
62 | |
63 | command += "#{CVSWEB_LOCATION}" |
64 | @output = `#{command}` |
65 | |
66 | # The command should have included HTTP headers; split the two. |
67 | |
68 | pos = @output.index("\r\n\r\n") |
69 | headstr = @output.slice!(0..pos + 3) if pos |
70 | headers = {} |
71 | |
72 | if (headstr) |
73 | |
74 | # There are indeed some headers. Create a hash from them. |
75 | |
76 | headstr.downcase.split("\r\n").each do |str| |
77 | pos = str.index(':') |
78 | headers[str.slice!(0..pos - 1).strip] = str[1..-1].strip if (pos > 1) |
79 | end |
80 | |
81 | # If we find a Status header with a 300-series code, check for a |
82 | # Location header too. If found, redirect to that location. |
83 | |
84 | if (headers['status']) |
85 | code = headers['status'].to_i |
86 | |
87 | if (code >= 300 and code < 400 and headers['location']) |
88 | redirect_to headers['location'] |
89 | return |
90 | end |
91 | end |
92 | |
93 | # For a content type of 'text/html', render within a View. Otherwise |
94 | # send the data directly without a surrounding template. |
95 | |
96 | if ([ 'text/html', 'text/x-html' ].include? headers['content-type']) |
97 | |
98 | # Almost there - extract a title if we can, and chop off the header |
99 | # and footer (HTML prologue and epilogue) to attempt to produce |
100 | # valid (X)HTML. The version of CVSweb in use at the time of writing |
101 | # always writes body and title container tags in lower case which |
102 | # helps save a bit of effort. |
103 | |
104 | title_tag = @output.slice(/<title.*\/title>/) |
105 | title_tag.gsub!(/<title.*?>/, '') |
106 | @title = title_tag.gsub(/<\/title>/, '') || 'CVS Repository' |
107 | |
108 | # Chop everything from the front of the output string up to the end |
109 | # of the opening body tag, inclusive. |
110 | |
111 | body_tag = @output.slice(/<body.*?>/) |
112 | body_pos = @output.index('<body') |
113 | |
114 | if (body_pos && body_tag && body_tag.length > 0) |
115 | @output.slice!(0..body_pos + body_tag.length - 1) |
116 | end |
117 | |
118 | # Chop off anything after the closing body tag too. |
119 | |
120 | body_pos = @output.index('</body') |
121 | @output.slice!(body_pos..-1) if body_pos |
122 | |
123 | # Render the default layout to send the template-based output. |
124 | |
125 | render :layout => 'default' |
126 | |
127 | else |
128 | |
129 | # Apparently, not HTML; send the data directly. |
130 | |
131 | type = headers['content-type'] || 'application/octet-stream' |
132 | send_data @output, |
133 | :type => type, |
134 | :disposition => 'inline' |
135 | end |
136 | |
137 | else |
138 | |
139 | # CVSweb output had no HTTP header - this is unexpected. We don't |
140 | # understand its output so just send this to the browser as a |
141 | # stream of binary data. |
142 | |
143 | send_data @output, |
144 | :filename => 'rcvsweb.dat', |
145 | :type => 'application/octet-stream' |
146 | end |
147 | end |
148 | end |