source: contrib/uwsgi.rb @ 365:6ce4b4ac3505

Revision 365:6ce4b4ac3505, 3.5 KB checked in by roberto@…, 2 years ago (diff)

fix for ruby 1.8.6

Line 
1require 'socket'
2require 'rack/content_length'
3require 'rack/rewindable_input'
4require 'stringio'
5
6module Rack
7  module Handler
8    class Uwsgi
9
10      def self.run(app, options={})
11        if ENV['UWSGI_FD']
12          server = UNIXServer.for_fd(ENV['UWSGI_FD'].to_i)
13        else
14          server = TCPServer.new(options[:Host], options[:Port])
15        end
16        while client = server.accept
17          serve client, app
18        end
19      end
20
21      def self.serve(client, app)
22
23        head, sender = client.recvfrom(4)
24
25        unless head
26          client.close
27          return
28        end
29       
30        mod1, size, mod2 = head.unpack('CvC')
31
32        if size == 0 or size.nil?
33          client.close
34          return
35        end
36
37        vars, sender = client.recvfrom(size)
38
39        if vars.length != size
40          client.close
41          return
42        end
43
44        env = Hash.new
45
46        i = 0
47        while i < size
48          kl = vars[i, 2].unpack('v')[0]
49          i = i + 2
50          key = vars[i, kl]
51          i = i + kl
52          vl = vars[i, 2].unpack('v')[0]
53          i = i + 2
54          value = vars[i, vl]
55          i = i + vl
56          env[key] = value
57        end
58
59
60
61        env.delete "HTTP_CONTENT_LENGTH"
62        env.delete "HTTP_CONTENT_TYPE"
63
64        env["SCRIPT_NAME"] = ""  if env["SCRIPT_NAME"] == "/"
65        env["QUERY_STRING"] ||= ""
66        env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
67        env["REQUEST_PATH"] ||= "/"
68        env.delete "PATH_INFO"  if env["PATH_INFO"] == ""
69        env.delete "CONTENT_TYPE"  if env["CONTENT_TYPE"] == ""
70        env.delete "CONTENT_LENGTH"  if env["CONTENT_LENGTH"] == ""
71       
72       
73        if env["CONTENT_LENGTH"].to_i > 4096
74                rack_input = Rack::RewindableInput::Tempfile.new('Rack_uwsgi_Input')
75                rack_input.chmod(0000)
76                rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
77                rack_input.binmode
78                if RUBY_PLATFORM !~ /(mswin|mingw|cygwin|java)/
79                  rack_input.unlink
80                end
81
82                remains = env["CONTENT_LENGTH"].to_i
83                while remains > 0
84                        if remains >= 4096
85                                buf, sender = client.recvfrom(4096)
86                        else
87                                buf, sender = client.recvfrom(remains)
88                        end
89
90                        rack_input.write( buf )
91                        remains -= buf.length
92                end
93
94        elsif env["CONTENT_LENGTH"].to_i > 0
95                rack_input =  StringIO.new(client.recvfrom(env["CONTENT_LENGTH"].to_i)[0])
96        else
97                rack_input = StringIO.new('')
98        end
99
100        rack_input.rewind
101
102        env.update({"rack.version" => [1,1],
103                     "rack.input" => rack_input,
104                     "rack.errors" => $stderr,
105
106                     "rack.multithread" => false,
107                     "rack.multiprocess" => true,
108                     "rack.run_once" => false,
109
110                     "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
111                   })
112
113
114        app = Rack::ContentLength.new(app)
115
116        begin
117          status, headers, body = app.call(env)
118          begin
119            send_headers client, env["HTTP_VERSION"] ,status, headers
120            send_body client, body
121          ensure
122            body.close  if body.respond_to? :close
123          end
124        rescue Errno::EPIPE, Errno::ECONNRESET
125        ensure
126          rack_input.close
127          client.close
128        end
129      end
130
131      def self.send_headers(client, protocol, status, headers)
132        client.print "#{protocol} #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
133        headers.each { |k, vs|
134          vs.split("\n").each { |v|
135            client.print "#{k}: #{v}\r\n"
136          }
137        }
138        client.print "\r\n"
139        client.flush
140      end
141
142      def self.send_body(client, body)
143        body.each { |part|
144          client.print part
145          client.flush
146        }
147      end
148    end
149  end
150end
Note: See TracBrowser for help on using the repository browser.