yaws 1.73 compatibility
[fuzed.git] / bin / fuzed-adapter
blob7bdfbf15afa27fdad31b24fe719712c51f693809
1 #!/usr/bin/env ruby
3 rails_root = ARGV[0]
5 require File.join(rails_root, 'config/boot')
6 require RAILS_ROOT + "/config/environment"
8 require 'erlectricity'
9 require 'stringio'
10 require 'logger'
12 LOG = true
14 $total_avg = [0, 0]
15 $rails_avg = [0, 0]
16 $logger = Logger.new(RAILS_ROOT + "/log/fuzed.#{Process.pid}.log")
18 def log(msg)
19 $logger << msg + "\n"
20 end
22 module Rack
23 module Handler
24 class Fuzed
25 def self.run(app)
26 Fuzed.new(app).listen
27 end
29 def initialize(app)
30 @app = app
31 end
33 def listen
34 log "Waiting for connections" if LOG
36 me = self
38 receive(IO.new(3), IO.new(4)) do |f|
39 f.when(:request, Array) do |request|
40 $t = Time.now
41 log('------------MATCH------------')
42 log request.inspect
43 res = me.service(request)
45 # res = [:response,
46 # [[:status, 200],
47 # [:allheaders, [
48 # [:header, "Content-Type", "text/plain; charset=utf-8"],
49 # [:header, "Cache-Control", "no-cache"]]],
50 # [:html, "ok"]]]
52 f.send!(res)
53 total_delta = Time.now - $t
54 $total_avg[0] += total_delta
55 $total_avg[1] += 1
56 log(">> Total in #{total_delta} (#{$total_avg[0] / $total_avg[1]} avg) sec\n") if LOG
57 f.receive_loop
58 end
60 f.when(:ping) do
61 f.send!(:pong)
62 f.receive_loop
63 end
65 f.when(Any) do |obj|
66 log('------------NO-MATCH------------') if LOG
67 log any.inspect if LOG
68 f.receive_loop
69 end
70 end
71 end
73 def service(vars)
74 request = vars.inject({}) { |a, x| a[x[0]] = x[1]; a }
76 method = request[:method]
77 version = request[:http_version] # => e.g. [1, 1]
78 path = request[:querypath]
79 query = request[:querydata] == :undefined ? '' : request[:querydata]
80 server = request[:servername]
81 headers = request[:headers]
82 cookies = request[:cookies]
83 postdata = request[:postdata] == :undefined ? '' : request[:postdata]
85 translate = {:content_type => 'CONTENT_TYPE',
86 :content_length => 'CONTENT_LENGTH',
87 :accept => 'HTTP_ACCEPT',
88 :'Accept-Charset' => 'HTTP_ACCEPT_CHARSET',
89 :'Accept-Encoding' => 'HTTP_ACCEPT_ENCODING',
90 :'Accept-Language' => 'HTTP_ACCEPT_LANGUAGE',
91 :connection => 'HTTP_CONNECTION',
92 :keep_alive => 'HTTP_KEEP_ALIVE',
93 :host => 'HTTP_HOST',
94 :referer => 'HTTP_REFERER',
95 :user_agent => 'HTTP_USER_AGENT',
96 'X-Prototype-Version' => 'HTTP_X_PROTOTYPE_VERSION',
97 'X-Requested-With' => 'HTTP_X_REQUESTED_WITH'}
99 env = {}
100 env['REQUEST_METHOD'] = method.to_s
101 env['QUERY_STRING'] = query
102 env["PATH_INFO"] = path == '/' ? '' : path
103 env = headers.inject(env) { |a, x| a[translate[x[0]] || x[0].to_s] = x[1]; a }
104 env.delete_if { |k, v| v.nil? }
106 env.update({"rack.version" => [0, 1],
107 "rack.input" => StringIO.new(postdata),
108 "rack.errors" => STDERR,
110 "rack.multithread" => true,
111 "rack.multiprocess" => false,
112 "rack.run_once" => false,
114 "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
117 env['SERVER_NAME'] = server.split(':')[0]
118 env['SERVER_PORT'] = server.split(':')[1]
119 env['HTTP_VERSION'] = version.join('.')
121 env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
122 env["QUERY_STRING"] ||= ""
123 env["REQUEST_PATH"] ||= "/"
124 env.delete "PATH_INFO" if env["PATH_INFO"] == ""
126 cookies.each do |cookie|
127 env["HTTP_COOKIE"] = cookie.to_s
130 log('------------IN------------') if LOG
131 log(env.inspect) if LOG
133 begin
134 t1 = Time.now
136 # status = '200'
137 # headers = {}
138 # body = ['foo']
140 status, headers, body = @app.call(env)
142 rails_delta = Time.now - t1
143 $rails_avg[0] += rails_delta
144 $rails_avg[1] += 1
145 log(">> Rails in #{rails_delta} (#{$rails_avg[0] / $rails_avg[1]} avg) sec") if LOG
147 html = ''
148 body.each do |part|
149 html << part
152 headers['Server'] = 'YAWS + Fuzed 0.0.1'
153 headers['Connection'] = 'close'
155 cookies = headers.delete('cookie')
156 #cookies.map! {|c| c.include?('path=') ? c : c + "; path=/"}
157 headers['Set-Cookie'] = cookies if cookies
159 # p headers
161 status = (headers["Status"].split(" ").first rescue nil) || status
162 headers.delete("Status") if headers["Status"]
164 res =
165 [:response,
166 [[:status, status.to_i],
167 [:allheaders, headers.inject([]) { |a, x| a += x[1].map { |y| [:header, x[0], y] } }],
168 [:html, html]]]
169 rescue => e
170 res =
171 [:response,
172 [[:status, 500],
173 [:allheaders, [
174 [:header, "Content-Type", "text/plain; charset=utf-8"],
175 [:header, "Cache-Control", "no-cache"]]],
176 [:html, "500 Internal Error\n\n#{e}\n\n#{e.backtrace}"]]]
179 log('-----------OUT------------') if LOG
180 log(res.inspect) if LOG
188 ###############################################################################
190 unless defined? RAILS_ROOT
191 raise "Rails' environment has to be loaded before using Rack::Adapter::Rails"
194 require "rack/request"
195 require "rack/response"
196 require "dispatcher"
198 module Rack
199 module Adapter
200 class Rails
201 def call(env)
202 request = Request.new(env)
203 response = Response.new
205 cgi = CGIStub.new(request, response)
207 Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response)
209 response.finish
212 protected
214 class CGIStub < ::CGI
216 def initialize(request, response, *args)
217 @request = request
218 @response = response
219 @args = *args
220 @input = request.body
221 super(*args)
224 IGNORED_HEADERS = [ "Status" ]
226 def header(options = "text/html")
227 # puts 'header---------------'
228 # p options
229 # puts '---------------------'
231 if options.instance_of?(String)
232 @response['Content-Type'] = options unless @response['Content-Type']
233 else
234 @response['Content-Length'] = options.delete('Content-Length').to_s if options['Content-Length']
236 @response['Content-Type'] = options.delete('type') || "text/html"
237 @response['Content-Type'] += "; charset=" + options.delete('charset') if options['charset']
239 @response['Status'] = options.delete('Status') if options['Status']
240 @response['Content-Language'] = options.delete('language') if options['language']
241 @response['Expires'] = options.delete('expires') if options['expires']
243 IGNORED_HEADERS.each {|k| options.delete(k) }
245 options.each{|k,v| @response[k] = v}
247 # convert 'cookie' header to 'Set-Cookie' headers
248 if cookie = @response['cookie']
249 case cookie
250 when Array
251 cookie.each {|c| @response['Set-Cookie'] = c.to_s }
252 when Hash
253 cookie.each_value {|c| @response['Set-Cookie'] = c.to_s}
254 else
255 @response['Set-Cookie'] = options['cookie'].to_s
258 @output_cookies.each { |c| @response['Set-Cookie'] = c.to_s } if @output_cookies
265 def params
266 @params ||= @request.params
269 def cookies
270 @request.cookies
273 def query_string
274 @request.query_string
277 # Used to wrap the normal args variable used inside CGI.
278 def args
279 @args
282 # Used to wrap the normal env_table variable used inside CGI.
283 def env_table
284 @request.env
287 # Used to wrap the normal stdinput variable used inside CGI.
288 def stdinput
289 @input
292 def stdoutput
293 STDERR.puts "stdoutput should not be used."
294 @response.body
295 end
301 ###############################################################################
303 require 'rack'
304 require 'rack/cascade'
305 require 'rack/showexceptions'
306 # Rack::Handler::Fuzed.run \
307 # Rack::ShowExceptions.new(Rack::Lint.new(Rack::Adapter::Rails.new))
309 if ARGV.first != 'test'
310 Rack::Handler::Fuzed.run(Rack::Adapter::Rails.new)
311 else
312 req =
313 [[:method, :POST], [:http_version, [1, 1]], [:querypath, "/main/go"], [:querydata, ""], [:servername, "testing:8002"], [:headers, [[:connection, "keep-alive"], [:accept, "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"], [:host, "localhost:8002"], [:referer, "http://localhost:8002/main/ready"], [:user_agent, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3"], [:keep_alive, "300"], [:content_length, "7"], [:content_type, "application/x-www-form-urlencoded"], [:"Cache-Control", "max-age=0"], [:"Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"], [:"Accept-Encoding", "gzip,deflate"], [:"Accept-Language", "en-us,en;q=0.5"]]], [:cookies, ["_helloworld_session_id=d3eae987aab3230377abc433b7a8d7c1"]], [:pathinfo, "/Users/tom/dev/fuzed/helloworld/public"], [:postdata, "val=foo"]]
315 # [[:method, :GET], [:http_version, [1, 1]], [:querypath, "/main/say"], [:querydata, ""], [:servername, "testing:8002"], [:headers, [[:connection, "keep-alive"], [:accept, "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"], [:host, "localhost:8002"], [:user_agent, "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3"], [:keep_alive, "300"], [:"Cache-Control", "max-age=0"], [:"Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"], [:"Accept-Encoding", "gzip,deflate"], [:"Accept-Language", "en-us,en;q=0.5"]]], [:cookies, ["_helloworld_session_id=166098a3c3f702698d0529c6148c6164"]], [:pathinfo, "/Users/tom/dev/fuzed/helloworld/public"], [:postdata, :undefined]]
317 p Rack::Handler::Fuzed.new(Rack::Adapter::Rails.new).service(req)