mongrel2 0.24.0 → 0.25.0.pre.285
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/ChangeLog +53 -1
- data/History.rdoc +14 -0
- data/examples/Procfile +1 -1
- data/examples/async-upload.rb +4 -1
- data/examples/config.rb +4 -3
- data/examples/request-dumper.rb +1 -0
- data/examples/request-dumper.tmpl +6 -5
- data/examples/ws-echo.rb +3 -3
- data/lib/mongrel2.rb +2 -2
- data/lib/mongrel2/connection.rb +4 -2
- data/lib/mongrel2/constants.rb +7 -0
- data/lib/mongrel2/httprequest.rb +0 -42
- data/lib/mongrel2/httpresponse.rb +20 -22
- data/lib/mongrel2/request.rb +97 -3
- data/lib/mongrel2/response.rb +34 -6
- data/lib/mongrel2/testing.rb +2 -4
- data/lib/mongrel2/websocket.rb +104 -45
- data/spec/mongrel2/httprequest_spec.rb +0 -40
- data/spec/mongrel2/httpresponse_spec.rb +6 -12
- data/spec/mongrel2/request_spec.rb +112 -3
- data/spec/mongrel2/response_spec.rb +22 -7
- data/spec/mongrel2/websocket_spec.rb +32 -13
- metadata +2 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/ChangeLog
CHANGED
@@ -1,9 +1,61 @@
|
|
1
|
+
2012-06-20 Michael Granger <ged@FaerieMUD.org>
|
2
|
+
|
3
|
+
* examples/async-upload.rb, examples/config.rb,
|
4
|
+
lib/mongrel2/httprequest.rb, lib/mongrel2/request.rb,
|
5
|
+
lib/mongrel2/testing.rb, spec/mongrel2/httprequest_spec.rb,
|
6
|
+
spec/mongrel2/request_spec.rb:
|
7
|
+
Hook up the async uploaded entity body to the request
|
8
|
+
[349c0049a4a1] [tip]
|
9
|
+
|
10
|
+
2012-06-19 Michael Granger <ged@FaerieMUD.org>
|
11
|
+
|
12
|
+
* examples/Procfile, examples/async-upload.rb, examples/config.rb,
|
13
|
+
examples/ws-echo.rb, lib/mongrel2/websocket.rb,
|
14
|
+
spec/mongrel2/websocket_spec.rb:
|
15
|
+
Fixes for the websocket frame class for the stream API, fixed some
|
16
|
+
examples.
|
17
|
+
[4202d9942c16]
|
18
|
+
|
19
|
+
* lib/mongrel2/connection.rb, lib/mongrel2/httpresponse.rb,
|
20
|
+
lib/mongrel2/request.rb, lib/mongrel2/response.rb,
|
21
|
+
lib/mongrel2/websocket.rb, spec/mongrel2/httpresponse_spec.rb,
|
22
|
+
spec/mongrel2/response_spec.rb, spec/mongrel2/websocket_spec.rb:
|
23
|
+
Convert to an IO-based request/response body
|
24
|
+
[96edda5cdb69]
|
25
|
+
|
26
|
+
2012-06-08 Mahlon E. Smith <mahlon@martini.nu>
|
27
|
+
|
28
|
+
* lib/mongrel2/constants.rb:
|
29
|
+
Add a few newer-rfc HTTP error codes.
|
30
|
+
[8e125eaf25ce]
|
31
|
+
|
32
|
+
2012-05-31 Michael Granger <ged@FaerieMUD.org>
|
33
|
+
|
34
|
+
* .hgtags:
|
35
|
+
Added tag v0.24.0 for changeset d2b1df5fc74d
|
36
|
+
[dbe3504c63ad]
|
37
|
+
|
38
|
+
* .hgsigs:
|
39
|
+
Added signature for changeset 3ed1175a2f9e
|
40
|
+
[d2b1df5fc74d] [v0.24.0]
|
41
|
+
|
42
|
+
* History.rdoc, lib/mongrel2.rb:
|
43
|
+
Bumping minor version, updating history.
|
44
|
+
[3ed1175a2f9e]
|
45
|
+
|
46
|
+
2012-05-29 Mahlon E. Smith <mahlon@martini.nu>
|
47
|
+
|
48
|
+
* lib/mongrel2/table.rb:
|
49
|
+
Take immediate objects into account when dup/cloning a
|
50
|
+
Mongrel2::Table.
|
51
|
+
[f10cba1487ea]
|
52
|
+
|
1
53
|
2012-05-20 Michael Granger <ged@FaerieMUD.org>
|
2
54
|
|
3
55
|
* .rvm.gems:
|
4
56
|
Comment out amalgalite rvmrc gem until
|
5
57
|
https://github.com/copiousfreetime/amalgalite/pull/22 is fixed
|
6
|
-
[b872e092ed92]
|
58
|
+
[b872e092ed92]
|
7
59
|
|
8
60
|
2012-05-21 Michael Granger <ged@FaerieMUD.org>
|
9
61
|
|
data/History.rdoc
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
== v0.25.0 [2012-06-20] Michael Granger <ged@FaerieMUD.org>
|
2
|
+
|
3
|
+
NOTE: This revision contains non-backward-compatible changes to
|
4
|
+
Mongrel2::Request, Mongrel2::Response, and all subclasses.
|
5
|
+
|
6
|
+
- Convert request and response entity bodies to IOish objects instead of
|
7
|
+
Strings.
|
8
|
+
- Finished implementation of Mongrel2 async upload API -- async-uploaded
|
9
|
+
entity bodies now become File entity bodies of the
|
10
|
+
"X-Mongrel2-Upload-Done" request.
|
11
|
+
- Add a few newer-rfc HTTP error codes.
|
12
|
+
- Add support for Content-type charsets.
|
13
|
+
|
14
|
+
|
1
15
|
== v0.24.0 [2012-05-31] Michael Granger <ged@FaerieMUD.org>
|
2
16
|
|
3
17
|
- Fix a bug when duping a Mongrel2::Table with immediate objects as values.
|
data/examples/Procfile
CHANGED
data/examples/async-upload.rb
CHANGED
@@ -8,6 +8,9 @@ require 'mongrel2/handler'
|
|
8
8
|
# A example of how to allow Mongrel2's async uploads.
|
9
9
|
class AsyncUploadHandler < Mongrel2::Handler
|
10
10
|
|
11
|
+
# App ID
|
12
|
+
ID = 'async-upload'
|
13
|
+
|
11
14
|
### Load up the ERB template from the DATA section on instantiation.
|
12
15
|
def initialize( * )
|
13
16
|
super
|
@@ -35,7 +38,7 @@ class AsyncUploadHandler < Mongrel2::Handler
|
|
35
38
|
[ request.uploaded_file, request.content_length, request.content_type ]
|
36
39
|
|
37
40
|
response = request.response
|
38
|
-
response.puts "Upload complete: %
|
41
|
+
response.puts "Upload complete: %p" % [ request.uploaded_file ]
|
39
42
|
response.content_type = 'text/plain'
|
40
43
|
|
41
44
|
return response
|
data/examples/config.rb
CHANGED
@@ -45,9 +45,10 @@ server 'examples' do
|
|
45
45
|
|
46
46
|
end
|
47
47
|
|
48
|
-
setting
|
49
|
-
setting
|
50
|
-
setting
|
48
|
+
setting 'zeromq.threads', 1
|
49
|
+
setting 'limits.content_length', 4096
|
50
|
+
setting 'control_port', 'ipc://var/run/control'
|
51
|
+
setting 'upload.temp_store', upload_dir + 'mongrel2.upload.XXXXXX'
|
51
52
|
|
52
53
|
mkdir_p 'var/run'
|
53
54
|
mkdir_p 'logs'
|
data/examples/request-dumper.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
</header>
|
21
21
|
|
22
22
|
<section id="dump">
|
23
|
-
|
23
|
+
|
24
24
|
<table>
|
25
25
|
<tr>
|
26
26
|
<th>Sender ID</th>
|
@@ -35,7 +35,7 @@
|
|
35
35
|
<td><?attr safelevel ?></td>
|
36
36
|
</tr>
|
37
37
|
</table>
|
38
|
-
|
38
|
+
|
39
39
|
<section id="headers">
|
40
40
|
<header>
|
41
41
|
<h1>Headers</h1>
|
@@ -49,13 +49,14 @@
|
|
49
49
|
<?end for ?>
|
50
50
|
</table>
|
51
51
|
</section>
|
52
|
-
|
52
|
+
|
53
53
|
<section id="body">
|
54
54
|
<header>
|
55
55
|
<h1>Body</h1>
|
56
56
|
</header>
|
57
57
|
|
58
|
-
<p><code><?escape request.body.
|
58
|
+
<p><code><?escape request.body.inspect ?></code>
|
59
|
+
(<?call "%0.2fKb" % request.body.size ?>, <?call request.body.external_encoding.name ?>)</p>
|
59
60
|
</section>
|
60
61
|
|
61
62
|
<section id="inspect">
|
@@ -66,7 +67,7 @@
|
|
66
67
|
</pre>
|
67
68
|
</header>
|
68
69
|
</section>
|
69
|
-
|
70
|
+
|
70
71
|
</section>
|
71
72
|
|
72
73
|
<footer>
|
data/examples/ws-echo.rb
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
require 'loggability'
|
5
5
|
require 'pathname'
|
6
6
|
require 'mongrel2/config'
|
7
|
-
require 'mongrel2/logging'
|
8
7
|
require 'mongrel2/handler'
|
9
8
|
|
10
9
|
|
@@ -99,8 +98,9 @@ class WebSocketEchoServer < Mongrel2::Handler
|
|
99
98
|
frame.opcode.to_s.upcase,
|
100
99
|
frame.fin? ? '' : '(cont)',
|
101
100
|
frame.headers.x_forwarded_for,
|
102
|
-
frame.payload
|
101
|
+
frame.payload.read( 20 ),
|
103
102
|
]
|
103
|
+
frame.payload.rewind
|
104
104
|
|
105
105
|
# If a client sends an invalid frame, close their connection, but politely.
|
106
106
|
if !frame.valid?
|
@@ -130,7 +130,7 @@ class WebSocketEchoServer < Mongrel2::Handler
|
|
130
130
|
# Make the response frame
|
131
131
|
response = frame.response
|
132
132
|
response.fin = frame.fin?
|
133
|
-
|
133
|
+
IO.copy_stream( frame.payload, response.payload )
|
134
134
|
|
135
135
|
return response
|
136
136
|
end
|
data/lib/mongrel2.rb
CHANGED
@@ -20,10 +20,10 @@ module Mongrel2
|
|
20
20
|
abort "\n\n>>> Mongrel2 requires Ruby 1.9.2 or later. <<<\n\n" if RUBY_VERSION < '1.9.2'
|
21
21
|
|
22
22
|
# Library version constant
|
23
|
-
VERSION = '0.
|
23
|
+
VERSION = '0.25.0'
|
24
24
|
|
25
25
|
# Version-control revision constant
|
26
|
-
REVISION = %q$Revision:
|
26
|
+
REVISION = %q$Revision: 928743f397cc $
|
27
27
|
|
28
28
|
|
29
29
|
require 'mongrel2/constants'
|
data/lib/mongrel2/connection.rb
CHANGED
@@ -105,7 +105,7 @@ class Mongrel2::Connection
|
|
105
105
|
|
106
106
|
self.log.debug "Fetching next request (PULL)"
|
107
107
|
data = self.request_sock.recv
|
108
|
-
self.log.debug " got request data: %p" % [ data ]
|
108
|
+
self.log.debug " got %s request data: %p" % [ data.encoding.name, data ]
|
109
109
|
return data
|
110
110
|
end
|
111
111
|
|
@@ -131,7 +131,9 @@ class Mongrel2::Connection
|
|
131
131
|
|
132
132
|
### Write the specified +response+ (Mongrel::Response object) to the requester.
|
133
133
|
def reply( response )
|
134
|
-
|
134
|
+
response.each_chunk do |data|
|
135
|
+
self.send( response.sender_id, response.conn_id, data )
|
136
|
+
end
|
135
137
|
end
|
136
138
|
|
137
139
|
|
data/lib/mongrel2/constants.rb
CHANGED
@@ -65,6 +65,10 @@ module Mongrel2::Constants
|
|
65
65
|
UNPROCESSABLE_ENTITY = 422
|
66
66
|
LOCKED = 423
|
67
67
|
FAILED_DEPENDENCY = 424
|
68
|
+
UPGRADE_REQUIRED = 426
|
69
|
+
RECONDITION_REQUIRED = 428
|
70
|
+
TOO_MANY_REQUESTS = 429
|
71
|
+
REQUEST_HEADERS_TOO_LARGE = 431
|
68
72
|
|
69
73
|
SERVER_ERROR = 500
|
70
74
|
NOT_IMPLEMENTED = 501
|
@@ -140,6 +144,9 @@ module Mongrel2::Constants
|
|
140
144
|
424 => "Failed Dependency",
|
141
145
|
425 => "No code",
|
142
146
|
426 => "Upgrade Required",
|
147
|
+
428 => "Precondition Required",
|
148
|
+
429 => "Too Many Requests",
|
149
|
+
431 => "Request Headers too Large",
|
143
150
|
500 => "Internal Server Error",
|
144
151
|
501 => "Method Not Implemented",
|
145
152
|
502 => "Bad Gateway",
|
data/lib/mongrel2/httprequest.rb
CHANGED
@@ -100,48 +100,6 @@ class Mongrel2::HTTPRequest < Mongrel2::Request
|
|
100
100
|
end
|
101
101
|
|
102
102
|
|
103
|
-
#
|
104
|
-
# :section: Async Upload Support
|
105
|
-
# See http://mongrel2.org/static/book-finalch6.html#x8-810005.5 for details.
|
106
|
-
#
|
107
|
-
|
108
|
-
### The Pathname, relative to Mongrel2's chroot path, of the uploaded entity body.
|
109
|
-
def uploaded_file
|
110
|
-
raise Mongrel2::UploadError, "invalid upload: upload headers don't match" unless
|
111
|
-
self.upload_headers_match?
|
112
|
-
return Pathname( self.headers.x_mongrel2_upload_done )
|
113
|
-
end
|
114
|
-
|
115
|
-
|
116
|
-
### Returns +true+ if this request is an 'asynchronous upload started' notification.
|
117
|
-
def upload_started?
|
118
|
-
return self.headers.member?( :x_mongrel2_upload_start ) &&
|
119
|
-
!self.headers.member?( :x_mongrel2_upload_done )
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
### Returns +true+ if this request is an 'asynchronous upload done' notification.
|
124
|
-
def upload_done?
|
125
|
-
return self.headers.member?( :x_mongrel2_upload_start ) &&
|
126
|
-
self.headers.member?( :x_mongrel2_upload_done )
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
### Returns +true+ if this request is an 'asynchronous upload done' notification
|
131
|
-
### and the two headers match (trivial guard against forgery)
|
132
|
-
def upload_headers_match?
|
133
|
-
return self.upload_done? &&
|
134
|
-
self.headers.x_mongrel2_upload_start == self.headers.x_mongrel2_upload_done
|
135
|
-
end
|
136
|
-
|
137
|
-
|
138
|
-
### Returns true if this request is an asynchronous upload, and the filename of the
|
139
|
-
### finished request matches the one from the starting notification.
|
140
|
-
def valid_upload?
|
141
|
-
return self.upload_done? && self.upload_headers_match?
|
142
|
-
end
|
143
|
-
|
144
|
-
|
145
103
|
#########
|
146
104
|
protected
|
147
105
|
#########
|
@@ -37,7 +37,7 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
37
37
|
|
38
38
|
@headers = Mongrel2::Table.new
|
39
39
|
@status = nil
|
40
|
-
self.
|
40
|
+
self.set_defaults
|
41
41
|
|
42
42
|
@headers.merge!( headers )
|
43
43
|
end
|
@@ -55,12 +55,18 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
55
55
|
attr_accessor :status
|
56
56
|
|
57
57
|
|
58
|
+
### Set up response default headers, etc.
|
59
|
+
def set_defaults
|
60
|
+
@headers[:server] = Mongrel2.version_string( true )
|
61
|
+
end
|
62
|
+
|
63
|
+
|
58
64
|
### Stringify the response
|
59
65
|
def to_s
|
60
66
|
return [
|
61
67
|
self.status_line,
|
62
68
|
self.header_data,
|
63
|
-
self.bodiless? ? '' :
|
69
|
+
self.bodiless? ? '' : super
|
64
70
|
].join( "\r\n" )
|
65
71
|
end
|
66
72
|
|
@@ -69,8 +75,8 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
69
75
|
def status_line
|
70
76
|
self.log.debug "Building status line for status: %p" % [ self.status ]
|
71
77
|
|
72
|
-
st = self.status ||
|
73
|
-
|
78
|
+
st = self.status || (self.body.size.zero? ? HTTP::NO_CONTENT : HTTP::OK)
|
79
|
+
|
74
80
|
return STATUS_LINE_FORMAT % [ st, HTTP::STATUS_NAME[st] ]
|
75
81
|
end
|
76
82
|
|
@@ -141,9 +147,10 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
141
147
|
### Clear any existing headers and body and restore them to their defaults
|
142
148
|
def reset
|
143
149
|
@headers.clear
|
144
|
-
@
|
150
|
+
@body.truncate( 0 )
|
145
151
|
@status = nil
|
146
|
-
|
152
|
+
|
153
|
+
self.set_defaults
|
147
154
|
|
148
155
|
return true
|
149
156
|
end
|
@@ -174,25 +181,15 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
174
181
|
end
|
175
182
|
|
176
183
|
|
177
|
-
### Get the length of the body
|
178
|
-
###
|
179
|
-
### possible, an exception is raised.
|
184
|
+
### Get the length of the body IO. If the IO's offset is somewhere other than
|
185
|
+
### the beginning or end, the size of the remainder is used.
|
180
186
|
def get_content_length
|
181
187
|
if self.bodiless?
|
182
188
|
return 0
|
183
|
-
elsif self.body.
|
184
|
-
return self.body.
|
185
|
-
elsif self.body.respond_to?( :seek ) && self.body.respond_to?( :tell )
|
186
|
-
starting_pos = self.body.tell
|
187
|
-
self.body.seek( 0, IO::SEEK_END )
|
188
|
-
length = self.body.tell - starting_pos
|
189
|
-
self.body.seek( starting_pos, IO::SEEK_SET )
|
190
|
-
|
191
|
-
return length
|
189
|
+
elsif self.body.pos.nonzero? && !self.body.eof?
|
190
|
+
return self.body.size - self.body.pos
|
192
191
|
else
|
193
|
-
|
194
|
-
"No way to calculate the content length of the response (a %s)." %
|
195
|
-
[ self.body.class.name ]
|
192
|
+
return self.body.size
|
196
193
|
end
|
197
194
|
end
|
198
195
|
|
@@ -219,10 +216,11 @@ class Mongrel2::HTTPResponse < Mongrel2::Response
|
|
219
216
|
|
220
217
|
### Return the details to include in the contents of the #inspected object.
|
221
218
|
def inspect_details
|
222
|
-
return %Q{%s -- %d headers, %0.2fK body} % [
|
219
|
+
return %Q{%s -- %d headers, %0.2fK body (%p)} % [
|
223
220
|
self.status_line,
|
224
221
|
self.headers.length,
|
225
222
|
(self.get_content_length / 1024.0),
|
223
|
+
self.body,
|
226
224
|
]
|
227
225
|
end
|
228
226
|
|
data/lib/mongrel2/request.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
|
+
require 'stringio'
|
3
4
|
require 'tnetstring'
|
4
5
|
require 'yajl'
|
5
6
|
require 'loggability'
|
@@ -110,13 +111,14 @@ class Mongrel2::Request
|
|
110
111
|
### and +body+. The optional +nil+ is for the raw request content, which can be useful
|
111
112
|
### later for debugging.
|
112
113
|
def initialize( sender_id, conn_id, path, headers, body='', raw=nil )
|
114
|
+
|
113
115
|
@sender_id = sender_id
|
114
116
|
@conn_id = Integer( conn_id )
|
115
117
|
@path = path
|
116
118
|
@headers = Mongrel2::Table.new( headers )
|
117
|
-
@body = body
|
118
119
|
@raw = raw
|
119
120
|
|
121
|
+
@body = self.make_entity_body( body )
|
120
122
|
@response = nil
|
121
123
|
end
|
122
124
|
|
@@ -131,7 +133,7 @@ class Mongrel2::Request
|
|
131
133
|
# The listener ID on the server
|
132
134
|
attr_reader :conn_id
|
133
135
|
|
134
|
-
# The path component of the requested URL in HTTP, or the equivalent
|
136
|
+
# The path component of the requested URL in HTTP, or the equivalent
|
135
137
|
# for other request types
|
136
138
|
attr_reader :path
|
137
139
|
|
@@ -139,7 +141,7 @@ class Mongrel2::Request
|
|
139
141
|
attr_reader :headers
|
140
142
|
alias_method :header, :headers
|
141
143
|
|
142
|
-
# The request body data, if there is any, as
|
144
|
+
# The request body data, if there is any, as an IO object
|
143
145
|
attr_reader :body
|
144
146
|
|
145
147
|
# The raw request content, if the request was parsed from mongrel2
|
@@ -161,6 +163,69 @@ class Mongrel2::Request
|
|
161
163
|
end
|
162
164
|
|
163
165
|
|
166
|
+
#
|
167
|
+
# :section: Async Upload Support
|
168
|
+
# See http://mongrel2.org/static/book-finalch6.html#x8-810005.5 for details.
|
169
|
+
#
|
170
|
+
|
171
|
+
### The Pathname, relative to Mongrel2's chroot path, of the uploaded entity body.
|
172
|
+
def uploaded_file
|
173
|
+
raise Mongrel2::UploadError, "invalid upload: upload headers don't match" unless
|
174
|
+
self.upload_headers_match?
|
175
|
+
|
176
|
+
server = Mongrel2::Config::Server.by_uuid( self.sender_id ).first or
|
177
|
+
raise Mongrel2::UploadError, "couldn't find the server %p in the config DB" %
|
178
|
+
[ self.sender_id ]
|
179
|
+
|
180
|
+
relpath = Pathname( self.headers.x_mongrel2_upload_done )
|
181
|
+
chrooted = Pathname( server.chroot ) + relpath
|
182
|
+
|
183
|
+
if chrooted.exist?
|
184
|
+
return chrooted
|
185
|
+
elsif relpath.exist?
|
186
|
+
return relpath
|
187
|
+
else
|
188
|
+
self.log.error "uploaded body %s not found: tried relative to cwd and server chroot (%s)" %
|
189
|
+
[ relpath, server.chroot ]
|
190
|
+
raise Mongrel2::UploadError,
|
191
|
+
"couldn't find the path to uploaded body."
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
### Returns +true+ if this request is an 'asynchronous upload started' notification.
|
197
|
+
def upload_started?
|
198
|
+
return self.headers.member?( :x_mongrel2_upload_start ) &&
|
199
|
+
!self.headers.member?( :x_mongrel2_upload_done )
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
### Returns +true+ if this request is an 'asynchronous upload done' notification.
|
204
|
+
def upload_done?
|
205
|
+
return self.headers.member?( :x_mongrel2_upload_start ) &&
|
206
|
+
self.headers.member?( :x_mongrel2_upload_done )
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
### Returns +true+ if this request is an 'asynchronous upload done' notification
|
211
|
+
### and the two headers match (trivial guard against forgery)
|
212
|
+
def upload_headers_match?
|
213
|
+
return self.upload_done? &&
|
214
|
+
self.headers.x_mongrel2_upload_start == self.headers.x_mongrel2_upload_done
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
### Returns true if this request is an asynchronous upload, and the filename of the
|
219
|
+
### finished request matches the one from the starting notification.
|
220
|
+
def valid_upload?
|
221
|
+
return self.upload_done? && self.upload_headers_match?
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
#
|
226
|
+
# :section: Introspection Methods
|
227
|
+
#
|
228
|
+
|
164
229
|
### Returns a string containing a human-readable representation of the Request,
|
165
230
|
### suitable for debugging.
|
166
231
|
def inspect
|
@@ -178,6 +243,35 @@ class Mongrel2::Request
|
|
178
243
|
protected
|
179
244
|
#########
|
180
245
|
|
246
|
+
### Convert the entity +body+ into an IOish object, wrapping it in a StringIO if
|
247
|
+
### it doesn't already respond to :read, :pos, and :seek. If the request has
|
248
|
+
### valid 'X-Mongrel2-Upload-*' headers (the async upload API), a File object
|
249
|
+
### opened to the spool file will be returned instead.
|
250
|
+
def make_entity_body( body )
|
251
|
+
# :TODO: Handle Content-Encoding, too.
|
252
|
+
|
253
|
+
enc = self.headers.content_type[ /\bcharset=(\S+)/, 1 ] if self.headers.content_type
|
254
|
+
|
255
|
+
if self.valid_upload?
|
256
|
+
enc ||= Encoding::ASCII_8BIT
|
257
|
+
spoolfile = self.uploaded_file
|
258
|
+
self.log.info "Using async %s spool file %s as request entity body." % [ enc, spoolfile ]
|
259
|
+
return spoolfile.open( 'r', encoding: enc )
|
260
|
+
|
261
|
+
elsif !( body.respond_to?(:read) && body.respond_to?(:pos) && body.respond_to?(:seek) )
|
262
|
+
self.log.info "Wrapping non-IO (%p) body in a StringIO" % [ body.class ]
|
263
|
+
|
264
|
+
# Get the object as a String, set the encoding
|
265
|
+
str = body.to_s
|
266
|
+
str.force_encoding( enc ) if enc && str.encoding == Encoding::ASCII_8BIT
|
267
|
+
|
268
|
+
return StringIO.new( str, 'r+' )
|
269
|
+
else
|
270
|
+
return body
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
|
181
275
|
### Return the details to include in the contents of the #inspected object. This
|
182
276
|
### method allows other request types to provide their own details while keeping
|
183
277
|
### the form somewhat consistent.
|