mongrel 0.2.2 → 0.3
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/README +27 -25
- data/Rakefile +2 -3
- data/bin/mongrel_rails +114 -0
- data/doc/rdoc/classes/Mongrel.html +30 -0
- data/doc/rdoc/classes/Mongrel.src/M000001.html +18 -0
- data/doc/rdoc/classes/Mongrel/Const.html +2 -2
- data/doc/rdoc/classes/Mongrel/DirHandler.html +84 -21
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000009.html +7 -18
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000010.html +26 -9
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000011.html +27 -26
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000012.html +31 -0
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000013.html +38 -0
- data/doc/rdoc/classes/Mongrel/Error404Handler.html +10 -10
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000028.html → M000033.html} +4 -4
- data/doc/rdoc/classes/Mongrel/Error404Handler.src/{M000029.html → M000034.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.html +10 -10
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000017.html → M000019.html} +4 -4
- data/doc/rdoc/classes/Mongrel/HeaderOut.src/{M000018.html → M000020.html} +7 -7
- data/doc/rdoc/classes/Mongrel/HttpHandler.html +5 -5
- data/doc/rdoc/classes/Mongrel/HttpHandler.src/{M000023.html → M000025.html} +3 -3
- data/doc/rdoc/classes/Mongrel/HttpParser.html +35 -35
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000002.html +5 -6
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000003.html +7 -7
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000004.html +8 -20
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000005.html +20 -6
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000006.html +5 -5
- data/doc/rdoc/classes/Mongrel/HttpParser.src/M000007.html +5 -6
- data/doc/rdoc/classes/Mongrel/HttpParser.src/{M000001.html → M000008.html} +6 -6
- data/doc/rdoc/classes/Mongrel/HttpRequest.html +5 -5
- data/doc/rdoc/classes/Mongrel/HttpRequest.src/{M000030.html → M000035.html} +17 -17
- data/doc/rdoc/classes/Mongrel/HttpResponse.html +66 -21
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000026.html +8 -6
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000027.html +7 -12
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000028.html +19 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000029.html +18 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000030.html +20 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000031.html +21 -0
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000032.html +20 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.html +28 -28
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000014.html +18 -10
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000015.html +51 -5
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000016.html +9 -4
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000017.html +18 -0
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000018.html +18 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +31 -21
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000021.html +18 -15
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000022.html +25 -42
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000023.html +36 -0
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000024.html +84 -0
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/README.html +32 -42
- 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_method_index.html +35 -30
- data/examples/simpletest.rb +16 -6
- data/ext/http11/http11.c +19 -3
- data/ext/http11/tst_search.c +2 -3
- data/lib/mongrel.rb +108 -20
- data/test/test_uriclassifier.rb +22 -1
- metadata +25 -19
- data/doc/rdoc/classes/Mongrel/DirHandler.src/M000008.html +0 -20
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000024.html +0 -21
- data/doc/rdoc/classes/Mongrel/HttpResponse.src/M000025.html +0 -20
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000012.html +0 -31
- data/doc/rdoc/classes/Mongrel/HttpServer.src/M000013.html +0 -64
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000019.html +0 -39
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000020.html +0 -51
- data/lib/#mongrel.rb# +0 -493
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>new (Mongrel::DirHandler)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre> <span class="ruby-comment cmt"># File lib/mongrel.rb, line 433</span>
|
|
14
|
-
433: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">path</span>, <span class="ruby-identifier">listing_allowed</span>=<span class="ruby-keyword kw">true</span>)
|
|
15
|
-
434: <span class="ruby-ivar">@path</span> = <span class="ruby-constant">File</span>.<span class="ruby-identifier">expand_path</span>(<span class="ruby-identifier">path</span>)
|
|
16
|
-
435: <span class="ruby-ivar">@listing_allowed</span>=<span class="ruby-identifier">listing_allowed</span>
|
|
17
|
-
436: <span class="ruby-identifier">puts</span> <span class="ruby-value str">"DIR: #@path"</span>
|
|
18
|
-
437: <span class="ruby-keyword kw">end</span></pre>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>new (Mongrel::HttpResponse)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre> <span class="ruby-comment cmt"># File lib/mongrel.rb, line 218</span>
|
|
14
|
-
218: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">socket</span>)
|
|
15
|
-
219: <span class="ruby-ivar">@socket</span> = <span class="ruby-identifier">socket</span>
|
|
16
|
-
220: <span class="ruby-ivar">@body</span> = <span class="ruby-constant">StringIO</span>.<span class="ruby-identifier">new</span>
|
|
17
|
-
221: <span class="ruby-ivar">@status</span> = <span class="ruby-value">404</span>
|
|
18
|
-
222: <span class="ruby-ivar">@header</span> = <span class="ruby-constant">HeaderOut</span>.<span class="ruby-identifier">new</span>(<span class="ruby-constant">StringIO</span>.<span class="ruby-identifier">new</span>)
|
|
19
|
-
223: <span class="ruby-keyword kw">end</span></pre>
|
|
20
|
-
</body>
|
|
21
|
-
</html>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>start (Mongrel::HttpResponse)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre> <span class="ruby-comment cmt"># File lib/mongrel.rb, line 229</span>
|
|
14
|
-
229: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">start</span>(<span class="ruby-identifier">status</span>=<span class="ruby-value">200</span>)
|
|
15
|
-
230: <span class="ruby-ivar">@status</span> = <span class="ruby-identifier">status</span>
|
|
16
|
-
231: <span class="ruby-keyword kw">yield</span> <span class="ruby-ivar">@header</span>, <span class="ruby-ivar">@body</span>
|
|
17
|
-
232: <span class="ruby-identifier">finished</span>
|
|
18
|
-
233: <span class="ruby-keyword kw">end</span></pre>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>new (Mongrel::HttpServer)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre> <span class="ruby-comment cmt"># File lib/mongrel.rb, line 303</span>
|
|
14
|
-
303: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">port</span>, <span class="ruby-identifier">num_processors</span>=<span class="ruby-value">20</span>)
|
|
15
|
-
304: <span class="ruby-ivar">@socket</span> = <span class="ruby-constant">TCPServer</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">port</span>)
|
|
16
|
-
305:
|
|
17
|
-
306: <span class="ruby-ivar">@classifier</span> = <span class="ruby-constant">URIClassifier</span>.<span class="ruby-identifier">new</span>
|
|
18
|
-
307: <span class="ruby-ivar">@req_queue</span> = <span class="ruby-constant">Queue</span>.<span class="ruby-identifier">new</span>
|
|
19
|
-
308: <span class="ruby-ivar">@host</span> = <span class="ruby-identifier">host</span>
|
|
20
|
-
309: <span class="ruby-ivar">@port</span> = <span class="ruby-identifier">port</span>
|
|
21
|
-
310: <span class="ruby-ivar">@num_procesors</span> = <span class="ruby-identifier">num_processors</span>
|
|
22
|
-
311:
|
|
23
|
-
312: <span class="ruby-identifier">num_processors</span>.<span class="ruby-identifier">times</span> {<span class="ruby-operator">|</span><span class="ruby-identifier">i</span><span class="ruby-operator">|</span> <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">new</span> <span class="ruby-keyword kw">do</span>
|
|
24
|
-
313: <span class="ruby-keyword kw">while</span> <span class="ruby-identifier">client</span> = <span class="ruby-ivar">@req_queue</span>.<span class="ruby-identifier">deq</span>
|
|
25
|
-
314: <span class="ruby-identifier">process_client</span>(<span class="ruby-identifier">client</span>)
|
|
26
|
-
315: <span class="ruby-keyword kw">end</span>
|
|
27
|
-
316: <span class="ruby-keyword kw">end</span>
|
|
28
|
-
317: }
|
|
29
|
-
318: <span class="ruby-keyword kw">end</span></pre>
|
|
30
|
-
</body>
|
|
31
|
-
</html>
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>process_client (Mongrel::HttpServer)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre> <span class="ruby-comment cmt"># File lib/mongrel.rb, line 326</span>
|
|
14
|
-
326: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">process_client</span>(<span class="ruby-identifier">client</span>)
|
|
15
|
-
327: <span class="ruby-keyword kw">begin</span>
|
|
16
|
-
328: <span class="ruby-identifier">parser</span> = <span class="ruby-constant">HttpParser</span>.<span class="ruby-identifier">new</span>
|
|
17
|
-
329: <span class="ruby-identifier">params</span> = {}
|
|
18
|
-
330: <span class="ruby-identifier">data</span> = <span class="ruby-identifier">client</span>.<span class="ruby-identifier">readpartial</span>(<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">CHUNK_SIZE</span>)
|
|
19
|
-
331:
|
|
20
|
-
332: <span class="ruby-keyword kw">while</span> <span class="ruby-keyword kw">true</span>
|
|
21
|
-
333: <span class="ruby-identifier">nread</span> = <span class="ruby-identifier">parser</span>.<span class="ruby-identifier">execute</span>(<span class="ruby-identifier">params</span>, <span class="ruby-identifier">data</span>)
|
|
22
|
-
334: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">parser</span>.<span class="ruby-identifier">finished?</span>
|
|
23
|
-
335: <span class="ruby-identifier">script_name</span>, <span class="ruby-identifier">path_info</span>, <span class="ruby-identifier">handler</span> = <span class="ruby-ivar">@classifier</span>.<span class="ruby-identifier">resolve</span>(<span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">REQUEST_URI</span>])
|
|
24
|
-
336:
|
|
25
|
-
337: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">handler</span>
|
|
26
|
-
338: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">PATH_INFO</span>] = <span class="ruby-identifier">path_info</span>
|
|
27
|
-
339: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SCRIPT_NAME</span>] = <span class="ruby-identifier">script_name</span>
|
|
28
|
-
340: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">GATEWAY_INTERFACE</span>]=<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">GATEWAY_INTERFACE_VALUE</span>
|
|
29
|
-
341: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">REMOTE_ADDR</span>]=<span class="ruby-identifier">client</span>.<span class="ruby-identifier">peeraddr</span>
|
|
30
|
-
342: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SERVER_NAME</span>]=<span class="ruby-ivar">@host</span>
|
|
31
|
-
343: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SERVER_PORT</span>]=<span class="ruby-ivar">@port</span>
|
|
32
|
-
344: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SERVER_PROTOCOL</span>]=<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SERVER_PROTOCOL_VALUE</span>
|
|
33
|
-
345: <span class="ruby-identifier">params</span>[<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">SERVER_SOFTWARE</span>]=<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">MONGREL_VERSION</span>
|
|
34
|
-
346:
|
|
35
|
-
347: <span class="ruby-identifier">request</span> = <span class="ruby-constant">HttpRequest</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">params</span>, <span class="ruby-identifier">data</span>[<span class="ruby-identifier">nread</span> <span class="ruby-operator">...</span> <span class="ruby-identifier">data</span>.<span class="ruby-identifier">length</span>], <span class="ruby-identifier">client</span>)
|
|
36
|
-
348: <span class="ruby-identifier">response</span> = <span class="ruby-constant">HttpResponse</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">client</span>)
|
|
37
|
-
349: <span class="ruby-identifier">handler</span>.<span class="ruby-identifier">process</span>(<span class="ruby-identifier">request</span>, <span class="ruby-identifier">response</span>)
|
|
38
|
-
350: <span class="ruby-keyword kw">else</span>
|
|
39
|
-
351: <span class="ruby-identifier">client</span>.<span class="ruby-identifier">write</span>(<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">ERROR_404_RESPONSE</span>)
|
|
40
|
-
352: <span class="ruby-keyword kw">end</span>
|
|
41
|
-
353:
|
|
42
|
-
354: <span class="ruby-keyword kw">break</span>
|
|
43
|
-
355: <span class="ruby-keyword kw">else</span>
|
|
44
|
-
356: <span class="ruby-comment cmt"># gotta stream and read again until we can get the parser to be character safe</span>
|
|
45
|
-
357: <span class="ruby-comment cmt"># TODO: make this more efficient since this means we're parsing a lot repeatedly</span>
|
|
46
|
-
358: <span class="ruby-identifier">parser</span>.<span class="ruby-identifier">reset</span>
|
|
47
|
-
359: <span class="ruby-identifier">data</span> <span class="ruby-operator"><<</span> <span class="ruby-identifier">client</span>.<span class="ruby-identifier">readpartial</span>(<span class="ruby-constant">Const</span><span class="ruby-operator">::</span><span class="ruby-constant">CHUNK_SIZE</span>)
|
|
48
|
-
360: <span class="ruby-keyword kw">end</span>
|
|
49
|
-
361: <span class="ruby-keyword kw">end</span>
|
|
50
|
-
362: <span class="ruby-keyword kw">rescue</span> <span class="ruby-constant">EOFError</span>
|
|
51
|
-
363: <span class="ruby-comment cmt"># ignored</span>
|
|
52
|
-
364: <span class="ruby-keyword kw">rescue</span> <span class="ruby-constant">Errno</span><span class="ruby-operator">::</span><span class="ruby-constant">ECONNRESET</span>
|
|
53
|
-
365: <span class="ruby-comment cmt"># ignored</span>
|
|
54
|
-
366: <span class="ruby-keyword kw">rescue</span> <span class="ruby-constant">Errno</span><span class="ruby-operator">::</span><span class="ruby-constant">EPIPE</span>
|
|
55
|
-
367: <span class="ruby-comment cmt"># ignored</span>
|
|
56
|
-
368: <span class="ruby-keyword kw">rescue</span> =<span class="ruby-operator">></span> <span class="ruby-identifier">details</span>
|
|
57
|
-
369: <span class="ruby-constant">STDERR</span>.<span class="ruby-identifier">puts</span> <span class="ruby-node">"ERROR(#{details.class}): #{details}"</span>
|
|
58
|
-
370: <span class="ruby-constant">STDERR</span>.<span class="ruby-identifier">puts</span> <span class="ruby-identifier">details</span>.<span class="ruby-identifier">backtrace</span>.<span class="ruby-identifier">join</span>(<span class="ruby-value str">"\n"</span>)
|
|
59
|
-
371: <span class="ruby-keyword kw">ensure</span>
|
|
60
|
-
372: <span class="ruby-identifier">client</span>.<span class="ruby-identifier">close</span>
|
|
61
|
-
373: <span class="ruby-keyword kw">end</span>
|
|
62
|
-
374: <span class="ruby-keyword kw">end</span></pre>
|
|
63
|
-
</body>
|
|
64
|
-
</html>
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>new (Mongrel::URIClassifier)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre>/**
|
|
14
|
-
* call-seq:
|
|
15
|
-
* URIClassifier.new -> URIClassifier
|
|
16
|
-
*
|
|
17
|
-
* Initializes a new URIClassifier object that you can use to associate URI sequences
|
|
18
|
-
* with objects. You can actually use it with any string sequence and any objects,
|
|
19
|
-
* but it's mostly used with URIs.
|
|
20
|
-
*
|
|
21
|
-
* It uses TST from http://www.octavian.org/cs/software.html to build an ternary search
|
|
22
|
-
* trie to hold all of the URIs. It uses this to do an initial search for the a URI
|
|
23
|
-
* prefix, and then to break the URI into SCRIPT_NAME and PATH_INFO portions. It actually
|
|
24
|
-
* will do two searches most of the time in order to find the right handler for the
|
|
25
|
-
* registered prefix portion.
|
|
26
|
-
*
|
|
27
|
-
*/
|
|
28
|
-
VALUE URIClassifier_init(VALUE self)
|
|
29
|
-
{
|
|
30
|
-
VALUE hash;
|
|
31
|
-
|
|
32
|
-
// we create an internal hash to protect stuff from the GC
|
|
33
|
-
hash = rb_hash_new();
|
|
34
|
-
rb_ivar_set(self, id_handler_map, hash);
|
|
35
|
-
|
|
36
|
-
return self;
|
|
37
|
-
}</pre>
|
|
38
|
-
</body>
|
|
39
|
-
</html>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
2
|
-
<!DOCTYPE html
|
|
3
|
-
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
4
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
5
|
-
|
|
6
|
-
<html>
|
|
7
|
-
<head>
|
|
8
|
-
<title>register (Mongrel::URIClassifier)</title>
|
|
9
|
-
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
|
10
|
-
<link rel="stylesheet" href="../../.././rdoc-style.css" type="text/css" media="screen" />
|
|
11
|
-
</head>
|
|
12
|
-
<body class="standalone-code">
|
|
13
|
-
<pre>/**
|
|
14
|
-
* call-seq:
|
|
15
|
-
* uc.register("/someuri", SampleHandler.new) -> nil
|
|
16
|
-
*
|
|
17
|
-
* Registers the SampleHandler (one for all requests) with the "/someuri".
|
|
18
|
-
* When URIClassifier::resolve is called with "/someuri" it'll return
|
|
19
|
-
* SampleHandler immediately. When called with "/someuri/iwant" it'll also
|
|
20
|
-
* return SomeHandler immediatly, with no additional searches, but it will
|
|
21
|
-
* return path info with "/iwant".
|
|
22
|
-
*
|
|
23
|
-
* You actually can reuse this class to register nearly anything and
|
|
24
|
-
* quickly resolve it. This could be used for caching, fast mapping, etc.
|
|
25
|
-
* The downside is it uses much more memory than a Hash, but it can be
|
|
26
|
-
* a lot faster. It's main advantage is that it works on prefixes, which
|
|
27
|
-
* is damn hard to get right with a Hash.
|
|
28
|
-
*/
|
|
29
|
-
VALUE URIClassifier_register(VALUE self, VALUE uri, VALUE handler)
|
|
30
|
-
{
|
|
31
|
-
int rc = 0;
|
|
32
|
-
void *ptr = NULL;
|
|
33
|
-
struct tst *tst = NULL;
|
|
34
|
-
DATA_GET(self, struct tst, tst);
|
|
35
|
-
|
|
36
|
-
rc = tst_insert((unsigned char *)StringValueCStr(uri), (void *)handler , tst, 0, &ptr);
|
|
37
|
-
|
|
38
|
-
if(rc == TST_DUPLICATE_KEY) {
|
|
39
|
-
rb_raise(rb_eStandardError, "Handler already registered with that name");
|
|
40
|
-
} else if(rc == TST_ERROR) {
|
|
41
|
-
rb_raise(rb_eStandardError, "Memory error registering handler");
|
|
42
|
-
} else if(rc == TST_NULL_KEY) {
|
|
43
|
-
rb_raise(rb_eStandardError, "URI was empty");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
rb_hash_aset(rb_ivar_get(self, id_handler_map), uri, handler);
|
|
47
|
-
|
|
48
|
-
return Qnil;
|
|
49
|
-
}</pre>
|
|
50
|
-
</body>
|
|
51
|
-
</html>
|
data/lib/#mongrel.rb#
DELETED
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
require 'socket'
|
|
2
|
-
require 'http11'
|
|
3
|
-
require 'thread'
|
|
4
|
-
require 'stringio'
|
|
5
|
-
|
|
6
|
-
# Mongrel module containing all of the classes (include C extensions) for running
|
|
7
|
-
# a Mongrel web server. It contains a minimalist HTTP server with just enough
|
|
8
|
-
# functionality to service web application requests fast as possible.
|
|
9
|
-
module Mongrel
|
|
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.
|
|
14
|
-
HTTP_STATUS_CODES = {
|
|
15
|
-
100 => 'Continue',
|
|
16
|
-
101 => 'Switching Protocols',
|
|
17
|
-
200 => 'OK',
|
|
18
|
-
201 => 'Created',
|
|
19
|
-
202 => 'Accepted',
|
|
20
|
-
203 => 'Non-Authoritative Information',
|
|
21
|
-
204 => 'No Content',
|
|
22
|
-
205 => 'Reset Content',
|
|
23
|
-
206 => 'Partial Content',
|
|
24
|
-
300 => 'Multiple Choices',
|
|
25
|
-
301 => 'Moved Permanently',
|
|
26
|
-
302 => 'Moved Temporarily',
|
|
27
|
-
303 => 'See Other',
|
|
28
|
-
304 => 'Not Modified',
|
|
29
|
-
305 => 'Use Proxy',
|
|
30
|
-
400 => 'Bad Request',
|
|
31
|
-
401 => 'Unauthorized',
|
|
32
|
-
402 => 'Payment Required',
|
|
33
|
-
403 => 'Forbidden',
|
|
34
|
-
404 => 'Not Found',
|
|
35
|
-
405 => 'Method Not Allowed',
|
|
36
|
-
406 => 'Not Acceptable',
|
|
37
|
-
407 => 'Proxy Authentication Required',
|
|
38
|
-
408 => 'Request Time-out',
|
|
39
|
-
409 => 'Conflict',
|
|
40
|
-
410 => 'Gone',
|
|
41
|
-
411 => 'Length Required',
|
|
42
|
-
412 => 'Precondition Failed',
|
|
43
|
-
413 => 'Request Entity Too Large',
|
|
44
|
-
414 => 'Request-URI Too Large',
|
|
45
|
-
415 => 'Unsupported Media Type',
|
|
46
|
-
500 => 'Internal Server Error',
|
|
47
|
-
501 => 'Not Implemented',
|
|
48
|
-
502 => 'Bad Gateway',
|
|
49
|
-
503 => 'Service Unavailable',
|
|
50
|
-
504 => 'Gateway Time-out',
|
|
51
|
-
505 => 'HTTP Version not supported'
|
|
52
|
-
}
|
|
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
|
-
|
|
124
|
-
# When a handler is found for a registered URI then this class is constructed
|
|
125
|
-
# and passed to your HttpHandler::process method. You should assume that
|
|
126
|
-
# *one* handler processes all requests. Included in the HttpReqeust is a
|
|
127
|
-
# HttpRequest.params Hash that matches common CGI params, and a HttpRequest.body
|
|
128
|
-
# which is a string containing the request body (raw for now).
|
|
129
|
-
#
|
|
130
|
-
# Mongrel really only supports small-ish request bodies right now since really
|
|
131
|
-
# huge ones have to be completely read off the wire and put into a string.
|
|
132
|
-
# Later there will be several options for efficiently handling large file
|
|
133
|
-
# uploads.
|
|
134
|
-
class HttpRequest
|
|
135
|
-
attr_reader :body, :params
|
|
136
|
-
|
|
137
|
-
# You don't really call this. It's made for you.
|
|
138
|
-
# Main thing it does is hook up the params, and store any remaining
|
|
139
|
-
# body data into the HttpRequest.body attribute.
|
|
140
|
-
def initialize(params, initial_body, socket)
|
|
141
|
-
@body = initial_body || ""
|
|
142
|
-
@params = params
|
|
143
|
-
@socket = socket
|
|
144
|
-
|
|
145
|
-
# fix up the CGI requirements
|
|
146
|
-
params[Const::CONTENT_LENGTH] = params[Const::HTTP_CONTENT_LENGTH] || 0
|
|
147
|
-
params[Const::CONTENT_TYPE] ||= params[Const::HTTP_CONTENT_TYPE]
|
|
148
|
-
|
|
149
|
-
# now, if the initial_body isn't long enough for the content length we have to fill it
|
|
150
|
-
# TODO: adapt for big ass stuff by writing to a temp file
|
|
151
|
-
clen = params[Const::HTTP_CONTENT_LENGTH].to_i
|
|
152
|
-
if @body.length < clen
|
|
153
|
-
@body << @socket.read(clen - @body.length)
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
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.
|
|
166
|
-
class HeaderOut
|
|
167
|
-
attr_reader :out
|
|
168
|
-
|
|
169
|
-
def initialize(out)
|
|
170
|
-
@out = out
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
# Simply writes "#{key}: #{value}" to an output buffer.
|
|
174
|
-
def[]=(key,value)
|
|
175
|
-
@out.write(key)
|
|
176
|
-
@out.write(": ")
|
|
177
|
-
@out.write(value)
|
|
178
|
-
@out.write("\r\n")
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
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.
|
|
211
|
-
class HttpResponse
|
|
212
|
-
attr_reader :socket
|
|
213
|
-
attr_reader :body
|
|
214
|
-
attr_reader :header
|
|
215
|
-
attr_reader :status
|
|
216
|
-
attr_writer :status
|
|
217
|
-
|
|
218
|
-
def initialize(socket)
|
|
219
|
-
@socket = socket
|
|
220
|
-
@body = StringIO.new
|
|
221
|
-
@status = 404
|
|
222
|
-
@header = HeaderOut.new(StringIO.new)
|
|
223
|
-
end
|
|
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.
|
|
229
|
-
def start(status=200)
|
|
230
|
-
@status = status
|
|
231
|
-
yield @header, @body
|
|
232
|
-
finished
|
|
233
|
-
end
|
|
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.
|
|
244
|
-
def finished
|
|
245
|
-
@header.out.rewind
|
|
246
|
-
@body.rewind
|
|
247
|
-
|
|
248
|
-
# connection: close is also added to ensure that the client does not pipeline.
|
|
249
|
-
@socket.write("HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status]}\r\nContent-Length: #{@body.length}\r\nConnection: close\r\n")
|
|
250
|
-
@socket.write(@header.out.read)
|
|
251
|
-
@socket.write("\r\n")
|
|
252
|
-
@socket.write(@body.read)
|
|
253
|
-
end
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
# You implement your application handler with this. It's very light giving
|
|
258
|
-
# just the minimum necessary for you to handle a request and shoot back
|
|
259
|
-
# a response. Look at the HttpRequest and HttpResponse objects for how
|
|
260
|
-
# to use them.
|
|
261
|
-
class HttpHandler
|
|
262
|
-
def process(request, response)
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
# This is the main driver of Mongrel, while the Mognrel::HttpParser and Mongrel::URIClassifier
|
|
268
|
-
# make up the majority of how the server functions. It's a very simple class that just
|
|
269
|
-
# has a thread accepting connections and a simple HttpServer.process_client function
|
|
270
|
-
# to do the heavy lifting with the IO and Ruby.
|
|
271
|
-
#
|
|
272
|
-
# You use it by doing the following:
|
|
273
|
-
#
|
|
274
|
-
# server = HttpServer.new("0.0.0.0", 3000)
|
|
275
|
-
# server.register("/stuff", MyNifterHandler.new)
|
|
276
|
-
# server.run.join
|
|
277
|
-
#
|
|
278
|
-
# The last line can be just server.run if you don't want to join the thread used.
|
|
279
|
-
# If you don't though Ruby will mysteriously just exit on you.
|
|
280
|
-
#
|
|
281
|
-
# Ruby's thread implementation is "interesting" to say the least. Experiments with
|
|
282
|
-
# *many* different types of IO processing simply cannot make a dent in it. Future
|
|
283
|
-
# releases of Mongrel will find other creative ways to make threads faster, but don't
|
|
284
|
-
# hold your breath until Ruby 1.9 is actually finally useful.
|
|
285
|
-
class HttpServer
|
|
286
|
-
attr_reader :acceptor
|
|
287
|
-
|
|
288
|
-
# Creates a working server on host:port (strange things happen if port isn't a Number).
|
|
289
|
-
# Use HttpServer::run to start the server.
|
|
290
|
-
#
|
|
291
|
-
# The num_processors variable has varying affects on how requests are processed. You'd
|
|
292
|
-
# think adding more processing threads (processors) would make the server faster, but
|
|
293
|
-
# that's just not true. There's actually an effect of how Ruby does threads such that
|
|
294
|
-
# the more processors waiting on the request queue, the slower the system is to handle
|
|
295
|
-
# each request. But, the lower the number of processors the fewer concurrent responses
|
|
296
|
-
# the server can make.
|
|
297
|
-
#
|
|
298
|
-
# 20 is the default number of processors and is based on experimentation on a few
|
|
299
|
-
# systems. If you find that you overload Mongrel too much
|
|
300
|
-
# try changing it higher. If you find that responses are way too slow
|
|
301
|
-
# try lowering it (after you've tuned your stuff of course).
|
|
302
|
-
# Future versions of Mongrel will make this more dynamic (hopefully).
|
|
303
|
-
def initialize(host, port, num_processors=20)
|
|
304
|
-
@socket = TCPServer.new(host, port)
|
|
305
|
-
|
|
306
|
-
@classifier = URIClassifier.new
|
|
307
|
-
@req_queue = Queue.new
|
|
308
|
-
@host = host
|
|
309
|
-
@port = port
|
|
310
|
-
@num_procesors = num_processors
|
|
311
|
-
|
|
312
|
-
num_processors.times {|i| Thread.new do
|
|
313
|
-
while client = @req_queue.deq
|
|
314
|
-
process_client(client)
|
|
315
|
-
end
|
|
316
|
-
end
|
|
317
|
-
}
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
# Does the majority of the IO processing. It has been written in Ruby using
|
|
322
|
-
# about 7 different IO processing strategies and no matter how it's done
|
|
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.
|
|
326
|
-
def process_client(client)
|
|
327
|
-
begin
|
|
328
|
-
parser = HttpParser.new
|
|
329
|
-
params = {}
|
|
330
|
-
data = client.readpartial(Const::CHUNK_SIZE)
|
|
331
|
-
|
|
332
|
-
while true
|
|
333
|
-
nread = parser.execute(params, data)
|
|
334
|
-
if parser.finished?
|
|
335
|
-
script_name, path_info, handler = @classifier.resolve(params[Const::REQUEST_URI])
|
|
336
|
-
|
|
337
|
-
if handler
|
|
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
|
|
346
|
-
|
|
347
|
-
request = HttpRequest.new(params, data[nread ... data.length], client)
|
|
348
|
-
response = HttpResponse.new(client)
|
|
349
|
-
handler.process(request, response)
|
|
350
|
-
else
|
|
351
|
-
client.write(Const::ERROR_404_RESPONSE)
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
break
|
|
355
|
-
else
|
|
356
|
-
# gotta stream and read again until we can get the parser to be character safe
|
|
357
|
-
# TODO: make this more efficient since this means we're parsing a lot repeatedly
|
|
358
|
-
parser.reset
|
|
359
|
-
data << client.readpartial(Const::CHUNK_SIZE)
|
|
360
|
-
end
|
|
361
|
-
end
|
|
362
|
-
rescue EOFError
|
|
363
|
-
# ignored
|
|
364
|
-
rescue Errno::ECONNRESET
|
|
365
|
-
# ignored
|
|
366
|
-
rescue Errno::EPIPE
|
|
367
|
-
# ignored
|
|
368
|
-
rescue => details
|
|
369
|
-
STDERR.puts "ERROR(#{details.class}): #{details}"
|
|
370
|
-
STDERR.puts details.backtrace.join("\n")
|
|
371
|
-
ensure
|
|
372
|
-
client.close
|
|
373
|
-
end
|
|
374
|
-
end
|
|
375
|
-
|
|
376
|
-
# Runs the thing. It returns the thread used so you can "join" it. You can also
|
|
377
|
-
# access the HttpServer::acceptor attribute to get the thread later.
|
|
378
|
-
def run
|
|
379
|
-
BasicSocket.do_not_reverse_lookup=true
|
|
380
|
-
@acceptor = Thread.new do
|
|
381
|
-
while true
|
|
382
|
-
@req_queue << @socket.accept
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
# Simply registers a handler with the internal URIClassifier. When the URI is
|
|
389
|
-
# found in the prefix of a request then your handler's HttpHandler::process method
|
|
390
|
-
# is called. See Mongrel::URIClassifier#register for more information.
|
|
391
|
-
def register(uri, handler)
|
|
392
|
-
@classifier.register(uri, handler)
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
# Removes any handler registered at the given URI. See Mongrel::URIClassifier#unregister
|
|
396
|
-
# for more information.
|
|
397
|
-
def unregister(uri)
|
|
398
|
-
@classifier.unregister(uri)
|
|
399
|
-
end
|
|
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
|
-
# You give it the path to the directory root and an (optional)
|
|
434
|
-
def initialize(path, listing_allowed=true)
|
|
435
|
-
@path = File.expand_path(path)
|
|
436
|
-
@listing_allowed=listing_allowed
|
|
437
|
-
puts "DIR: #@path"
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
def send_dir_listing(base, dir, response)
|
|
441
|
-
if @listing_allowed
|
|
442
|
-
response.start(200) do |head,out|
|
|
443
|
-
head['Content-Type'] = "text/html"
|
|
444
|
-
out << "<html><head><title>Directory Listing</title></head><body>"
|
|
445
|
-
Dir.entries(dir).each do |child|
|
|
446
|
-
out << "<a href=\"#{base}/#{child}\">#{child}</a><br/>"
|
|
447
|
-
end
|
|
448
|
-
out << "</body></html>"
|
|
449
|
-
end
|
|
450
|
-
else
|
|
451
|
-
response.start(403) do |head,out|
|
|
452
|
-
out.write("Directory listings not allowed")
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
def send_file(req, response)
|
|
459
|
-
response.start(200) do |head,out|
|
|
460
|
-
open(req, "r") do |f|
|
|
461
|
-
out.write(f.read)
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
def process(request, response)
|
|
468
|
-
req = File.expand_path("." + request.params['PATH_INFO'], @path)
|
|
469
|
-
puts "FIND: #{req}"
|
|
470
|
-
if req.index(@path) != 0 or !File.exist? req
|
|
471
|
-
# not found, return a 404
|
|
472
|
-
response.start(404) do |head,out|
|
|
473
|
-
out << "File not found"
|
|
474
|
-
end
|
|
475
|
-
else
|
|
476
|
-
begin
|
|
477
|
-
if File.directory? req
|
|
478
|
-
send_dir_listing(request.params["REQUEST_URI"],req, response)
|
|
479
|
-
else
|
|
480
|
-
send_file(req, response)
|
|
481
|
-
end
|
|
482
|
-
rescue => details
|
|
483
|
-
response.reset
|
|
484
|
-
response.start(403) do |head,out|
|
|
485
|
-
out << "Error accessing file"
|
|
486
|
-
end
|
|
487
|
-
STDERR.puts "ERROR: #{details}"
|
|
488
|
-
end
|
|
489
|
-
end
|
|
490
|
-
end
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
end
|