mongrel 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +10 -2
- data/Rakefile +1 -1
- data/doc/rdoc/classes/Mongrel.html +11 -1
- data/doc/rdoc/classes/Mongrel/Const.html +342 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.html +201 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000008.html +20 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000009.html +31 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000010.html +22 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000011.html +39 -0
- data/doc/rdoc/classes/Mongrel/Error404Handler.html +10 -10
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000023.html → M000028.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000024.html → M000029.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +28 -10
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000013.html → M000017.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/M000018.html +21 -0
- data/doc/rdoc/classes/Mongrel/HttpHandler.html +5 -18
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000019.html → M000023.html} +3 -3
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +8 -8
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000030.html +31 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +89 -15
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000020.html → M000024.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000021.html → M000025.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000026.html +19 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/{M000022.html → M000027.html} +11 -11
- data/doc/rdoc/classes/Mongrel/HttpServer.html +32 -76
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html +18 -5
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000013.html +64 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000010.html → M000014.html} +9 -8
- data/doc/rdoc/classes/Mongrel/HttpServer.src/{M000011.html → M000015.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000016.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +25 -23
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000015.html → M000019.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000016.html → M000020.html} +3 -2
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000017.html → M000021.html} +0 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/{M000018.html → M000022.html} +1 -1
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/README.html +14 -2
- data/doc/rdoc/files/ext/http11/http11_c.html +1 -1
- data/doc/rdoc/files/lib/mongrel_rb.html +1 -1
- data/doc/rdoc/fr_class_index.html +2 -0
- data/doc/rdoc/fr_method_index.html +23 -18
- data/examples/simpletest.rb +2 -1
- data/ext/http11/http11.c +10 -9
- data/ext/http11/http11_parser.c +10 -10
- data/ext/http11/http11_parser.h +5 -1
- data/lib/#mongrel.rb# +493 -0
- data/lib/mongrel.rb +242 -48
- metadata +28 -19
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/M000014.html +0 -21
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/M000025.html +0 -30
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000008.html +0 -26
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html +0 -58
data/lib/mongrel.rb
CHANGED
@@ -8,6 +8,9 @@ require 'stringio'
|
|
8
8
|
# functionality to service web application requests fast as possible.
|
9
9
|
module Mongrel
|
10
10
|
|
11
|
+
# Every standard HTTP code mapped to the appropriate message. These are
|
12
|
+
# used so frequently that they are placed directly in Mongrel for easy
|
13
|
+
# access rather than Mongrel::Const.
|
11
14
|
HTTP_STATUS_CODES = {
|
12
15
|
100 => 'Continue',
|
13
16
|
101 => 'Switching Protocols',
|
@@ -48,19 +51,89 @@ module Mongrel
|
|
48
51
|
505 => 'HTTP Version not supported'
|
49
52
|
}
|
50
53
|
|
54
|
+
# Frequently used constants when constructing requests or responses. Many times
|
55
|
+
# the constant just refers to a string with the same contents. Using these constants
|
56
|
+
# gave about a 3% to 10% performance improvement over using the strings directly.
|
57
|
+
# Symbols did not really improve things much compared to constants.
|
58
|
+
#
|
59
|
+
# While Mongrel does try to emulate the CGI/1.2 protocol, it does not use the REMOTE_IDENT,
|
60
|
+
# REMOTE_USER, or REMOTE_HOST parameters since those are either a security problem or
|
61
|
+
# too taxing on performance.
|
62
|
+
module Const
|
63
|
+
# This is the part of the path after the SCRIPT_NAME. URIClassifier will determine this.
|
64
|
+
PATH_INFO="PATH_INFO"
|
65
|
+
# This is the intial part that your handler is identified as by URIClassifier.
|
66
|
+
SCRIPT_NAME="SCRIPT_NAME"
|
67
|
+
# The original URI requested by the client. Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
|
68
|
+
REQUEST_URI='REQUEST_URI'
|
69
|
+
|
70
|
+
# Content length (also available as HTTP_CONTENT_LENGTH).
|
71
|
+
CONTENT_LENGTH='CONTENT_LENGTH'
|
72
|
+
|
73
|
+
# Content length (also available as CONTENT_LENGTH).
|
74
|
+
HTTP_CONTENT_LENGTH='HTTP_CONTENT_LENGTH'
|
75
|
+
|
76
|
+
# Content type (also available as HTTP_CONTENT_TYPE).
|
77
|
+
CONTENT_TYPE='CONTENT_TYPE'
|
78
|
+
|
79
|
+
# Content type (also available as CONTENT_TYPE).
|
80
|
+
HTTP_CONTENT_TYPE='HTTP_CONTENT_TYPE'
|
81
|
+
|
82
|
+
# Gateway interface key in the HttpRequest parameters.
|
83
|
+
GATEWAY_INTERFACE='GATEWAY_INTERFACE'
|
84
|
+
# We claim to support CGI/1.2.
|
85
|
+
GATEWAY_INTERFACE_VALUE='CGI/1.2'
|
86
|
+
|
87
|
+
# Hosts remote IP address. Mongrel does not do DNS resolves since that slows
|
88
|
+
# processing down considerably.
|
89
|
+
REMOTE_ADDR='REMOTE_ADDR'
|
90
|
+
|
91
|
+
# This is not given since Mongrel does not do DNS resolves. It is only here for
|
92
|
+
# completeness for the CGI standard.
|
93
|
+
REMOTE_HOST='REMOTE_HOST'
|
94
|
+
|
95
|
+
# The name/host of our server as given by the HttpServer.new(host,port) call.
|
96
|
+
SERVER_NAME='SERVER_NAME'
|
97
|
+
|
98
|
+
# The port of our server as given by the HttpServer.new(host,port) call.
|
99
|
+
SERVER_PORT='SERVER_PORT'
|
100
|
+
|
101
|
+
# Official server protocol key in the HttpRequest parameters.
|
102
|
+
SERVER_PROTOCOL='SERVER_PROTOCOL'
|
103
|
+
# Mongrel claims to support HTTP/1.1.
|
104
|
+
SERVER_PROTOCOL_VALUE='HTTP/1.1'
|
105
|
+
|
106
|
+
# The actual server software being used (it's Mongrel man).
|
107
|
+
SERVER_SOFTWARE='SERVER_SOFTWARE'
|
108
|
+
|
109
|
+
# Current Mongrel version (used for SERVER_SOFTWARE and other response headers).
|
110
|
+
MONGREL_VERSION='Mongrel 0.2.2'
|
111
|
+
|
112
|
+
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
113
|
+
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND"
|
114
|
+
|
115
|
+
# A common header for indicating the server is too busy. Not used yet.
|
116
|
+
ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
|
117
|
+
|
118
|
+
# The basic max request size we'll try to read.
|
119
|
+
CHUNK_SIZE=(16 * 1024)
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
|
51
124
|
# When a handler is found for a registered URI then this class is constructed
|
52
125
|
# and passed to your HttpHandler::process method. You should assume that
|
53
126
|
# *one* handler processes all requests. Included in the HttpReqeust is a
|
54
127
|
# HttpRequest.params Hash that matches common CGI params, and a HttpRequest.body
|
55
128
|
# which is a string containing the request body (raw for now).
|
56
129
|
#
|
57
|
-
# Mongrel really only
|
130
|
+
# Mongrel really only supports small-ish request bodies right now since really
|
58
131
|
# huge ones have to be completely read off the wire and put into a string.
|
59
132
|
# Later there will be several options for efficiently handling large file
|
60
133
|
# uploads.
|
61
134
|
class HttpRequest
|
62
135
|
attr_reader :body, :params
|
63
|
-
|
136
|
+
|
64
137
|
# You don't really call this. It's made for you.
|
65
138
|
# Main thing it does is hook up the params, and store any remaining
|
66
139
|
# body data into the HttpRequest.body attribute.
|
@@ -68,13 +141,14 @@ module Mongrel
|
|
68
141
|
@body = initial_body || ""
|
69
142
|
@params = params
|
70
143
|
@socket = socket
|
71
|
-
|
144
|
+
|
72
145
|
# fix up the CGI requirements
|
73
|
-
params[
|
146
|
+
params[Const::CONTENT_LENGTH] = params[Const::HTTP_CONTENT_LENGTH] || 0
|
147
|
+
params[Const::CONTENT_TYPE] ||= params[Const::HTTP_CONTENT_TYPE]
|
74
148
|
|
75
149
|
# now, if the initial_body isn't long enough for the content length we have to fill it
|
76
150
|
# TODO: adapt for big ass stuff by writing to a temp file
|
77
|
-
clen = params[
|
151
|
+
clen = params[Const::HTTP_CONTENT_LENGTH].to_i
|
78
152
|
if @body.length < clen
|
79
153
|
@body << @socket.read(clen - @body.length)
|
80
154
|
end
|
@@ -82,6 +156,13 @@ module Mongrel
|
|
82
156
|
end
|
83
157
|
|
84
158
|
|
159
|
+
# This class implements a simple way of constructing the HTTP headers dynamically
|
160
|
+
# via a Hash syntax. Think of it as a write-only Hash. Refer to HttpResponse for
|
161
|
+
# information on how this is used.
|
162
|
+
#
|
163
|
+
# One consequence of this write-only nature is that you can write multiple headers
|
164
|
+
# by just doing them twice (which is sometimes needed in HTTP), but that the normal
|
165
|
+
# semantics for Hash (where doing an insert replaces) is not there.
|
85
166
|
class HeaderOut
|
86
167
|
attr_reader :out
|
87
168
|
|
@@ -89,6 +170,7 @@ module Mongrel
|
|
89
170
|
@out = out
|
90
171
|
end
|
91
172
|
|
173
|
+
# Simply writes "#{key}: #{value}" to an output buffer.
|
92
174
|
def[]=(key,value)
|
93
175
|
@out.write(key)
|
94
176
|
@out.write(": ")
|
@@ -97,7 +179,35 @@ module Mongrel
|
|
97
179
|
end
|
98
180
|
end
|
99
181
|
|
100
|
-
|
182
|
+
# Writes and controls your response to the client using the HTTP/1.1 specification.
|
183
|
+
# You use it by simply doing:
|
184
|
+
#
|
185
|
+
# response.start(200) do |head,out|
|
186
|
+
# head['Content-Type'] = 'text/plain'
|
187
|
+
# out.write("hello\n")
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# The parameter to start is the response code--which Mongrel will translate for you
|
191
|
+
# based on HTTP_STATUS_CODES. The head parameter is how you write custom headers.
|
192
|
+
# The out parameter is where you write your body. The default status code for
|
193
|
+
# HttpResponse.start is 200 so the above example is redundant.
|
194
|
+
#
|
195
|
+
# As you can see, it's just like using a Hash and as you do this it writes the proper
|
196
|
+
# header to the output on the fly. You can even intermix specifying headers and
|
197
|
+
# writing content. The HttpResponse class with write the things in the proper order
|
198
|
+
# once the HttpResponse.block is ended.
|
199
|
+
#
|
200
|
+
# You may also work the HttpResponse object directly using the various attributes available
|
201
|
+
# for the raw socket, body, header, and status codes. If you do this you're on your own.
|
202
|
+
# A design decision was made to force the client to not pipeline requests. HTTP/1.1
|
203
|
+
# pipelining really kills the performance due to how it has to be handled and how
|
204
|
+
# unclear the standard is. To fix this the HttpResponse gives a "Connection: close"
|
205
|
+
# header which forces the client to close right away. The bonus for this is that it
|
206
|
+
# gives a pretty nice speed boost to most clients since they can close their connection
|
207
|
+
# immediately.
|
208
|
+
#
|
209
|
+
# One additional caveat is that you don't have to specify the Content-length header
|
210
|
+
# as the HttpResponse will write this for you based on the out length.
|
101
211
|
class HttpResponse
|
102
212
|
attr_reader :socket
|
103
213
|
attr_reader :body
|
@@ -112,12 +222,25 @@ module Mongrel
|
|
112
222
|
@header = HeaderOut.new(StringIO.new)
|
113
223
|
end
|
114
224
|
|
225
|
+
# Receives a block passing it the header and body for you to work with.
|
226
|
+
# When the block is finished it writes everything you've done to
|
227
|
+
# the socket in the proper order. This lets you intermix header and
|
228
|
+
# body content as needed.
|
115
229
|
def start(status=200)
|
116
230
|
@status = status
|
117
231
|
yield @header, @body
|
118
232
|
finished
|
119
233
|
end
|
120
|
-
|
234
|
+
|
235
|
+
# Primarily used in exception handling to reset the response output in order to write
|
236
|
+
# an alternative response.
|
237
|
+
def reset
|
238
|
+
@header.out.rewind
|
239
|
+
@body.rewind
|
240
|
+
end
|
241
|
+
|
242
|
+
# This takes whatever has been done to header and body and then writes it in the
|
243
|
+
# proper format to make an HTTP/1.1 response.
|
121
244
|
def finished
|
122
245
|
@header.out.rewind
|
123
246
|
@body.rewind
|
@@ -136,29 +259,8 @@ module Mongrel
|
|
136
259
|
# a response. Look at the HttpRequest and HttpResponse objects for how
|
137
260
|
# to use them.
|
138
261
|
class HttpHandler
|
139
|
-
attr_accessor :script_name
|
140
|
-
|
141
|
-
def process(request, response)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
|
146
|
-
# The server normally returns a 404 response if a URI is requested, but it
|
147
|
-
# also returns a lame empty message. This lets you do a 404 response
|
148
|
-
# with a custom message for special URIs.
|
149
|
-
class Error404Handler < HttpHandler
|
150
|
-
|
151
|
-
# Sets the message to return. This is constructed once for the handler
|
152
|
-
# so it's pretty efficient.
|
153
|
-
def initialize(msg)
|
154
|
-
@response = HttpServer::ERROR_404_RESPONSE + msg
|
155
|
-
end
|
156
|
-
|
157
|
-
# Just kicks back the standard 404 response with your special message.
|
158
262
|
def process(request, response)
|
159
|
-
response.socket.write(@response)
|
160
263
|
end
|
161
|
-
|
162
264
|
end
|
163
265
|
|
164
266
|
|
@@ -183,16 +285,6 @@ module Mongrel
|
|
183
285
|
class HttpServer
|
184
286
|
attr_reader :acceptor
|
185
287
|
|
186
|
-
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
187
|
-
ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: Mongrel/0.2\r\n\r\nNOT FOUND"
|
188
|
-
ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
|
189
|
-
|
190
|
-
# The basic max request size we'll try to read.
|
191
|
-
CHUNK_SIZE=(16 * 1024)
|
192
|
-
|
193
|
-
PATH_INFO="PATH_INFO"
|
194
|
-
SCRIPT_NAME="SCRIPT_NAME"
|
195
|
-
|
196
288
|
# Creates a working server on host:port (strange things happen if port isn't a Number).
|
197
289
|
# Use HttpServer::run to start the server.
|
198
290
|
#
|
@@ -210,8 +302,13 @@ module Mongrel
|
|
210
302
|
# Future versions of Mongrel will make this more dynamic (hopefully).
|
211
303
|
def initialize(host, port, num_processors=20)
|
212
304
|
@socket = TCPServer.new(host, port)
|
305
|
+
|
213
306
|
@classifier = URIClassifier.new
|
214
307
|
@req_queue = Queue.new
|
308
|
+
@host = host
|
309
|
+
@port = port
|
310
|
+
@num_procesors = num_processors
|
311
|
+
|
215
312
|
num_processors.times {|i| Thread.new do
|
216
313
|
while client = @req_queue.deq
|
217
314
|
process_client(client)
|
@@ -223,30 +320,35 @@ module Mongrel
|
|
223
320
|
|
224
321
|
# Does the majority of the IO processing. It has been written in Ruby using
|
225
322
|
# about 7 different IO processing strategies and no matter how it's done
|
226
|
-
# the performance just does not improve.
|
227
|
-
#
|
228
|
-
#
|
229
|
-
# focus of future releases.
|
323
|
+
# the performance just does not improve. It is currently carefully constructed
|
324
|
+
# to make sure that it gets the best possible performance, but anyone who
|
325
|
+
# thinks they can make it faster is more than welcome to take a crack at it.
|
230
326
|
def process_client(client)
|
231
327
|
begin
|
232
328
|
parser = HttpParser.new
|
233
329
|
params = {}
|
234
|
-
data = client.readpartial(CHUNK_SIZE)
|
330
|
+
data = client.readpartial(Const::CHUNK_SIZE)
|
235
331
|
|
236
332
|
while true
|
237
333
|
nread = parser.execute(params, data)
|
238
334
|
if parser.finished?
|
239
|
-
script_name, path_info, handler = @classifier.resolve(params[
|
335
|
+
script_name, path_info, handler = @classifier.resolve(params[Const::REQUEST_URI])
|
240
336
|
|
241
337
|
if handler
|
242
|
-
params[PATH_INFO] = path_info
|
243
|
-
params[SCRIPT_NAME] = script_name
|
338
|
+
params[Const::PATH_INFO] = path_info
|
339
|
+
params[Const::SCRIPT_NAME] = script_name
|
340
|
+
params[Const::GATEWAY_INTERFACE]=Const::GATEWAY_INTERFACE_VALUE
|
341
|
+
params[Const::REMOTE_ADDR]=client.peeraddr
|
342
|
+
params[Const::SERVER_NAME]=@host
|
343
|
+
params[Const::SERVER_PORT]=@port
|
344
|
+
params[Const::SERVER_PROTOCOL]=Const::SERVER_PROTOCOL_VALUE
|
345
|
+
params[Const::SERVER_SOFTWARE]=Const::MONGREL_VERSION
|
244
346
|
|
245
347
|
request = HttpRequest.new(params, data[nread ... data.length], client)
|
246
348
|
response = HttpResponse.new(client)
|
247
349
|
handler.process(request, response)
|
248
350
|
else
|
249
|
-
client.write(ERROR_404_RESPONSE)
|
351
|
+
client.write(Const::ERROR_404_RESPONSE)
|
250
352
|
end
|
251
353
|
|
252
354
|
break
|
@@ -254,7 +356,7 @@ module Mongrel
|
|
254
356
|
# gotta stream and read again until we can get the parser to be character safe
|
255
357
|
# TODO: make this more efficient since this means we're parsing a lot repeatedly
|
256
358
|
parser.reset
|
257
|
-
data << client.readpartial(CHUNK_SIZE)
|
359
|
+
data << client.readpartial(Const::CHUNK_SIZE)
|
258
360
|
end
|
259
361
|
end
|
260
362
|
rescue EOFError
|
@@ -274,6 +376,7 @@ module Mongrel
|
|
274
376
|
# Runs the thing. It returns the thread used so you can "join" it. You can also
|
275
377
|
# access the HttpServer::acceptor attribute to get the thread later.
|
276
378
|
def run
|
379
|
+
BasicSocket.do_not_reverse_lookup=true
|
277
380
|
@acceptor = Thread.new do
|
278
381
|
while true
|
279
382
|
@req_queue << @socket.accept
|
@@ -295,4 +398,95 @@ module Mongrel
|
|
295
398
|
@classifier.unregister(uri)
|
296
399
|
end
|
297
400
|
end
|
401
|
+
|
402
|
+
|
403
|
+
# The server normally returns a 404 response if a URI is requested, but it
|
404
|
+
# also returns a lame empty message. This lets you do a 404 response
|
405
|
+
# with a custom message for special URIs.
|
406
|
+
class Error404Handler < HttpHandler
|
407
|
+
|
408
|
+
# Sets the message to return. This is constructed once for the handler
|
409
|
+
# so it's pretty efficient.
|
410
|
+
def initialize(msg)
|
411
|
+
@response = HttpServer::ERROR_404_RESPONSE + msg
|
412
|
+
end
|
413
|
+
|
414
|
+
# Just kicks back the standard 404 response with your special message.
|
415
|
+
def process(request, response)
|
416
|
+
response.socket.write(@response)
|
417
|
+
end
|
418
|
+
|
419
|
+
end
|
420
|
+
|
421
|
+
|
422
|
+
# Serves the contents of a directory. You give it the path to the root
|
423
|
+
# where the files are located, and it tries to find the files based on
|
424
|
+
# the PATH_INFO inside the directory. If the requested path is a
|
425
|
+
# directory then it returns a simple directory listing.
|
426
|
+
#
|
427
|
+
# It does a simple protection against going outside it's root path by
|
428
|
+
# converting all paths to an absolute expanded path, and then making sure
|
429
|
+
# that the final expanded path includes the root path. If it doesn't
|
430
|
+
# than it simply gives a 404.
|
431
|
+
class DirHandler < HttpHandler
|
432
|
+
|
433
|
+
def initialize(path, listing_allowed=true)
|
434
|
+
@path = File.expand_path(path)
|
435
|
+
@listing_allowed=listing_allowed
|
436
|
+
puts "DIR: #@path"
|
437
|
+
end
|
438
|
+
|
439
|
+
def send_dir_listing(base, dir, response)
|
440
|
+
if @listing_allowed
|
441
|
+
response.start(200) do |head,out|
|
442
|
+
head['Content-Type'] = "text/html"
|
443
|
+
out << "<html><head><title>Directory Listing</title></head><body>"
|
444
|
+
Dir.entries(dir).each do |child|
|
445
|
+
out << "<a href=\"#{base}/#{child}\">#{child}</a><br/>"
|
446
|
+
end
|
447
|
+
out << "</body></html>"
|
448
|
+
end
|
449
|
+
else
|
450
|
+
response.start(403) do |head,out|
|
451
|
+
out.write("Directory listings not allowed")
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
def send_file(req, response)
|
458
|
+
response.start(200) do |head,out|
|
459
|
+
open(req, "r") do |f|
|
460
|
+
out.write(f.read)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
|
466
|
+
def process(request, response)
|
467
|
+
req = File.expand_path("." + request.params['PATH_INFO'], @path)
|
468
|
+
puts "FIND: #{req}"
|
469
|
+
if req.index(@path) != 0 or !File.exist? req
|
470
|
+
# not found, return a 404
|
471
|
+
response.start(404) do |head,out|
|
472
|
+
out << "File not found"
|
473
|
+
end
|
474
|
+
else
|
475
|
+
begin
|
476
|
+
if File.directory? req
|
477
|
+
send_dir_listing(request.params["REQUEST_URI"],req, response)
|
478
|
+
else
|
479
|
+
send_file(req, response)
|
480
|
+
end
|
481
|
+
rescue => details
|
482
|
+
response.reset
|
483
|
+
response.start(403) do |head,out|
|
484
|
+
out << "Error accessing file"
|
485
|
+
end
|
486
|
+
STDERR.puts "ERROR: #{details}"
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
298
492
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: mongrel
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2006-02-
|
6
|
+
version: 0.2.2
|
7
|
+
date: 2006-02-03 00:00:00 -05:00
|
8
8
|
summary: An experimental fast simple web server for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -45,6 +45,9 @@ files:
|
|
45
45
|
- doc/rdoc/rdoc-style.css
|
46
46
|
- doc/rdoc/classes/Mongrel
|
47
47
|
- doc/rdoc/classes/Mongrel.html
|
48
|
+
- doc/rdoc/classes/Mongrel/Const.html
|
49
|
+
- doc/rdoc/classes/Mongrel/DirHandler.html
|
50
|
+
- doc/rdoc/classes/Mongrel/DirHandler.src
|
48
51
|
- doc/rdoc/classes/Mongrel/Error404Handler.html
|
49
52
|
- doc/rdoc/classes/Mongrel/Error404Handler.src
|
50
53
|
- doc/rdoc/classes/Mongrel/HeaderOut.html
|
@@ -61,11 +64,15 @@ files:
|
|
61
64
|
- doc/rdoc/classes/Mongrel/HttpServer.src
|
62
65
|
- doc/rdoc/classes/Mongrel/URIClassifier.html
|
63
66
|
- doc/rdoc/classes/Mongrel/URIClassifier.src
|
64
|
-
- doc/rdoc/classes/Mongrel/
|
65
|
-
- doc/rdoc/classes/Mongrel/
|
66
|
-
- doc/rdoc/classes/Mongrel/
|
67
|
-
- doc/rdoc/classes/Mongrel/
|
68
|
-
- doc/rdoc/classes/Mongrel/
|
67
|
+
- doc/rdoc/classes/Mongrel/DirHandler.src/M000008.html
|
68
|
+
- doc/rdoc/classes/Mongrel/DirHandler.src/M000009.html
|
69
|
+
- doc/rdoc/classes/Mongrel/DirHandler.src/M000010.html
|
70
|
+
- doc/rdoc/classes/Mongrel/DirHandler.src/M000011.html
|
71
|
+
- doc/rdoc/classes/Mongrel/Error404Handler.src/M000028.html
|
72
|
+
- doc/rdoc/classes/Mongrel/Error404Handler.src/M000029.html
|
73
|
+
- doc/rdoc/classes/Mongrel/HeaderOut.src/M000017.html
|
74
|
+
- doc/rdoc/classes/Mongrel/HeaderOut.src/M000018.html
|
75
|
+
- doc/rdoc/classes/Mongrel/HttpHandler.src/M000023.html
|
69
76
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000001.html
|
70
77
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html
|
71
78
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html
|
@@ -73,19 +80,20 @@ files:
|
|
73
80
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html
|
74
81
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html
|
75
82
|
- doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html
|
76
|
-
- doc/rdoc/classes/Mongrel/HttpRequest.src/
|
77
|
-
- doc/rdoc/classes/Mongrel/HttpResponse.src/
|
78
|
-
- doc/rdoc/classes/Mongrel/HttpResponse.src/
|
79
|
-
- doc/rdoc/classes/Mongrel/HttpResponse.src/
|
80
|
-
- doc/rdoc/classes/Mongrel/
|
81
|
-
- doc/rdoc/classes/Mongrel/HttpServer.src/M000009.html
|
82
|
-
- doc/rdoc/classes/Mongrel/HttpServer.src/M000010.html
|
83
|
-
- doc/rdoc/classes/Mongrel/HttpServer.src/M000011.html
|
83
|
+
- doc/rdoc/classes/Mongrel/HttpRequest.src/M000030.html
|
84
|
+
- doc/rdoc/classes/Mongrel/HttpResponse.src/M000024.html
|
85
|
+
- doc/rdoc/classes/Mongrel/HttpResponse.src/M000025.html
|
86
|
+
- doc/rdoc/classes/Mongrel/HttpResponse.src/M000026.html
|
87
|
+
- doc/rdoc/classes/Mongrel/HttpResponse.src/M000027.html
|
84
88
|
- doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html
|
85
|
-
- doc/rdoc/classes/Mongrel/
|
86
|
-
- doc/rdoc/classes/Mongrel/
|
87
|
-
- doc/rdoc/classes/Mongrel/
|
88
|
-
- doc/rdoc/classes/Mongrel/
|
89
|
+
- doc/rdoc/classes/Mongrel/HttpServer.src/M000013.html
|
90
|
+
- doc/rdoc/classes/Mongrel/HttpServer.src/M000014.html
|
91
|
+
- doc/rdoc/classes/Mongrel/HttpServer.src/M000015.html
|
92
|
+
- doc/rdoc/classes/Mongrel/HttpServer.src/M000016.html
|
93
|
+
- doc/rdoc/classes/Mongrel/URIClassifier.src/M000019.html
|
94
|
+
- doc/rdoc/classes/Mongrel/URIClassifier.src/M000020.html
|
95
|
+
- doc/rdoc/classes/Mongrel/URIClassifier.src/M000021.html
|
96
|
+
- doc/rdoc/classes/Mongrel/URIClassifier.src/M000022.html
|
89
97
|
- doc/rdoc/files/COPYING.html
|
90
98
|
- doc/rdoc/files/ext
|
91
99
|
- doc/rdoc/files/lib
|
@@ -98,6 +106,7 @@ files:
|
|
98
106
|
- test/test_response.rb
|
99
107
|
- test/test_uriclassifier.rb
|
100
108
|
- test/test_ws.rb
|
109
|
+
- lib/#mongrel.rb#
|
101
110
|
- lib/mongrel.rb
|
102
111
|
- ext/http11/ext_help.h
|
103
112
|
- ext/http11/http11_parser.h
|