mongrel2 0.24.0 → 0.25.0.pre.285
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|