rack 1.4.7 → 1.5.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/README.rdoc +2 -30
- data/Rakefile +1 -0
- data/SPEC +68 -4
- data/example/protectedlobster.rb +1 -1
- data/lib/rack.rb +2 -14
- data/lib/rack/auth/abstract/request.rb +1 -5
- data/lib/rack/builder.rb +8 -4
- data/lib/rack/cascade.rb +2 -2
- data/lib/rack/config.rb +5 -0
- data/lib/rack/deflater.rb +2 -1
- data/lib/rack/file.rb +25 -28
- data/lib/rack/handler.rb +18 -5
- data/lib/rack/handler/mongrel.rb +1 -1
- data/lib/rack/handler/scgi.rb +1 -1
- data/lib/rack/handler/thin.rb +6 -3
- data/lib/rack/handler/webrick.rb +1 -0
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +132 -7
- data/lib/rack/lobster.rb +3 -3
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/methodoverride.rb +0 -2
- data/lib/rack/mime.rb +29 -0
- data/lib/rack/multipart/parser.rb +0 -9
- data/lib/rack/request.rb +66 -25
- data/lib/rack/response.rb +1 -2
- data/lib/rack/sendfile.rb +18 -4
- data/lib/rack/server.rb +20 -12
- data/lib/rack/session/abstract/id.rb +60 -59
- data/lib/rack/session/cookie.rb +11 -16
- data/lib/rack/utils.rb +97 -85
- data/rack.gemspec +1 -6
- data/test/spec_builder.rb +7 -0
- data/test/spec_cgi.rb +1 -1
- data/test/spec_chunked.rb +3 -5
- data/test/spec_content_length.rb +3 -6
- data/test/spec_deflater.rb +26 -9
- data/test/spec_fastcgi.rb +1 -1
- data/test/spec_file.rb +24 -11
- data/test/spec_head.rb +3 -8
- data/test/spec_lint.rb +6 -6
- data/test/spec_lock.rb +4 -7
- data/test/spec_methodoverride.rb +4 -1
- data/test/spec_mime.rb +51 -0
- data/test/spec_mongrel.rb +1 -1
- data/test/spec_multipart.rb +15 -49
- data/test/spec_nulllogger.rb +3 -6
- data/test/spec_request.rb +112 -18
- data/test/spec_response.rb +8 -8
- data/test/spec_sendfile.rb +52 -13
- data/test/spec_server.rb +6 -0
- data/test/spec_session_abstract_id.rb +11 -1
- data/test/spec_session_cookie.rb +140 -153
- data/test/spec_thin.rb +6 -1
- data/test/spec_utils.rb +23 -17
- data/test/spec_webrick.rb +1 -1
- metadata +37 -83
- checksums.yaml +0 -7
- data/test/cgi/lighttpd.errors +0 -1
- data/test/multipart/three_files_three_fields +0 -31
- data/test/spec_auth.rb +0 -57
data/README.rdoc
CHANGED
@@ -29,6 +29,7 @@ These web servers include Rack handlers in their distributions:
|
|
29
29
|
* Phusion Passenger (which is mod_rack for Apache and for nginx)
|
30
30
|
* Puma
|
31
31
|
* Rainbows!
|
32
|
+
* Reel
|
32
33
|
* Unicorn
|
33
34
|
* unixrack
|
34
35
|
* uWSGI
|
@@ -42,6 +43,7 @@ changing anything.
|
|
42
43
|
These frameworks include Rack adapters in their distributions:
|
43
44
|
* Camping
|
44
45
|
* Coset
|
46
|
+
* Espresso
|
45
47
|
* Halcyon
|
46
48
|
* Mack
|
47
49
|
* Maveric
|
@@ -57,9 +59,6 @@ These frameworks include Rack adapters in their distributions:
|
|
57
59
|
* Wee
|
58
60
|
* ... and many others.
|
59
61
|
|
60
|
-
Current links to these projects can be found at
|
61
|
-
http://wiki.ramaze.net/Home#other-frameworks
|
62
|
-
|
63
62
|
== Available middleware
|
64
63
|
|
65
64
|
Between the server and the framework, Rack can be customized to your
|
@@ -479,38 +478,11 @@ run on port 11211) and memcache-client installed.
|
|
479
478
|
* January 7th, 2013: Thirty first public release 1.4.3
|
480
479
|
* Security: Prevent unbounded reads in large multipart boundaries
|
481
480
|
|
482
|
-
* January 13th, 2013: Thirty second public release 1.4.4, 1.3.9, 1.2.7, 1.1.5
|
483
|
-
* [SEC] Rack::Auth::AbstractRequest no longer symbolizes arbitrary strings
|
484
|
-
* Fixed erroneous test case in the 1.3.x series
|
485
|
-
|
486
|
-
* February 7th, Thirty fifth public release 1.1.6, 1.2.8, 1.3.10
|
487
|
-
* Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
|
488
|
-
|
489
|
-
* February 7th, Thirty fifth public release 1.4.5
|
490
|
-
* Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
|
491
|
-
* Fix CVE-2013-0262, symlink path traversal in Rack::File
|
492
|
-
|
493
|
-
* February 7th, Thirty fifth public release 1.5.2
|
494
|
-
* Fix CVE-2013-0263, timing attack against Rack::Session::Cookie
|
495
|
-
* Fix CVE-2013-0262, symlink path traversal in Rack::File
|
496
|
-
* Add various methods to Session for enhanced Rails compatibility
|
497
|
-
* Request#trusted_proxy? now only matches whole stirngs
|
498
|
-
* Add JSON cookie coder, to be default in Rack 1.6+ due to security concerns
|
499
|
-
* URLMap host matching in environments that don't set the Host header fixed
|
500
|
-
* Fix a race condition that could result in overwritten pidfiles
|
501
|
-
* Various documentation additions
|
502
|
-
|
503
481
|
== Contact
|
504
482
|
|
505
483
|
Please post bugs, suggestions and patches to
|
506
484
|
the bug tracker at <http://github.com/rack/rack/issues>.
|
507
485
|
|
508
|
-
Please post security related bugs and suggestions to the core team at
|
509
|
-
<https://groups.google.com/group/rack-core> or rack-core@googlegroups.com. Due
|
510
|
-
to wide usage of the library, it is strongly preferred that we manage timing in
|
511
|
-
order to provide viable patches at the time of disclosure. Your assistance in
|
512
|
-
this matter is greatly appreciated.
|
513
|
-
|
514
486
|
Mailing list archives are available at
|
515
487
|
<http://groups.google.com/group/rack-devel>.
|
516
488
|
|
data/Rakefile
CHANGED
data/SPEC
CHANGED
@@ -49,7 +49,8 @@ below.
|
|
49
49
|
variables should correspond with
|
50
50
|
the presence or absence of the
|
51
51
|
appropriate HTTP header in the
|
52
|
-
request.
|
52
|
+
request. See <a href="https://tools.ietf.org/html/rfc3875#section-4.1.18">
|
53
|
+
RFC3875 section 4.1.18</a> for specific behavior.
|
53
54
|
In addition to this, the Rack environment must include these
|
54
55
|
Rack-specific variables:
|
55
56
|
<tt>rack.version</tt>:: The Array [1,1], representing this version of Rack.
|
@@ -59,6 +60,9 @@ Rack-specific variables:
|
|
59
60
|
<tt>rack.multithread</tt>:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise.
|
60
61
|
<tt>rack.multiprocess</tt>:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise.
|
61
62
|
<tt>rack.run_once</tt>:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar).
|
63
|
+
<tt>rack.hijack?</tt>:: present and true if the server supports connection hijacking. See below, hijacking.
|
64
|
+
<tt>rack.hijack</tt>:: an object responding to #call that must be called at least once before using rack.hijack_io. It is recommended #call return rack.hijack_io as well as setting it in env if necessary.
|
65
|
+
<tt>rack.hijack_io</tt>:: if rack.hijack? is true, and rack.hijack has received #call, this will contain an object resembling an IO. See hijacking.
|
62
66
|
Additional environment specifications have approved to
|
63
67
|
standardized middleware APIs. None of these are required to
|
64
68
|
be implemented by the server.
|
@@ -89,6 +93,7 @@ There are the following restrictions:
|
|
89
93
|
* <tt>rack.url_scheme</tt> must either be +http+ or +https+.
|
90
94
|
* There must be a valid input stream in <tt>rack.input</tt>.
|
91
95
|
* There must be a valid error stream in <tt>rack.errors</tt>.
|
96
|
+
* There may be a valid hijack stream in <tt>rack.hijack_io</tt>
|
92
97
|
* The <tt>REQUEST_METHOD</tt> must be a valid token.
|
93
98
|
* The <tt>SCRIPT_NAME</tt>, if non-empty, must start with <tt>/</tt>
|
94
99
|
* The <tt>PATH_INFO</tt>, if non-empty, must start with <tt>/</tt>
|
@@ -128,12 +133,72 @@ The error stream must respond to +puts+, +write+ and +flush+.
|
|
128
133
|
* +flush+ must be called without arguments and must be called
|
129
134
|
in order to make the error appear for sure.
|
130
135
|
* +close+ must never be called on the error stream.
|
136
|
+
=== Hijacking
|
137
|
+
==== Request (before status)
|
138
|
+
If rack.hijack? is true then rack.hijack must respond to #call.
|
139
|
+
rack.hijack must return the io that will also be assigned (or is
|
140
|
+
already present, in rack.hijack_io.
|
141
|
+
|
142
|
+
rack.hijack_io must respond to:
|
143
|
+
<tt>read, write, read_nonblock, write_nonblock, flush, close,
|
144
|
+
close_read, close_write, closed?</tt>
|
145
|
+
|
146
|
+
The semantics of these IO methods must be a best effort match to
|
147
|
+
those of a normal ruby IO or Socket object, using standard
|
148
|
+
arguments and raising standard exceptions. Servers are encouraged
|
149
|
+
to simply pass on real IO objects, although it is recognized that
|
150
|
+
this approach is not directly compatible with SPDY and HTTP 2.0.
|
151
|
+
|
152
|
+
IO provided in rack.hijack_io should preference the
|
153
|
+
IO::WaitReadable and IO::WaitWritable APIs wherever supported.
|
154
|
+
|
155
|
+
There is a deliberate lack of full specification around
|
156
|
+
rack.hijack_io, as semantics will change from server to server.
|
157
|
+
Users are encouraged to utilize this API with a knowledge of their
|
158
|
+
server choice, and servers may extend the functionality of
|
159
|
+
hijack_io to provide additional features to users. The purpose of
|
160
|
+
rack.hijack is for Rack to "get out of the way", as such, Rack only
|
161
|
+
provides the minimum of specification and support.
|
162
|
+
|
163
|
+
If rack.hijack? is false, then rack.hijack should not be set.
|
164
|
+
|
165
|
+
If rack.hijack? is false, then rack.hijack_io should not be set.
|
166
|
+
==== Response (after headers)
|
167
|
+
It is also possible to hijack a response after the status and headers
|
168
|
+
have been sent.
|
169
|
+
In order to do this, an application may set the special header
|
170
|
+
<tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
|
171
|
+
accepting an argument that conforms to the <tt>rack.hijack_io</tt>
|
172
|
+
protocol.
|
173
|
+
|
174
|
+
After the headers have been sent, and this hijack callback has been
|
175
|
+
called, the application is now responsible for the remaining lifecycle
|
176
|
+
of the IO. The application is also responsible for maintaining HTTP
|
177
|
+
semantics. Of specific note, in almost all cases in the current SPEC,
|
178
|
+
applications will have wanted to specify the header Connection:close in
|
179
|
+
HTTP/1.1, and not Connection:keep-alive, as there is no protocol for
|
180
|
+
returning hijacked sockets to the web server. For that purpose, use the
|
181
|
+
body streaming API instead (progressively yielding strings via each).
|
182
|
+
|
183
|
+
Servers must ignore the <tt>body</tt> part of the response tuple when
|
184
|
+
the <tt>rack.hijack</tt> response API is in use.
|
185
|
+
|
186
|
+
The special response header <tt>rack.hijack</tt> must only be set
|
187
|
+
if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
|
188
|
+
==== Conventions
|
189
|
+
* Middleware should not use hijack unless it is handling the whole
|
190
|
+
response.
|
191
|
+
* Middleware may wrap the IO object for the response pattern.
|
192
|
+
* Middleware should not wrap the IO object for the request pattern. The
|
193
|
+
request pattern is intended to provide the hijacker with "raw tcp".
|
131
194
|
== The Response
|
132
195
|
=== The Status
|
133
196
|
This is an HTTP status. When parsed as integer (+to_i+), it must be
|
134
197
|
greater than or equal to 100.
|
135
198
|
=== The Headers
|
136
199
|
The header must respond to +each+, and yield values of key and value.
|
200
|
+
Special headers starting "rack." are for communicating with the
|
201
|
+
server, and must not be sent back to the client.
|
137
202
|
The header keys must be Strings.
|
138
203
|
The header must not contain a +Status+ key,
|
139
204
|
contain keys with <tt>:</tt> or newlines in their name,
|
@@ -145,9 +210,8 @@ consisting of lines (for multiple header values, e.g. multiple
|
|
145
210
|
<tt>Set-Cookie</tt> values) seperated by "\n".
|
146
211
|
The lines must not contain characters below 037.
|
147
212
|
=== The Content-Type
|
148
|
-
There must be a <tt>Content-Type</tt>,
|
149
|
-
|
150
|
-
given.
|
213
|
+
There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
|
214
|
+
204, 205 or 304.
|
151
215
|
=== The Content-Length
|
152
216
|
There must not be a <tt>Content-Length</tt> header when the
|
153
217
|
+Status+ is 1xx, 204, 205 or 304.
|
data/example/protectedlobster.rb
CHANGED
@@ -11,4 +11,4 @@ protected_lobster.realm = 'Lobster 2.0'
|
|
11
11
|
|
12
12
|
pretty_protected_lobster = Rack::ShowStatus.new(Rack::ShowExceptions.new(protected_lobster))
|
13
13
|
|
14
|
-
Rack::
|
14
|
+
Rack::Server.start :app => pretty_protected_lobster, :Port => 9292
|
data/lib/rack.rb
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
|
12
12
|
module Rack
|
13
13
|
# The Rack protocol version number implemented.
|
14
|
-
VERSION = [1,
|
14
|
+
VERSION = [1,2]
|
15
15
|
|
16
16
|
# Return the Rack protocol version as a dotted string.
|
17
17
|
def self.version
|
@@ -20,7 +20,7 @@ module Rack
|
|
20
20
|
|
21
21
|
# Return the Rack release as a dotted string.
|
22
22
|
def self.release
|
23
|
-
"1.
|
23
|
+
"1.5"
|
24
24
|
end
|
25
25
|
|
26
26
|
autoload :Builder, "rack/builder"
|
@@ -73,18 +73,6 @@ module Rack
|
|
73
73
|
autoload :Params, "rack/auth/digest/params"
|
74
74
|
autoload :Request, "rack/auth/digest/request"
|
75
75
|
end
|
76
|
-
|
77
|
-
# Not all of the following schemes are "standards", but they are used often.
|
78
|
-
@schemes = %w[basic digest bearer mac token oauth oauth2]
|
79
|
-
|
80
|
-
def self.add_scheme scheme
|
81
|
-
@schemes << scheme
|
82
|
-
@schemes.uniq!
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.schemes
|
86
|
-
@schemes.dup
|
87
|
-
end
|
88
76
|
end
|
89
77
|
|
90
78
|
module Session
|
data/lib/rack/builder.rb
CHANGED
@@ -25,7 +25,7 @@ module Rack
|
|
25
25
|
#
|
26
26
|
# run app
|
27
27
|
#
|
28
|
-
# +use+ adds
|
28
|
+
# +use+ adds middleware to the stack, +run+ dispatches to an application.
|
29
29
|
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
30
30
|
|
31
31
|
class Builder
|
@@ -37,8 +37,7 @@ module Rack
|
|
37
37
|
options = opts.parse! $1.split(/\s+/)
|
38
38
|
end
|
39
39
|
cfgfile.sub!(/^__END__\n.*\Z/m, '')
|
40
|
-
app =
|
41
|
-
TOPLEVEL_BINDING, config, 0
|
40
|
+
app = new_from_string cfgfile, config
|
42
41
|
else
|
43
42
|
require config
|
44
43
|
app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
@@ -46,6 +45,11 @@ module Rack
|
|
46
45
|
return app, options
|
47
46
|
end
|
48
47
|
|
48
|
+
def self.new_from_string(builder_script, file="(rackup)")
|
49
|
+
eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
|
50
|
+
TOPLEVEL_BINDING, file, 0
|
51
|
+
end
|
52
|
+
|
49
53
|
def initialize(default_app = nil,&block)
|
50
54
|
@use, @map, @run = [], nil, default_app
|
51
55
|
instance_eval(&block) if block_given?
|
@@ -55,7 +59,7 @@ module Rack
|
|
55
59
|
self.new(default_app, &block).to_app
|
56
60
|
end
|
57
61
|
|
58
|
-
# Specifies
|
62
|
+
# Specifies middleware to use in a stack.
|
59
63
|
#
|
60
64
|
# class Middleware
|
61
65
|
# def initialize(app)
|
data/lib/rack/cascade.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Rack
|
2
|
-
# Rack::Cascade tries
|
3
|
-
# first response that is not 404 (or in a list of configurable
|
2
|
+
# Rack::Cascade tries a request on several apps, and returns the
|
3
|
+
# first response that is not 404 or 405 (or in a list of configurable
|
4
4
|
# status codes).
|
5
5
|
|
6
6
|
class Cascade
|
data/lib/rack/config.rb
CHANGED
data/lib/rack/deflater.rb
CHANGED
@@ -16,7 +16,8 @@ module Rack
|
|
16
16
|
# Skip compressing empty entity body responses and responses with
|
17
17
|
# no-transform set.
|
18
18
|
if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
|
19
|
-
headers['Cache-Control'].to_s =~ /\bno-transform\b/
|
19
|
+
headers['Cache-Control'].to_s =~ /\bno-transform\b/ ||
|
20
|
+
(headers['Content-Encoding'] && headers['Content-Encoding'] !~ /\bidentity\b/)
|
20
21
|
return [status, headers, body]
|
21
22
|
end
|
22
23
|
|
data/lib/rack/file.rb
CHANGED
@@ -21,16 +21,10 @@ module Rack
|
|
21
21
|
|
22
22
|
alias :to_path :path
|
23
23
|
|
24
|
-
def initialize(root, headers={})
|
24
|
+
def initialize(root, headers={}, default_mime = 'text/plain')
|
25
25
|
@root = root
|
26
|
-
|
27
|
-
|
28
|
-
warn \
|
29
|
-
"Rack::File headers parameter replaces cache_control after Rack 1.5."
|
30
|
-
@headers = { 'Cache-Control' => headers }
|
31
|
-
else
|
32
|
-
@headers = headers
|
33
|
-
end
|
26
|
+
@headers = headers
|
27
|
+
@default_mime = default_mime
|
34
28
|
end
|
35
29
|
|
36
30
|
def call(env)
|
@@ -44,17 +38,22 @@ module Rack
|
|
44
38
|
return fail(405, "Method Not Allowed")
|
45
39
|
end
|
46
40
|
|
47
|
-
|
48
|
-
parts =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
41
|
+
path_info = Utils.unescape(env["PATH_INFO"])
|
42
|
+
parts = path_info.split SEPS
|
43
|
+
|
44
|
+
parts.inject(0) do |depth, part|
|
45
|
+
case part
|
46
|
+
when '', '.'
|
47
|
+
depth
|
48
|
+
when '..'
|
49
|
+
return fail(404, "Not Found") if depth - 1 < 0
|
50
|
+
depth - 1
|
51
|
+
else
|
52
|
+
depth + 1
|
53
|
+
end
|
55
54
|
end
|
56
55
|
|
57
|
-
@path = F.join(@root, *
|
56
|
+
@path = F.join(@root, *parts)
|
58
57
|
|
59
58
|
available = begin
|
60
59
|
F.file?(@path) && F.readable?(@path)
|
@@ -65,24 +64,22 @@ module Rack
|
|
65
64
|
if available
|
66
65
|
serving(env)
|
67
66
|
else
|
68
|
-
fail(404, "File not found: #{
|
67
|
+
fail(404, "File not found: #{path_info}")
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
72
71
|
def serving(env)
|
73
72
|
last_modified = F.mtime(@path).httpdate
|
74
73
|
return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
"Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain')
|
80
|
-
},
|
81
|
-
env["REQUEST_METHOD"] == "HEAD" ? [] : self
|
82
|
-
]
|
74
|
+
|
75
|
+
headers = { "Last-Modified" => last_modified }
|
76
|
+
mime = Mime.mime_type(F.extname(@path), @default_mime)
|
77
|
+
headers["Content-Type"] = mime if mime
|
83
78
|
|
84
79
|
# Set custom headers
|
85
|
-
@headers.each { |field, content|
|
80
|
+
@headers.each { |field, content| headers[field] = content } if @headers
|
81
|
+
|
82
|
+
response = [ 200, headers, env["REQUEST_METHOD"] == "HEAD" ? [] : self ]
|
86
83
|
|
87
84
|
# NOTE:
|
88
85
|
# We check via File::size? whether this file provides size info
|
data/lib/rack/handler.rb
CHANGED
@@ -26,6 +26,23 @@ module Rack
|
|
26
26
|
raise load_error || name_error
|
27
27
|
end
|
28
28
|
|
29
|
+
# Select first available Rack handler given an `Array` of server names.
|
30
|
+
# Raises `LoadError` if no handler was found.
|
31
|
+
#
|
32
|
+
# > pick ['thin', 'webrick']
|
33
|
+
# => Rack::Handler::WEBrick
|
34
|
+
def self.pick(server_names)
|
35
|
+
server_names = Array(server_names)
|
36
|
+
server_names.each do |server_name|
|
37
|
+
begin
|
38
|
+
return get(server_name.to_s)
|
39
|
+
rescue LoadError, NameError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
raise LoadError, "Couldn't find handler for: #{server_names.join(', ')}."
|
44
|
+
end
|
45
|
+
|
29
46
|
def self.default(options = {})
|
30
47
|
# Guess.
|
31
48
|
if ENV.include?("PHP_FCGI_CHILDREN")
|
@@ -37,11 +54,7 @@ module Rack
|
|
37
54
|
elsif ENV.include?("REQUEST_METHOD")
|
38
55
|
Rack::Handler::CGI
|
39
56
|
else
|
40
|
-
|
41
|
-
Rack::Handler::Thin
|
42
|
-
rescue LoadError
|
43
|
-
Rack::Handler::WEBrick
|
44
|
-
end
|
57
|
+
pick ['thin', 'puma', 'webrick']
|
45
58
|
end
|
46
59
|
end
|
47
60
|
|
data/lib/rack/handler/mongrel.rb
CHANGED
data/lib/rack/handler/scgi.rb
CHANGED
@@ -29,7 +29,7 @@ module Rack
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def process_request(request, input_body, socket)
|
32
|
-
env =
|
32
|
+
env = Hash[request]
|
33
33
|
env.delete "HTTP_CONTENT_TYPE"
|
34
34
|
env.delete "HTTP_CONTENT_LENGTH"
|
35
35
|
env["REQUEST_PATH"], env["QUERY_STRING"] = env["REQUEST_URI"].split('?', 2)
|