Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 115
- Log:
Updated for use with HubSsoLib 0.1.0 (Changeset #113).
- Author:
- adh
- Date:
- Fri Oct 27 16:01:11 +0100 2006
- Size:
- 6464 Bytes
1 | # RCVSweb - a Ruby On Rails wrapper around the Perl-based FreeBSD |
2 | # version of the CVSweb and Python-based CVShistory. |
3 | # |
4 | # See "http://www.freebsd.org/projects/cvsweb.html" and |
5 | # "http://www.jamwt.com/CVSHistory/" |
6 | # |
7 | # This wrapper was created for the sole purpose of embedding CVSweb |
8 | # output into a Rails-provided layout. This layout is shared between |
9 | # different Rails applications on one host. Using the wrapper means |
10 | # that it is not necessary to create a derived copy of the layout |
11 | # expressed in a form that CVSweb understands - instead, the layout |
12 | # can be used directly. |
13 | # |
14 | # Later extensions to the application gave it the ability to wrap |
15 | # CVShistory output too. |
16 | |
17 | class ApplicationController < ActionController::Base |
18 | |
19 | # Hub single sign-on support. |
20 | |
21 | require 'hub_sso_lib' |
22 | include HubSsoLib::Core |
23 | before_filter :hubssolib_beforehand |
24 | after_filter :hubssolib_afterwards |
25 | |
26 | # Turn of session management. |
27 | |
28 | session :off |
29 | |
30 | # The root URL action. |
31 | # |
32 | def index |
33 | redirect_to url_for(:controller => 'rcvsweb', :action => 'run') |
34 | end |
35 | |
36 | private |
37 | |
38 | # Pass the fully qualified pathname of the script that is to be |
39 | # executed and a path prefix from routing (e.g. "/view"). |
40 | |
41 | def capture_script_output(script_location, extra_prefix) |
42 | # Get the request URI in a way that works for FCGI and regular |
43 | # CGI, at least for LightTPD. Strip off the PATH_PREFIX (location |
44 | # of the Rails application) if present. |
45 | |
46 | uri = @request.env['REQUEST_URI'].dup |
47 | uri.slice!(PATH_PREFIX + '/') |
48 | |
49 | # Split off the query string section, if there is one. |
50 | |
51 | (path_info, query) = uri.split('?') |
52 | |
53 | # The CGI script expects certain variables to be set up in a |
54 | # certain way. "Slow" CGI does this but FastCGI does not because |
55 | # the script executes under a different process environment |
56 | # entirely, without the benefit of server-set variables. We must |
57 | # therefore emulate the required environment by setting system |
58 | # variables before executing the CVSweb script. |
59 | |
60 | command = '' |
61 | needed = %w( |
62 | HTTP_USER_AGENT HTTP_ACCEPT_ENCODING |
63 | MOD_PERL PATH_INFO |
64 | SCRIPT_NAME SCRIPT_FILENAME |
65 | QUERY_STRING SERVER_PROTOCOL |
66 | SERVER_PORT SERVER_NAME |
67 | ) |
68 | |
69 | needed.each do |key| |
70 | |
71 | # Override certain items where we know we want a particular |
72 | # result, else use a server-set value if there is one. |
73 | |
74 | case key |
75 | when 'SCRIPT_NAME' |
76 | value = PATH_PREFIX + extra_prefix |
77 | when 'SCRIPT_FILENAME' |
78 | value = "#{RAILS_ROOT}/public/dispatch.cgi" |
79 | when 'PATH_INFO' |
80 | value = path_info || '' |
81 | value = '/' + value unless (value[0] == '/') |
82 | value = value[extra_prefix.length..-1] if (value[0..(extra_prefix.length - 1)] == extra_prefix) |
83 | when 'QUERY_STRING' |
84 | value = query |
85 | else |
86 | value = @request.env[key] || '' |
87 | end |
88 | |
89 | # Add the variable initialisation statement to the command string. |
90 | |
91 | command += "#{key}=\"#{value}\" " |
92 | |
93 | end # From needed.each |
94 | |
95 | # Add the CVSweb command to the command string and execute it. |
96 | # Return the output of the command. |
97 | |
98 | command += "#{script_location}" |
99 | return `#{command}` |
100 | end |
101 | |
102 | # Parse script output - pass the raw output data from the script and a |
103 | # filename to use in the event that the output isn't of a recognised type |
104 | # and has to be sent raw to the client. |
105 | |
106 | def parse_script_output(output, filename) |
107 | # The Views expect to use the @output instance variable, so we operate |
108 | # on that from the beginning. |
109 | |
110 | @output = output |
111 | |
112 | # The command should have included HTTP headers; split the two. |
113 | |
114 | pos = @output.index("\r\n\r\n") |
115 | short = true unless pos |
116 | pos = @output.index("\n\n") unless pos |
117 | headstr = @output.slice!(0..pos + (short ? 1 : 3)) if pos |
118 | headers = {} |
119 | |
120 | if (headstr) |
121 | |
122 | # There are indeed some headers. Create a hash from them. |
123 | |
124 | headstr.downcase.split(short ? "\n" : "\r\n").each do |str| |
125 | pos = str.index(':') |
126 | headers[str.slice!(0..pos - 1).strip] = str[1..-1].strip if (pos > 1) |
127 | end |
128 | |
129 | # If we find a Status header with a 300-series code, check for a |
130 | # Location header too. If found, redirect to that location. |
131 | |
132 | if (headers['status']) |
133 | code = headers['status'].to_i |
134 | |
135 | if (code >= 300 and code < 400 and headers['location']) |
136 | redirect_to headers['location'] |
137 | return |
138 | end |
139 | end |
140 | |
141 | # For a content type of 'text/html', render within a View. Otherwise |
142 | # send the data directly without a surrounding template. |
143 | |
144 | if ([ 'text/html', 'text/x-html' ].include? headers['content-type']) |
145 | |
146 | # Almost there - extract a title if we can, and chop off the header |
147 | # and footer (HTML prologue and epilogue) to attempt to produce |
148 | # valid (X)HTML. The version of CVSweb in use at the time of writing |
149 | # always writes body and title container tags in lower case which |
150 | # helps save a bit of effort. |
151 | |
152 | title_tag = @output.slice(/<title.*\/title>/) |
153 | title_tag.gsub!(/<title.*?>/, '') |
154 | @title = title_tag.gsub(/<\/title>/, '') || 'CVS Repository' |
155 | |
156 | # Chop everything from the front of the output string up to the end |
157 | # of the opening body tag, inclusive. |
158 | |
159 | body_tag = @output.slice(/<body.*?>/) |
160 | body_pos = @output.index('<body') |
161 | |
162 | if (body_pos && body_tag && body_tag.length > 0) |
163 | @output.slice!(0..body_pos + body_tag.length - 1) |
164 | end |
165 | |
166 | # Chop off anything after the closing body tag too. |
167 | |
168 | body_pos = @output.index('</body') |
169 | @output.slice!(body_pos..-1) if body_pos |
170 | |
171 | # Render the default layout to send the template-based output. |
172 | |
173 | render :layout => 'default' |
174 | |
175 | else |
176 | |
177 | # Apparently, not HTML; send the data directly. |
178 | |
179 | type = headers['content-type'] || 'application/octet-stream' |
180 | send_data @output, |
181 | :type => type, |
182 | :disposition => 'inline' |
183 | end |
184 | |
185 | else |
186 | |
187 | # CVSweb output had no HTTP header - this is unexpected. We don't |
188 | # understand its output so just send this to the browser as a |
189 | # stream of binary data. |
190 | |
191 | send_data @output, |
192 | :filename => filename, |
193 | :type => 'application/octet-stream' |
194 | end |
195 | end |
196 | end |