rack 1.3.6 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- data/COPYING +1 -1
- data/KNOWN-ISSUES +9 -0
- data/README.rdoc +100 -4
- data/SPEC +3 -1
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +150 -0
- data/lib/rack/auth/basic.rb +1 -1
- data/lib/rack/auth/digest/nonce.rb +1 -1
- data/lib/rack/backports/uri/common_18.rb +14 -28
- data/lib/rack/backports/uri/common_192.rb +14 -17
- data/lib/rack/backports/uri/common_193.rb +29 -0
- data/lib/rack/body_proxy.rb +10 -0
- data/lib/rack/builder.rb +1 -1
- data/lib/rack/cascade.rb +11 -0
- data/lib/rack/deflater.rb +5 -1
- data/lib/rack/head.rb +1 -0
- data/lib/rack/lint.rb +3 -1
- data/lib/rack/multipart.rb +2 -2
- data/lib/rack/reloader.rb +1 -1
- data/lib/rack/response.rb +2 -1
- data/lib/rack/server.rb +28 -2
- data/lib/rack/session/cookie.rb +9 -0
- data/lib/rack/utils.rb +11 -7
- data/rack.gemspec +3 -3
- data/test/builder/line.ru +1 -0
- data/test/spec_auth_basic.rb +8 -0
- data/test/spec_auth_digest.rb +14 -0
- data/test/spec_body_proxy.rb +4 -0
- data/test/spec_builder.rb +6 -0
- data/test/spec_cascade.rb +8 -0
- data/test/spec_head.rb +18 -6
- data/test/spec_multipart.rb +20 -0
- data/test/spec_response.rb +30 -0
- data/test/spec_server.rb +47 -0
- data/test/spec_session_cookie.rb +19 -0
- data/test/spec_session_pool.rb +3 -3
- data/test/spec_utils.rb +13 -0
- metadata +13 -8
data/COPYING
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
|
1
|
+
Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 Christian Neukirchen <purl.org/net/chneukirchen>
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
4
|
of this software and associated documentation files (the "Software"), to
|
data/KNOWN-ISSUES
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
= Known issues with Rack and ECMA-262
|
2
|
+
|
3
|
+
* Many users expect the escape() function defined in ECMA-262 to be compatible
|
4
|
+
with URI. Confusion is especially strong because the documentation for the
|
5
|
+
escape function includes a reference to the URI specifications. ECMA-262
|
6
|
+
escape is not however a URI escape function, it is a javascript escape
|
7
|
+
function, and is not fully compatible. Most notably, for characters outside of
|
8
|
+
the BMP. Users should use the more correct encodeURI functions.
|
9
|
+
|
1
10
|
= Known issues with Rack and Web servers
|
2
11
|
|
3
12
|
* Lighttpd sets wrong SCRIPT_NAME and PATH_INFO if you mount your
|
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Rack, a modular Ruby webserver interface
|
1
|
+
= Rack, a modular Ruby webserver interface {<img src="https://secure.travis-ci.org/rack/rack.png" alt="Build Status" />}[http://travis-ci.org/rack/rack] {<img src="https://gemnasium.com/rack/rack.png" alt="Dependency Status" />}[https://gemnasium.com/rack/rack]
|
2
2
|
|
3
3
|
Rack provides a minimal, modular and adaptable interface for developing
|
4
4
|
web applications in Ruby. By wrapping HTTP requests and responses in
|
@@ -27,8 +27,11 @@ These web servers include Rack handlers in their distributions:
|
|
27
27
|
* Fuzed
|
28
28
|
* Glassfish v3
|
29
29
|
* Phusion Passenger (which is mod_rack for Apache and for nginx)
|
30
|
+
* Puma
|
30
31
|
* Rainbows!
|
31
32
|
* Unicorn
|
33
|
+
* unixrack
|
34
|
+
* uWSGI
|
32
35
|
* Zbatery
|
33
36
|
|
34
37
|
Any valid Rack app will run the same on all these handlers, without
|
@@ -132,7 +135,11 @@ at my site:
|
|
132
135
|
|
133
136
|
Testing Rack requires the bacon testing framework:
|
134
137
|
|
135
|
-
|
138
|
+
bundle install --without extra # to be able to run the fast tests
|
139
|
+
|
140
|
+
Or:
|
141
|
+
|
142
|
+
bundle install # this assumes that you have installed native extensions!
|
136
143
|
|
137
144
|
There are two rake-based test tasks:
|
138
145
|
|
@@ -373,10 +380,99 @@ run on port 11211) and memcache-client installed.
|
|
373
380
|
* October 17, 2011: Twentieth public release 1.3.5
|
374
381
|
* Fix annoying warnings caused by the backport in 1.3.4
|
375
382
|
|
376
|
-
* December 28th, 2011: Twenty
|
383
|
+
* December 28th, 2011: Twenty first public release: 1.1.3.
|
377
384
|
* Security fix. http://www.ocert.org/advisories/ocert-2011-003.html
|
378
385
|
Further information here: http://jruby.org/2011/12/27/jruby-1-6-5-1
|
379
386
|
|
387
|
+
* December 28th, 2011: Twenty fourth public release 1.4.0
|
388
|
+
* Ruby 1.8.6 support has officially been dropped. Not all tests pass.
|
389
|
+
* Raise sane error messages for broken config.ru
|
390
|
+
* Allow combining run and map in a config.ru
|
391
|
+
* Rack::ContentType will not set Content-Type for responses without a body
|
392
|
+
* Status code 205 does not send a response body
|
393
|
+
* Rack::Response::Helpers will not rely on instance variables
|
394
|
+
* Rack::Utils.build_query no longer outputs '=' for nil query values
|
395
|
+
* Various mime types added
|
396
|
+
* Rack::MockRequest now supports HEAD
|
397
|
+
* Rack::Directory now supports files that contain RFC3986 reserved chars
|
398
|
+
* Rack::File now only supports GET and HEAD requests
|
399
|
+
* Rack::Server#start now passes the block to Rack::Handler::<h>#run
|
400
|
+
* Rack::Static now supports an index option
|
401
|
+
* Added the Teapot status code
|
402
|
+
* rackup now defaults to Thin instead of Mongrel (if installed)
|
403
|
+
* Support added for HTTP_X_FORWARDED_SCHEME
|
404
|
+
* Numerous bug fixes, including many fixes for new and alternate rubies
|
405
|
+
|
406
|
+
* January 22nd, 2012: Twenty fifth public release 1.4.1
|
407
|
+
* Alter the keyspace limit calculations to reduce issues with nested params
|
408
|
+
* Add a workaround for multipart parsing where files contain unescaped "%"
|
409
|
+
* Added Rack::Response::Helpers#method_not_allowed? (code 405)
|
410
|
+
* Rack::File now returns 404 for illegal directory traversals
|
411
|
+
* Rack::File now returns 405 for illegal methods (non HEAD/GET)
|
412
|
+
* Rack::Cascade now catches 405 by default, as well as 404
|
413
|
+
* Cookies missing '--' no longer cause an exception to be raised
|
414
|
+
* Various style changes and documentation spelling errors
|
415
|
+
* Rack::BodyProxy always ensures to execute its block
|
416
|
+
* Additional test coverage around cookies and secrets
|
417
|
+
* Rack::Session::Cookie can now be supplied either secret or old_secret
|
418
|
+
* Tests are no longer dependent on set order
|
419
|
+
* Rack::Static no longer defaults to serving index files
|
420
|
+
* Rack.release was fixed
|
421
|
+
|
422
|
+
* January 6th, 2013: Twenty sixth public release 1.1.4
|
423
|
+
* Add warnings when users do not provide a session secret
|
424
|
+
|
425
|
+
* January 6th, 2013: Twenty seventh public release 1.2.6
|
426
|
+
* Add warnings when users do not provide a session secret
|
427
|
+
* Fix parsing performance for unquoted filenames
|
428
|
+
|
429
|
+
* January 6th, 2013: Twenty eighth public release 1.3.7
|
430
|
+
* Add warnings when users do not provide a session secret
|
431
|
+
* Fix parsing performance for unquoted filenames
|
432
|
+
* Updated URI backports
|
433
|
+
* Fix URI backport version matching, and silence constant warnings
|
434
|
+
* Correct parameter parsing with empty values
|
435
|
+
* Correct rackup '-I' flag, to allow multiple uses
|
436
|
+
* Correct rackup pidfile handling
|
437
|
+
* Report rackup line numbers correctly
|
438
|
+
* Fix request loops caused by non-stale nonces with time limits
|
439
|
+
* Fix reloader on Windows
|
440
|
+
* Prevent infinite recursions from Response#to_ary
|
441
|
+
* Various middleware better conforms to the body close specification
|
442
|
+
* Updated language for the body close specification
|
443
|
+
* Additional notes regarding ECMA escape compatibility issues
|
444
|
+
* Fix the parsing of multiple ranges in range headers
|
445
|
+
|
446
|
+
* January 6th, 2013: Twenty ninth public release 1.4.2
|
447
|
+
* Add warnings when users do not provide a session secret
|
448
|
+
* Fix parsing performance for unquoted filenames
|
449
|
+
* Updated URI backports
|
450
|
+
* Fix URI backport version matching, and silence constant warnings
|
451
|
+
* Correct parameter parsing with empty values
|
452
|
+
* Correct rackup '-I' flag, to allow multiple uses
|
453
|
+
* Correct rackup pidfile handling
|
454
|
+
* Report rackup line numbers correctly
|
455
|
+
* Fix request loops caused by non-stale nonces with time limits
|
456
|
+
* Fix reloader on Windows
|
457
|
+
* Prevent infinite recursions from Response#to_ary
|
458
|
+
* Various middleware better conforms to the body close specification
|
459
|
+
* Updated language for the body close specification
|
460
|
+
* Additional notes regarding ECMA escape compatibility issues
|
461
|
+
* Fix the parsing of multiple ranges in range headers
|
462
|
+
* Prevent errors from empty parameter keys
|
463
|
+
* Added PATCH verb to Rack::Request
|
464
|
+
* Various documentation updates
|
465
|
+
* Fix session merge semantics (fixes rack-test)
|
466
|
+
* Rack::Static :index can now handle multiple directories
|
467
|
+
* All tests now utilize Rack::Lint (special thanks to Lars Gierth)
|
468
|
+
* Rack::File cache_control parameter is now deprecated, and removed by 1.5
|
469
|
+
* Correct Rack::Directory script name escaping
|
470
|
+
* Rack::Static supports header rules for sophisticated configurations
|
471
|
+
* Multipart parsing now works without a Content-Length header
|
472
|
+
* New logos courtesy of Zachary Scott!
|
473
|
+
* Rack::BodyProxy now explicitly defines #each, useful for C extensions
|
474
|
+
* Cookies that are not URI escaped no longer cause exceptions
|
475
|
+
|
380
476
|
== Contact
|
381
477
|
|
382
478
|
Please post bugs, suggestions and patches to
|
@@ -457,7 +553,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
457
553
|
|
458
554
|
== Links
|
459
555
|
|
460
|
-
Rack:: <http://rack.
|
556
|
+
Rack:: <http://rack.github.com/>
|
461
557
|
Official Rack repositories:: <http://github.com/rack>
|
462
558
|
Rack Bug Tracking:: <http://github.com/rack/rack/issues>
|
463
559
|
rack-devel mailing list:: <http://groups.google.com/group/rack-devel>
|
data/SPEC
CHANGED
@@ -156,7 +156,9 @@ The Body must respond to +each+
|
|
156
156
|
and must only yield String values.
|
157
157
|
The Body itself should not be an instance of String, as this will
|
158
158
|
break in Ruby 1.9.
|
159
|
-
If the Body responds to +close+, it will be called after iteration.
|
159
|
+
If the Body responds to +close+, it will be called after iteration. If
|
160
|
+
the body is replaced by a middleware after action, the original body
|
161
|
+
must be closed first, if it repsonds to close.
|
160
162
|
If the Body responds to +to_path+, it must return a String
|
161
163
|
identifying the location of a file whose contents are identical
|
162
164
|
to that produced by calling +each+; this may be used by the
|
data/contrib/rack.png
ADDED
Binary file
|
data/contrib/rack.svg
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
6
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
7
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
8
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
9
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
11
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
12
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
13
|
+
width="744.09448819"
|
14
|
+
height="1052.3622047"
|
15
|
+
id="svg2"
|
16
|
+
version="1.1"
|
17
|
+
inkscape:version="0.48.3.1 r9886"
|
18
|
+
sodipodi:docname="rack.svg">
|
19
|
+
<defs
|
20
|
+
id="defs4">
|
21
|
+
<linearGradient
|
22
|
+
id="linearGradient3837"
|
23
|
+
osb:paint="solid">
|
24
|
+
<stop
|
25
|
+
style="stop-color:#000000;stop-opacity:1;"
|
26
|
+
offset="0"
|
27
|
+
id="stop3839" />
|
28
|
+
</linearGradient>
|
29
|
+
</defs>
|
30
|
+
<sodipodi:namedview
|
31
|
+
id="base"
|
32
|
+
pagecolor="#ffffff"
|
33
|
+
bordercolor="#666666"
|
34
|
+
borderopacity="1.0"
|
35
|
+
inkscape:pageopacity="0.0"
|
36
|
+
inkscape:pageshadow="2"
|
37
|
+
inkscape:zoom="0.98994949"
|
38
|
+
inkscape:cx="230.49849"
|
39
|
+
inkscape:cy="656.46253"
|
40
|
+
inkscape:document-units="px"
|
41
|
+
inkscape:current-layer="layer1"
|
42
|
+
showgrid="false"
|
43
|
+
showguides="false"
|
44
|
+
inkscape:guide-bbox="true"
|
45
|
+
inkscape:window-width="1920"
|
46
|
+
inkscape:window-height="1056"
|
47
|
+
inkscape:window-x="1920"
|
48
|
+
inkscape:window-y="24"
|
49
|
+
inkscape:window-maximized="1">
|
50
|
+
<sodipodi:guide
|
51
|
+
orientation="1,0"
|
52
|
+
position="645.99255,757.10933"
|
53
|
+
id="guide2995" />
|
54
|
+
<sodipodi:guide
|
55
|
+
orientation="1,0"
|
56
|
+
position="488.40876,686.90373"
|
57
|
+
id="guide2997" />
|
58
|
+
<sodipodi:guide
|
59
|
+
orientation="1,0"
|
60
|
+
position="176.7767,748.52304"
|
61
|
+
id="guide2999" />
|
62
|
+
<sodipodi:guide
|
63
|
+
orientation="1,0"
|
64
|
+
position="355.71429,782.85714"
|
65
|
+
id="guide3005" />
|
66
|
+
<sodipodi:guide
|
67
|
+
orientation="0,1"
|
68
|
+
position="527.14286,642.85714"
|
69
|
+
id="guide3007" />
|
70
|
+
<sodipodi:guide
|
71
|
+
orientation="0,1"
|
72
|
+
position="431.42857,507.85714"
|
73
|
+
id="guide3009" />
|
74
|
+
<sodipodi:guide
|
75
|
+
orientation="0,1"
|
76
|
+
position="488.40876,783.57143"
|
77
|
+
id="guide3011" />
|
78
|
+
<sodipodi:guide
|
79
|
+
orientation="0,1"
|
80
|
+
position="505,372.85714"
|
81
|
+
id="guide3013" />
|
82
|
+
</sodipodi:namedview>
|
83
|
+
<metadata
|
84
|
+
id="metadata7">
|
85
|
+
<rdf:RDF>
|
86
|
+
<cc:Work
|
87
|
+
rdf:about="">
|
88
|
+
<dc:format>image/svg+xml</dc:format>
|
89
|
+
<dc:type
|
90
|
+
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
91
|
+
<dc:title></dc:title>
|
92
|
+
</cc:Work>
|
93
|
+
</rdf:RDF>
|
94
|
+
</metadata>
|
95
|
+
<g
|
96
|
+
inkscape:label="Layer 1"
|
97
|
+
inkscape:groupmode="layer"
|
98
|
+
id="layer1">
|
99
|
+
<path
|
100
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
101
|
+
d="m 176.28125,201.03125 0,0.625 0,395.125 0,0.375 0.34375,0.0937 312.34375,91.6875 0.625,0.1875 0,-0.65625 0.125,-419.09375 0,-0.40625 -0.40625,-0.0937 -312.4375,-67.71875 -0.59375,-0.125 z m 1,1.21875 311.4375,67.5 -0.125,418.0625 -311.3125,-91.375 0,-394.1875 z"
|
102
|
+
id="path2985"
|
103
|
+
inkscape:connector-curvature="0" />
|
104
|
+
<path
|
105
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
106
|
+
d="m 647.21875,206.59375 -0.6875,0.28125 -157.59375,62.21875 -0.3125,0.125 0,0.34375 0.1875,419.125 0,0.75 0.6875,-0.28125 156.0625,-63.1875 0.3125,-0.125 0,-0.34375 1.34375,-418.15625 0,-0.75 z m -1,1.4375 -1.34375,417.125 -155.0625,62.78125 -0.1875,-418.03125 156.59375,-61.875 z"
|
107
|
+
id="path2993"
|
108
|
+
inkscape:connector-curvature="0" />
|
109
|
+
<path
|
110
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
111
|
+
d="m 355.6875,137.40625 -0.15625,0.0625 L 176.96875,201.0625 177.3125,202 355.75,138.4375 646.78125,207.53125 647,206.5625 l -291.15625,-69.125 -0.15625,-0.0312 z"
|
112
|
+
id="path3003"
|
113
|
+
inkscape:connector-curvature="0" />
|
114
|
+
<path
|
115
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
116
|
+
d="m 355.71875,277.53125 -0.125,0.0312 -178.9375,47.96875 -1.8125,0.46875 1.8125,0.5 311.625,83.5 0.15625,0.0312 0.125,-0.0625 157.59375,-53.65625 1.5625,-0.53125 -1.59375,-0.4375 -290.28125,-77.78125 -0.125,-0.0312 z m 0,1.03125 L 644.3125,355.90625 488.375,409 178.71875,326 l 177,-47.4375 z"
|
117
|
+
id="path3015"
|
118
|
+
inkscape:connector-curvature="0" />
|
119
|
+
<path
|
120
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
121
|
+
d="m 355.21875,240.9375 0,37.125 1,0 0,-37.125 -1,0 z"
|
122
|
+
id="path3017"
|
123
|
+
inkscape:connector-curvature="0" />
|
124
|
+
<path
|
125
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
126
|
+
d="m 176.28125,202.65625 0,393.28125 1,0 0,-393.28125 -1,0 z"
|
127
|
+
id="path3019"
|
128
|
+
inkscape:connector-curvature="0" />
|
129
|
+
<path
|
130
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
131
|
+
d="m 355.71875,409 -0.125,0.0312 L 177,455.8125 l -1.78125,0.46875 1.78125,0.5 L 488.28125,545 l 0.15625,0.0312 0.125,-0.0625 156.71875,-56.25 1.46875,-0.53125 -1.53125,-0.40625 -289.375,-78.75 -0.125,-0.0312 z m 0,1.03125 287.6875,78.28125 L 488.375,544 179.03125,456.3125 355.71875,410.03125 z"
|
132
|
+
id="path3021"
|
133
|
+
inkscape:connector-curvature="0" />
|
134
|
+
<path
|
135
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
136
|
+
d="m 355.71875,544 -0.15625,0.0312 -178.5625,52.3125 0.28125,0.96875 178.4375,-52.28125 289.59375,80.25 0.28125,-0.96875 -289.75,-80.28125 -0.125,-0.0312 z"
|
137
|
+
id="path3023"
|
138
|
+
inkscape:connector-curvature="0" />
|
139
|
+
<path
|
140
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
141
|
+
d="m 355.21875,374.34375 0,35.15625 1,0 0,-35.15625 -1,0 z"
|
142
|
+
id="path3025"
|
143
|
+
inkscape:connector-curvature="0" />
|
144
|
+
<path
|
145
|
+
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:10;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans;stroke-opacity:1;stroke-miterlimit:30;stroke-dasharray:none;stroke-linecap:round;stroke-linejoin:round"
|
146
|
+
d="m 355.1875,507.03125 0,37.4375 1.03125,0 0,-37.4375 -1.03125,0 z"
|
147
|
+
id="path3027"
|
148
|
+
inkscape:connector-curvature="0" />
|
149
|
+
</g>
|
150
|
+
</svg>
|
data/lib/rack/auth/basic.rb
CHANGED
@@ -8,7 +8,21 @@
|
|
8
8
|
|
9
9
|
module URI
|
10
10
|
TBLENCWWWCOMP_ = {} # :nodoc:
|
11
|
+
256.times do |i|
|
12
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
13
|
+
end
|
14
|
+
TBLENCWWWCOMP_[' '] = '+'
|
15
|
+
TBLENCWWWCOMP_.freeze
|
11
16
|
TBLDECWWWCOMP_ = {} # :nodoc:
|
17
|
+
256.times do |i|
|
18
|
+
h, l = i>>4, i&15
|
19
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
20
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
21
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
22
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
23
|
+
end
|
24
|
+
TBLDECWWWCOMP_['+'] = ' '
|
25
|
+
TBLDECWWWCOMP_.freeze
|
12
26
|
|
13
27
|
# Encode given +s+ to URL-encoded form data.
|
14
28
|
#
|
@@ -26,18 +40,6 @@ module URI
|
|
26
40
|
'%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
|
27
41
|
end.tr(' ', '+')
|
28
42
|
else
|
29
|
-
if TBLENCWWWCOMP_.empty?
|
30
|
-
tbl = {}
|
31
|
-
256.times do |i|
|
32
|
-
tbl[i.chr] = '%%%02X' % i
|
33
|
-
end
|
34
|
-
tbl[' '] = '+'
|
35
|
-
begin
|
36
|
-
TBLENCWWWCOMP_.replace(tbl)
|
37
|
-
TBLENCWWWCOMP_.freeze
|
38
|
-
rescue
|
39
|
-
end
|
40
|
-
end
|
41
43
|
str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
|
42
44
|
end
|
43
45
|
end
|
@@ -48,22 +50,6 @@ module URI
|
|
48
50
|
#
|
49
51
|
# See URI.encode_www_form_component, URI.decode_www_form
|
50
52
|
def self.decode_www_form_component(str, enc=nil)
|
51
|
-
if TBLDECWWWCOMP_.empty?
|
52
|
-
tbl = {}
|
53
|
-
256.times do |i|
|
54
|
-
h, l = i>>4, i&15
|
55
|
-
tbl['%%%X%X' % [h, l]] = i.chr
|
56
|
-
tbl['%%%x%X' % [h, l]] = i.chr
|
57
|
-
tbl['%%%X%x' % [h, l]] = i.chr
|
58
|
-
tbl['%%%x%x' % [h, l]] = i.chr
|
59
|
-
end
|
60
|
-
tbl['+'] = ' '
|
61
|
-
begin
|
62
|
-
TBLDECWWWCOMP_.replace(tbl)
|
63
|
-
TBLDECWWWCOMP_.freeze
|
64
|
-
rescue
|
65
|
-
end
|
66
|
-
end
|
67
53
|
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%[0-9a-fA-F]{2}|[^%])*\z/ =~ str
|
68
54
|
str.gsub(/\+|%[0-9a-fA-F]{2}/) {|m| TBLDECWWWCOMP_[m]}
|
69
55
|
end
|
@@ -17,6 +17,19 @@
|
|
17
17
|
require 'uri/common'
|
18
18
|
|
19
19
|
module URI
|
20
|
+
TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
|
21
|
+
if TBLDECWWWCOMP_.empty?
|
22
|
+
256.times do |i|
|
23
|
+
h, l = i>>4, i&15
|
24
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
25
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
26
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
27
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
28
|
+
end
|
29
|
+
TBLDECWWWCOMP_['+'] = ' '
|
30
|
+
TBLDECWWWCOMP_.freeze
|
31
|
+
end
|
32
|
+
|
20
33
|
def self.decode_www_form(str, enc=Encoding::UTF_8)
|
21
34
|
return [] if str.empty?
|
22
35
|
unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
|
@@ -30,26 +43,10 @@ module URI
|
|
30
43
|
end
|
31
44
|
|
32
45
|
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
|
33
|
-
if TBLDECWWWCOMP_.empty?
|
34
|
-
tbl = {}
|
35
|
-
256.times do |i|
|
36
|
-
h, l = i>>4, i&15
|
37
|
-
tbl['%%%X%X' % [h, l]] = i.chr
|
38
|
-
tbl['%%%x%X' % [h, l]] = i.chr
|
39
|
-
tbl['%%%X%x' % [h, l]] = i.chr
|
40
|
-
tbl['%%%x%x' % [h, l]] = i.chr
|
41
|
-
end
|
42
|
-
tbl['+'] = ' '
|
43
|
-
begin
|
44
|
-
TBLDECWWWCOMP_.replace(tbl)
|
45
|
-
TBLDECWWWCOMP_.freeze
|
46
|
-
rescue
|
47
|
-
end
|
48
|
-
end
|
49
46
|
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
|
50
47
|
str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
|
51
48
|
end
|
52
49
|
|
53
|
-
remove_const :WFKV_
|
50
|
+
remove_const :WFKV_ if const_defined?(:WFKV_)
|
54
51
|
WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
|
55
52
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
|
3
|
+
require 'uri/common'
|
4
|
+
|
5
|
+
# Issue:
|
6
|
+
# http://bugs.ruby-lang.org/issues/5925
|
7
|
+
#
|
8
|
+
# Relevant commit:
|
9
|
+
# https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
|
10
|
+
|
11
|
+
module URI
|
12
|
+
256.times do |i|
|
13
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
14
|
+
end
|
15
|
+
TBLENCWWWCOMP_[' '] = '+'
|
16
|
+
TBLENCWWWCOMP_.freeze
|
17
|
+
|
18
|
+
256.times do |i|
|
19
|
+
h, l = i>>4, i&15
|
20
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
21
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
22
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
23
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
24
|
+
end
|
25
|
+
TBLDECWWWCOMP_['+'] = ' '
|
26
|
+
TBLDECWWWCOMP_.freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
# :startdoc:
|
data/lib/rack/body_proxy.rb
CHANGED
@@ -5,6 +5,7 @@ module Rack
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def respond_to?(*args)
|
8
|
+
return false if args.first.to_s =~ /^to_ary$/
|
8
9
|
super or @body.respond_to?(*args)
|
9
10
|
end
|
10
11
|
|
@@ -19,7 +20,16 @@ module Rack
|
|
19
20
|
@closed
|
20
21
|
end
|
21
22
|
|
23
|
+
# N.B. This method is a special case to address the bug described by #434.
|
24
|
+
# We are applying this special case for #each only. Future bugs of this
|
25
|
+
# class will be handled by requesting users to patch their ruby
|
26
|
+
# implementation, to save adding too many methods in this class.
|
27
|
+
def each(*args, &block)
|
28
|
+
@body.each(*args, &block)
|
29
|
+
end
|
30
|
+
|
22
31
|
def method_missing(*args, &block)
|
32
|
+
super if args.first.to_s =~ /^to_ary$/
|
23
33
|
@body.__send__(*args, &block)
|
24
34
|
end
|
25
35
|
end
|
data/lib/rack/builder.rb
CHANGED
@@ -38,7 +38,7 @@ module Rack
|
|
38
38
|
end
|
39
39
|
cfgfile.sub!(/^__END__\n.*/, '')
|
40
40
|
app = eval "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
|
41
|
-
TOPLEVEL_BINDING, config
|
41
|
+
TOPLEVEL_BINDING, config, 0
|
42
42
|
else
|
43
43
|
require config
|
44
44
|
app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
data/lib/rack/cascade.rb
CHANGED
@@ -19,8 +19,19 @@ module Rack
|
|
19
19
|
def call(env)
|
20
20
|
result = NotFound
|
21
21
|
|
22
|
+
last_body = nil
|
23
|
+
|
22
24
|
@apps.each do |app|
|
25
|
+
# The SPEC says that the body must be closed after it has been iterated
|
26
|
+
# by the server, or if it is replaced by a middleware action. Cascade
|
27
|
+
# replaces the body each time a cascade happens. It is assumed that nil
|
28
|
+
# does not respond to close, otherwise the previous application body
|
29
|
+
# will be closed. The final application body will not be closed, as it
|
30
|
+
# will be passed to the server as a result.
|
31
|
+
last_body.close if last_body.respond_to? :close
|
32
|
+
|
23
33
|
result = app.call(env)
|
34
|
+
last_body = result[2]
|
24
35
|
break unless @catch.include?(result[0].to_i)
|
25
36
|
end
|
26
37
|
|
data/lib/rack/deflater.rb
CHANGED
@@ -45,6 +45,7 @@ module Rack
|
|
45
45
|
when "identity"
|
46
46
|
[status, headers, body]
|
47
47
|
when nil
|
48
|
+
body.close if body.respond_to?(:close)
|
48
49
|
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
49
50
|
[406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]]
|
50
51
|
end
|
@@ -64,6 +65,7 @@ module Rack
|
|
64
65
|
gzip.write(part)
|
65
66
|
gzip.flush
|
66
67
|
}
|
68
|
+
ensure
|
67
69
|
@body.close if @body.respond_to?(:close)
|
68
70
|
gzip.close
|
69
71
|
@writer = nil
|
@@ -90,9 +92,11 @@ module Rack
|
|
90
92
|
def each
|
91
93
|
deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS)
|
92
94
|
@body.each { |part| yield deflater.deflate(part, Zlib::SYNC_FLUSH) }
|
93
|
-
@body.close if @body.respond_to?(:close)
|
94
95
|
yield deflater.finish
|
95
96
|
nil
|
97
|
+
ensure
|
98
|
+
@body.close if @body.respond_to?(:close)
|
99
|
+
deflater.close
|
96
100
|
end
|
97
101
|
end
|
98
102
|
end
|
data/lib/rack/head.rb
CHANGED
data/lib/rack/lint.rb
CHANGED
@@ -528,7 +528,9 @@ module Rack
|
|
528
528
|
## The Body itself should not be an instance of String, as this will
|
529
529
|
## break in Ruby 1.9.
|
530
530
|
##
|
531
|
-
## If the Body responds to +close+, it will be called after iteration.
|
531
|
+
## If the Body responds to +close+, it will be called after iteration. If
|
532
|
+
## the body is replaced by a middleware after action, the original body
|
533
|
+
## must be closed first, if it repsonds to close.
|
532
534
|
# XXX howto: assert("Body has not been closed") { @closed }
|
533
535
|
|
534
536
|
|
data/lib/rack/multipart.rb
CHANGED
@@ -12,7 +12,7 @@ module Rack
|
|
12
12
|
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
|
13
13
|
TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
|
14
14
|
CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
|
15
|
-
DISPPARM = /;\s*(#{TOKEN})=("(?:\\"|[^"])*"|#{TOKEN})
|
15
|
+
DISPPARM = /;\s*(#{TOKEN})=("(?:\\"|[^"])*"|#{TOKEN})/
|
16
16
|
RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i
|
17
17
|
BROKEN_QUOTED = /^#{CONDISP}.*;\sfilename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i
|
18
18
|
BROKEN_UNQUOTED = /^#{CONDISP}.*;\sfilename=(#{TOKEN})/i
|
@@ -31,4 +31,4 @@ module Rack
|
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
data/lib/rack/reloader.rb
CHANGED
data/lib/rack/response.rb
CHANGED
@@ -74,9 +74,10 @@ module Rack
|
|
74
74
|
if [204, 304].include?(status.to_i)
|
75
75
|
header.delete "Content-Type"
|
76
76
|
header.delete "Content-Length"
|
77
|
+
close
|
77
78
|
[status.to_i, header, []]
|
78
79
|
else
|
79
|
-
[status.to_i, header, self]
|
80
|
+
[status.to_i, header, BodyProxy.new(self){}]
|
80
81
|
end
|
81
82
|
end
|
82
83
|
alias to_a finish # For *response
|
data/lib/rack/server.rb
CHANGED
@@ -26,7 +26,7 @@ module Rack
|
|
26
26
|
|
27
27
|
opts.on("-I", "--include PATH",
|
28
28
|
"specify $LOAD_PATH (may be used more than once)") { |path|
|
29
|
-
options[:include]
|
29
|
+
(options[:include] ||= []).concat(path.split(":"))
|
30
30
|
}
|
31
31
|
|
32
32
|
opts.on("-r", "--require LIBRARY",
|
@@ -247,11 +247,14 @@ module Rack
|
|
247
247
|
pp app
|
248
248
|
end
|
249
249
|
|
250
|
+
check_pid! if options[:pid]
|
251
|
+
|
250
252
|
# Touch the wrapped app, so that the config.ru is loaded before
|
251
253
|
# daemonization (i.e. before chdir, etc).
|
252
254
|
wrapped_app
|
253
255
|
|
254
256
|
daemonize_app if options[:daemonize]
|
257
|
+
|
255
258
|
write_pid if options[:pid]
|
256
259
|
|
257
260
|
trap(:INT) do
|
@@ -274,7 +277,7 @@ module Rack
|
|
274
277
|
options = default_options
|
275
278
|
|
276
279
|
# Don't evaluate CGI ISINDEX parameters.
|
277
|
-
# http://
|
280
|
+
# http://www.meb.uni-bonn.de/docs/cgi/cl.html
|
278
281
|
args.clear if ENV.include?("REQUEST_METHOD")
|
279
282
|
|
280
283
|
options.merge! opt_parser.parse!(args)
|
@@ -319,5 +322,28 @@ module Rack
|
|
319
322
|
::File.open(options[:pid], 'w'){ |f| f.write("#{Process.pid}") }
|
320
323
|
at_exit { ::File.delete(options[:pid]) if ::File.exist?(options[:pid]) }
|
321
324
|
end
|
325
|
+
|
326
|
+
def check_pid!
|
327
|
+
case pidfile_process_status
|
328
|
+
when :running, :not_owned
|
329
|
+
$stderr.puts "A server is already running. Check #{options[:pid]}."
|
330
|
+
exit(1)
|
331
|
+
when :dead
|
332
|
+
::File.delete(options[:pid])
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def pidfile_process_status
|
337
|
+
return :exited unless ::File.exist?(options[:pid])
|
338
|
+
|
339
|
+
pid = ::File.read(options[:pid]).to_i
|
340
|
+
Process.kill(0, pid)
|
341
|
+
:running
|
342
|
+
rescue Errno::ESRCH
|
343
|
+
:dead
|
344
|
+
rescue Errno::EPERM
|
345
|
+
:not_owned
|
346
|
+
end
|
347
|
+
|
322
348
|
end
|
323
349
|
end
|
data/lib/rack/session/cookie.rb
CHANGED
@@ -80,6 +80,15 @@ module Rack
|
|
80
80
|
|
81
81
|
def initialize(app, options={})
|
82
82
|
@secret = options[:secret]
|
83
|
+
warn <<-MSG unless @secret
|
84
|
+
SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
|
85
|
+
This poses a security threat. It is strongly recommended that you
|
86
|
+
provide a secret to prevent exploits that may be possible from crafted
|
87
|
+
cookies. This will not be supported in future versions of Rack, and
|
88
|
+
future versions will even invalidate your existing user cookies.
|
89
|
+
|
90
|
+
Called from: #{caller[0]}.
|
91
|
+
MSG
|
83
92
|
@coder = options[:coder] ||= Base64::Marshal.new
|
84
93
|
super(app, options.merge!(:cookie_only => true))
|
85
94
|
end
|
data/lib/rack/utils.rb
CHANGED
@@ -5,11 +5,14 @@ require 'tempfile'
|
|
5
5
|
require 'rack/multipart'
|
6
6
|
|
7
7
|
major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
|
8
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
8
9
|
|
9
10
|
if major == 1 && minor < 9
|
10
11
|
require 'rack/backports/uri/common_18'
|
11
|
-
elsif major == 1 && minor == 9 && patch
|
12
|
+
elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL <= 320 && RUBY_ENGINE != 'jruby'
|
12
13
|
require 'rack/backports/uri/common_192'
|
14
|
+
elsif major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
|
15
|
+
require 'rack/backports/uri/common_193'
|
13
16
|
else
|
14
17
|
require 'uri/common'
|
15
18
|
end
|
@@ -60,6 +63,7 @@ module Rack
|
|
60
63
|
bytes = 0
|
61
64
|
|
62
65
|
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
|
66
|
+
next if p.empty?
|
63
67
|
k, v = p.split('=', 2).map { |x| unescape(x) }
|
64
68
|
|
65
69
|
if k
|
@@ -315,16 +319,16 @@ module Rack
|
|
315
319
|
def byte_ranges(env, size)
|
316
320
|
# See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
|
317
321
|
http_range = env['HTTP_RANGE']
|
318
|
-
return nil unless http_range
|
322
|
+
return nil unless http_range && http_range =~ /bytes=([^;]+)/
|
319
323
|
ranges = []
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
r0,r1 = matches[1], matches[2]
|
324
|
+
$1.split(/,\s*/).each do |range_spec|
|
325
|
+
return nil unless range_spec =~ /(\d*)-(\d*)/
|
326
|
+
r0,r1 = $1, $2
|
324
327
|
if r0.empty?
|
325
328
|
return nil if r1.empty?
|
326
329
|
# suffix-byte-range-spec, represents trailing suffix of file
|
327
|
-
r0 =
|
330
|
+
r0 = size - r1.to_i
|
331
|
+
r0 = 0 if r0 < 0
|
328
332
|
r1 = size - 1
|
329
333
|
else
|
330
334
|
r0 = r0.to_i
|
data/rack.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rack"
|
3
|
-
s.version = "1.3.
|
3
|
+
s.version = "1.3.7"
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.summary = "a modular Ruby webserver interface"
|
6
6
|
|
@@ -11,7 +11,7 @@ the simplest way possible, it unifies and distills the API for web
|
|
11
11
|
servers, web frameworks, and software in between (the so-called
|
12
12
|
middleware) into a single method call.
|
13
13
|
|
14
|
-
Also see http://rack.
|
14
|
+
Also see http://rack.github.com/.
|
15
15
|
EOF
|
16
16
|
|
17
17
|
s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*,test/**/*}'] +
|
@@ -24,7 +24,7 @@ EOF
|
|
24
24
|
|
25
25
|
s.author = 'Christian Neukirchen'
|
26
26
|
s.email = 'chneukirchen@gmail.com'
|
27
|
-
s.homepage = 'http://rack.
|
27
|
+
s.homepage = 'http://rack.github.com/'
|
28
28
|
s.rubyforge_project = 'rack'
|
29
29
|
|
30
30
|
s.add_development_dependency 'bacon'
|
@@ -0,0 +1 @@
|
|
1
|
+
run lambda{ |env| [200, {'Content-Type' => 'text/plain'}, [__LINE__.to_s]] }
|
data/test/spec_auth_basic.rb
CHANGED
@@ -63,6 +63,14 @@ describe Rack::Auth::Basic do
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
should 'return 400 Bad Request for a malformed authorization header' do
|
67
|
+
request 'HTTP_AUTHORIZATION' => '' do |response|
|
68
|
+
response.should.be.a.client_error
|
69
|
+
response.status.should.equal 400
|
70
|
+
response.should.not.include 'WWW-Authenticate'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
66
74
|
it 'takes realm as optional constructor arg' do
|
67
75
|
app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
|
68
76
|
realm.should == app.realm
|
data/test/spec_auth_digest.rb
CHANGED
@@ -152,6 +152,20 @@ describe Rack::Auth::Digest::MD5 do
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
155
|
+
should 'not rechallenge if nonce is not stale' do
|
156
|
+
begin
|
157
|
+
Rack::Auth::Digest::Nonce.time_limit = 10
|
158
|
+
|
159
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 1 do |response|
|
160
|
+
response.status.should.equal 200
|
161
|
+
response.body.to_s.should.equal 'Hi Alice'
|
162
|
+
response.headers['WWW-Authenticate'].should.not =~ /\bstale=true\b/
|
163
|
+
end
|
164
|
+
ensure
|
165
|
+
Rack::Auth::Digest::Nonce.time_limit = nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
155
169
|
should 'rechallenge with stale parameter if nonce is stale' do
|
156
170
|
begin
|
157
171
|
Rack::Auth::Digest::Nonce.time_limit = 1
|
data/test/spec_body_proxy.rb
CHANGED
data/test/spec_builder.rb
CHANGED
@@ -148,5 +148,11 @@ describe Rack::Builder do
|
|
148
148
|
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'OK'
|
149
149
|
$:.pop
|
150
150
|
end
|
151
|
+
|
152
|
+
it "sets __LINE__ correctly" do
|
153
|
+
app, options = Rack::Builder.parse_file config_file('line.ru')
|
154
|
+
options = nil # ignored, prevents warning
|
155
|
+
Rack::MockRequest.new(app).get("/").body.to_s.should.equal '1'
|
156
|
+
end
|
151
157
|
end
|
152
158
|
end
|
data/test/spec_cascade.rb
CHANGED
@@ -42,4 +42,12 @@ describe Rack::Cascade do
|
|
42
42
|
cascade << app3
|
43
43
|
Rack::MockRequest.new(cascade).get('/foo').should.be.ok
|
44
44
|
end
|
45
|
+
|
46
|
+
should "close the body on cascade" do
|
47
|
+
body = StringIO.new
|
48
|
+
closer = lambda { |env| [404, {}, body] }
|
49
|
+
cascade = Rack::Cascade.new([closer, app3], [404])
|
50
|
+
Rack::MockRequest.new(cascade).get("/foo").should.be.ok
|
51
|
+
body.should.be.closed
|
52
|
+
end
|
45
53
|
end
|
data/test/spec_head.rb
CHANGED
@@ -2,29 +2,41 @@ require 'rack/head'
|
|
2
2
|
require 'rack/mock'
|
3
3
|
|
4
4
|
describe Rack::Head do
|
5
|
+
|
5
6
|
def test_response(headers = {})
|
6
|
-
|
7
|
+
body = StringIO.new "foo"
|
8
|
+
app = lambda do |env|
|
9
|
+
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, body]
|
10
|
+
end
|
7
11
|
request = Rack::MockRequest.env_for("/", headers)
|
8
12
|
response = Rack::Head.new(app).call(request)
|
9
13
|
|
10
|
-
return response
|
14
|
+
return response, body
|
11
15
|
end
|
12
16
|
|
13
17
|
should "pass GET, POST, PUT, DELETE, OPTIONS, TRACE requests" do
|
14
18
|
%w[GET POST PUT DELETE OPTIONS TRACE].each do |type|
|
15
|
-
resp = test_response("REQUEST_METHOD" => type)
|
19
|
+
resp, _ = test_response("REQUEST_METHOD" => type)
|
16
20
|
|
17
21
|
resp[0].should.equal(200)
|
18
22
|
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
19
|
-
resp[2].should.equal(
|
23
|
+
resp[2].each { |b| b.should.equal("foo") }
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
23
27
|
should "remove body from HEAD requests" do
|
24
|
-
resp = test_response("REQUEST_METHOD" => "HEAD")
|
28
|
+
resp, _ = test_response("REQUEST_METHOD" => "HEAD")
|
29
|
+
|
30
|
+
resp[0].should.equal(200)
|
31
|
+
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
32
|
+
resp[2].each { |b| flunk "body should be empty" }
|
33
|
+
end
|
25
34
|
|
35
|
+
should "close the body when it is removed" do
|
36
|
+
resp, body = test_response("REQUEST_METHOD" => "HEAD")
|
26
37
|
resp[0].should.equal(200)
|
27
38
|
resp[1].should.equal({"Content-type" => "test/plain", "Content-length" => "3"})
|
28
|
-
resp[2].should
|
39
|
+
resp[2].each { |b| flunk "body should be empty" }
|
40
|
+
body.should.be.closed
|
29
41
|
end
|
30
42
|
end
|
data/test/spec_multipart.rb
CHANGED
@@ -295,4 +295,24 @@ describe Rack::Multipart do
|
|
295
295
|
message.should.equal "value must be a Hash"
|
296
296
|
end
|
297
297
|
|
298
|
+
should "parse very long unquoted multipart file names" do
|
299
|
+
data = <<-EOF
|
300
|
+
--AaB03x\r
|
301
|
+
Content-Type: text/plain\r
|
302
|
+
Content-Disposition: attachment; name=file; filename=#{'long' * 100}\r
|
303
|
+
\r
|
304
|
+
contents\r
|
305
|
+
--AaB03x--\r
|
306
|
+
EOF
|
307
|
+
|
308
|
+
options = {
|
309
|
+
"CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
|
310
|
+
"CONTENT_LENGTH" => data.length.to_s,
|
311
|
+
:input => StringIO.new(data)
|
312
|
+
}
|
313
|
+
env = Rack::MockRequest.env_for("/", options)
|
314
|
+
params = Rack::Utils::Multipart.parse_multipart(env)
|
315
|
+
|
316
|
+
params["file"][:filename].should.equal('long' * 100)
|
317
|
+
end
|
298
318
|
end
|
data/test/spec_response.rb
CHANGED
@@ -250,4 +250,34 @@ describe Rack::Response do
|
|
250
250
|
res.close
|
251
251
|
res.body.should.be.closed
|
252
252
|
end
|
253
|
+
|
254
|
+
it "calls close on #body when 204, 205, or 304" do
|
255
|
+
res = Rack::Response.new
|
256
|
+
res.body = StringIO.new
|
257
|
+
res.finish
|
258
|
+
res.body.should.not.be.closed
|
259
|
+
|
260
|
+
res.status = 204
|
261
|
+
_, _, b = res.finish
|
262
|
+
res.body.should.be.closed
|
263
|
+
b.should.not == res.body
|
264
|
+
|
265
|
+
res.body = StringIO.new
|
266
|
+
res.status = 205
|
267
|
+
_, _, b = res.finish
|
268
|
+
res.body.should.be.closed
|
269
|
+
b.should.not == res.body
|
270
|
+
|
271
|
+
res.body = StringIO.new
|
272
|
+
res.status = 304
|
273
|
+
_, _, b = res.finish
|
274
|
+
res.body.should.be.closed
|
275
|
+
b.should.not == res.body
|
276
|
+
end
|
277
|
+
|
278
|
+
it "wraps the body from #to_ary to prevent infinite loops" do
|
279
|
+
res = Rack::Response.new
|
280
|
+
res.finish.last.should.not.respond_to?(:to_ary)
|
281
|
+
lambda { res.finish.last.to_ary }.should.raise(NoMethodError)
|
282
|
+
end
|
253
283
|
end
|
data/test/spec_server.rb
CHANGED
@@ -10,6 +10,13 @@ describe Rack::Server do
|
|
10
10
|
lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['success']] }
|
11
11
|
end
|
12
12
|
|
13
|
+
def with_stderr
|
14
|
+
old, $stderr = $stderr, StringIO.new
|
15
|
+
yield $stderr
|
16
|
+
ensure
|
17
|
+
$stderr = old
|
18
|
+
end
|
19
|
+
|
13
20
|
it "overrides :config if :app is passed in" do
|
14
21
|
server = Rack::Server.new(:app => "FOO")
|
15
22
|
server.app.should == "FOO"
|
@@ -71,4 +78,44 @@ describe Rack::Server do
|
|
71
78
|
open(pidfile) { |f| f.read.should.eql $$.to_s }
|
72
79
|
end
|
73
80
|
|
81
|
+
should "check pid file presence and running process" do
|
82
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write($$); break f }.path
|
83
|
+
server = Rack::Server.new(:pid => pidfile)
|
84
|
+
server.send(:pidfile_process_status).should.eql :running
|
85
|
+
end
|
86
|
+
|
87
|
+
should "check pid file presence and dead process" do
|
88
|
+
dead_pid = `echo $$`.to_i
|
89
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(dead_pid); break f }.path
|
90
|
+
server = Rack::Server.new(:pid => pidfile)
|
91
|
+
server.send(:pidfile_process_status).should.eql :dead
|
92
|
+
end
|
93
|
+
|
94
|
+
should "check pid file presence and exited process" do
|
95
|
+
pidfile = Tempfile.open('pidfile') { |f| break f }.path
|
96
|
+
::File.delete(pidfile)
|
97
|
+
server = Rack::Server.new(:pid => pidfile)
|
98
|
+
server.send(:pidfile_process_status).should.eql :exited
|
99
|
+
end
|
100
|
+
|
101
|
+
should "check pid file presence and not owned process" do
|
102
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
103
|
+
server = Rack::Server.new(:pid => pidfile)
|
104
|
+
server.send(:pidfile_process_status).should.eql :not_owned
|
105
|
+
end
|
106
|
+
|
107
|
+
should "inform the user about existing pidfiles with running processes" do
|
108
|
+
pidfile = Tempfile.open('pidfile') { |f| f.write(1); break f }.path
|
109
|
+
server = Rack::Server.new(:pid => pidfile)
|
110
|
+
with_stderr do |err|
|
111
|
+
should.raise(SystemExit) do
|
112
|
+
server.start
|
113
|
+
end
|
114
|
+
err.rewind
|
115
|
+
output = err.read
|
116
|
+
output.should.match(/already running/)
|
117
|
+
output.should.include? pidfile
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
74
121
|
end
|
data/test/spec_session_cookie.rb
CHANGED
@@ -24,6 +24,17 @@ describe Rack::Session::Cookie do
|
|
24
24
|
Rack::Response.new("Nothing").to_a
|
25
25
|
end
|
26
26
|
|
27
|
+
before do
|
28
|
+
@warnings = warnings = []
|
29
|
+
Rack::Session::Cookie.class_eval do
|
30
|
+
define_method(:warn) { |m| warnings << m }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
after do
|
35
|
+
Rack::Session::Cookie.class_eval { remove_method :warn }
|
36
|
+
end
|
37
|
+
|
27
38
|
describe 'Base64' do
|
28
39
|
it 'uses base64 to encode' do
|
29
40
|
coder = Rack::Session::Cookie::Base64.new
|
@@ -57,6 +68,14 @@ describe Rack::Session::Cookie do
|
|
57
68
|
end
|
58
69
|
end
|
59
70
|
|
71
|
+
it "warns if no secret is given" do
|
72
|
+
cookie = Rack::Session::Cookie.new(incrementor)
|
73
|
+
@warnings.first.should =~ /no secret/i
|
74
|
+
@warnings.clear
|
75
|
+
cookie = Rack::Session::Cookie.new(incrementor, :secret => 'abc')
|
76
|
+
@warnings.should.be.empty?
|
77
|
+
end
|
78
|
+
|
60
79
|
it 'uses a coder' do
|
61
80
|
identity = Class.new {
|
62
81
|
attr_reader :calls
|
data/test/spec_session_pool.rb
CHANGED
@@ -181,19 +181,19 @@ describe Rack::Session::Pool do
|
|
181
181
|
end
|
182
182
|
|
183
183
|
it "does not return a cookie if cookie was not read/written" do
|
184
|
-
app = Rack::Session::Cookie.new(nothing)
|
184
|
+
app = Rack::Session::Cookie.new(nothing, :secret => 'abc')
|
185
185
|
res = Rack::MockRequest.new(app).get("/")
|
186
186
|
res["Set-Cookie"].should.be.nil
|
187
187
|
end
|
188
188
|
|
189
189
|
it "does not return a cookie if cookie was not written (only read)" do
|
190
|
-
app = Rack::Session::Cookie.new(session_id)
|
190
|
+
app = Rack::Session::Cookie.new(session_id, :secret => 'abc')
|
191
191
|
res = Rack::MockRequest.new(app).get("/")
|
192
192
|
res["Set-Cookie"].should.be.nil
|
193
193
|
end
|
194
194
|
|
195
195
|
it "returns even if not read/written if :expire_after is set" do
|
196
|
-
app = Rack::Session::Cookie.new(nothing, :expire_after => 3600)
|
196
|
+
app = Rack::Session::Cookie.new(nothing, :expire_after => 3600, :secret => 'abc')
|
197
197
|
res = Rack::MockRequest.new(app).get("/")
|
198
198
|
res["Set-Cookie"].should.not.be.nil
|
199
199
|
end
|
data/test/spec_utils.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require 'rack/utils'
|
3
3
|
require 'rack/mock'
|
4
|
+
require 'timeout'
|
4
5
|
|
5
6
|
describe Rack::Utils do
|
6
7
|
def kcodeu
|
@@ -93,6 +94,14 @@ describe Rack::Utils do
|
|
93
94
|
Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
|
94
95
|
should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
|
95
96
|
Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
|
97
|
+
Rack::Utils.parse_query("=").should.equal "" => ""
|
98
|
+
Rack::Utils.parse_query("=value").should.equal "" => "value"
|
99
|
+
Rack::Utils.parse_query("key=").should.equal "key" => ""
|
100
|
+
Rack::Utils.parse_query("&key&").should.equal "key" => nil
|
101
|
+
Rack::Utils.parse_query(";key;", ";,").should.equal "key" => nil
|
102
|
+
Rack::Utils.parse_query(",key,", ";,").should.equal "key" => nil
|
103
|
+
Rack::Utils.parse_query(";foo=bar,;", ";,").should.equal "foo" => "bar"
|
104
|
+
Rack::Utils.parse_query(",foo=bar;,", ";,").should.equal "foo" => "bar"
|
96
105
|
end
|
97
106
|
|
98
107
|
should "parse nested query strings correctly" do
|
@@ -326,6 +335,10 @@ describe Rack::Utils, "byte_range" do
|
|
326
335
|
Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)]
|
327
336
|
end
|
328
337
|
|
338
|
+
should "parse several byte ranges" do
|
339
|
+
Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).should.equal [(500..600),(601..999)]
|
340
|
+
end
|
341
|
+
|
329
342
|
should "truncate byte ranges" do
|
330
343
|
Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)]
|
331
344
|
Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal []
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 1.3.
|
9
|
+
- 7
|
10
|
+
version: 1.3.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Christian Neukirchen
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2013-01-07 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bacon
|
@@ -81,7 +81,7 @@ dependencies:
|
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
hash:
|
84
|
+
hash: 1777625759
|
85
85
|
segments:
|
86
86
|
- 1
|
87
87
|
- 2
|
@@ -112,7 +112,7 @@ description: |
|
|
112
112
|
servers, web frameworks, and software in between (the so-called
|
113
113
|
middleware) into a single method call.
|
114
114
|
|
115
|
-
Also see http://rack.
|
115
|
+
Also see http://rack.github.com/.
|
116
116
|
|
117
117
|
email: chneukirchen@gmail.com
|
118
118
|
executables:
|
@@ -124,6 +124,8 @@ extra_rdoc_files:
|
|
124
124
|
- KNOWN-ISSUES
|
125
125
|
files:
|
126
126
|
- bin/rackup
|
127
|
+
- contrib/rack.png
|
128
|
+
- contrib/rack.svg
|
127
129
|
- contrib/rack_logo.svg
|
128
130
|
- example/lobster.ru
|
129
131
|
- example/protectedlobster.rb
|
@@ -137,6 +139,7 @@ files:
|
|
137
139
|
- lib/rack/auth/digest/request.rb
|
138
140
|
- lib/rack/backports/uri/common_18.rb
|
139
141
|
- lib/rack/backports/uri/common_192.rb
|
142
|
+
- lib/rack/backports/uri/common_193.rb
|
140
143
|
- lib/rack/body_proxy.rb
|
141
144
|
- lib/rack/builder.rb
|
142
145
|
- lib/rack/cascade.rb
|
@@ -194,6 +197,7 @@ files:
|
|
194
197
|
- test/builder/anything.rb
|
195
198
|
- test/builder/comment.ru
|
196
199
|
- test/builder/end.ru
|
200
|
+
- test/builder/line.ru
|
197
201
|
- test/builder/options.ru
|
198
202
|
- test/cgi/lighttpd.conf
|
199
203
|
- test/cgi/rackup_stub.rb
|
@@ -277,7 +281,7 @@ files:
|
|
277
281
|
- Rakefile
|
278
282
|
- README.rdoc
|
279
283
|
- SPEC
|
280
|
-
homepage: http://rack.
|
284
|
+
homepage: http://rack.github.com/
|
281
285
|
licenses: []
|
282
286
|
|
283
287
|
post_install_message:
|
@@ -306,7 +310,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
306
310
|
requirements: []
|
307
311
|
|
308
312
|
rubyforge_project: rack
|
309
|
-
rubygems_version: 1.8.
|
313
|
+
rubygems_version: 1.8.24
|
310
314
|
signing_key:
|
311
315
|
specification_version: 3
|
312
316
|
summary: a modular Ruby webserver interface
|
@@ -357,3 +361,4 @@ test_files:
|
|
357
361
|
- test/spec_urlmap.rb
|
358
362
|
- test/spec_utils.rb
|
359
363
|
- test/spec_webrick.rb
|
364
|
+
has_rdoc:
|