rack 1.4.7 → 2.1.4

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.
Files changed (183) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +77 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +122 -456
  5. data/Rakefile +32 -31
  6. data/SPEC +119 -29
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +7 -5
  13. data/lib/rack/auth/abstract/request.rb +8 -6
  14. data/lib/rack/auth/basic.rb +5 -2
  15. data/lib/rack/auth/digest/md5.rb +10 -8
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +4 -2
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +63 -20
  21. data/lib/rack/cascade.rb +10 -9
  22. data/lib/rack/chunked.rb +45 -11
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +24 -15
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -6
  25. data/lib/rack/config.rb +7 -0
  26. data/lib/rack/content_length.rb +12 -6
  27. data/lib/rack/content_type.rb +4 -2
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +73 -42
  30. data/lib/rack/directory.rb +77 -56
  31. data/lib/rack/etag.rb +25 -13
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -143
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +21 -17
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +27 -21
  39. data/lib/rack/handler/thin.rb +19 -5
  40. data/lib/rack/handler/webrick.rb +66 -24
  41. data/lib/rack/handler.rb +29 -19
  42. data/lib/rack/head.rb +21 -14
  43. data/lib/rack/lint.rb +259 -65
  44. data/lib/rack/lobster.rb +17 -10
  45. data/lib/rack/lock.rb +19 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/method_override.rb +52 -0
  49. data/lib/rack/mime.rb +43 -6
  50. data/lib/rack/mock.rb +109 -44
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +302 -115
  53. data/lib/rack/multipart/uploaded_file.rb +4 -3
  54. data/lib/rack/multipart.rb +40 -9
  55. data/lib/rack/null_logger.rb +39 -0
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +14 -11
  58. data/lib/rack/reloader.rb +12 -5
  59. data/lib/rack/request.rb +484 -270
  60. data/lib/rack/response.rb +196 -77
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +13 -6
  63. data/lib/rack/sendfile.rb +44 -20
  64. data/lib/rack/server.rb +175 -61
  65. data/lib/rack/session/abstract/id.rb +276 -133
  66. data/lib/rack/session/cookie.rb +75 -40
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +24 -18
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +11 -9
  71. data/lib/rack/static.rb +65 -38
  72. data/lib/rack/tempfile_reaper.rb +24 -0
  73. data/lib/rack/urlmap.rb +40 -15
  74. data/lib/rack/utils.rb +316 -285
  75. data/lib/rack.rb +78 -23
  76. data/rack.gemspec +26 -19
  77. metadata +44 -209
  78. data/KNOWN-ISSUES +0 -30
  79. data/lib/rack/backports/uri/common_18.rb +0 -56
  80. data/lib/rack/backports/uri/common_192.rb +0 -52
  81. data/lib/rack/backports/uri/common_193.rb +0 -29
  82. data/lib/rack/handler/evented_mongrel.rb +0 -8
  83. data/lib/rack/handler/mongrel.rb +0 -100
  84. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  85. data/lib/rack/methodoverride.rb +0 -33
  86. data/lib/rack/nulllogger.rb +0 -18
  87. data/lib/rack/showexceptions.rb +0 -378
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/lighttpd.errors +0 -1
  101. data/test/cgi/rackup_stub.rb +0 -6
  102. data/test/cgi/sample_rackup.ru +0 -5
  103. data/test/cgi/test +0 -9
  104. data/test/cgi/test+directory/test+file +0 -1
  105. data/test/cgi/test.fcgi +0 -8
  106. data/test/cgi/test.ru +0 -5
  107. data/test/gemloader.rb +0 -10
  108. data/test/multipart/bad_robots +0 -259
  109. data/test/multipart/binary +0 -0
  110. data/test/multipart/content_type_and_no_filename +0 -6
  111. data/test/multipart/empty +0 -10
  112. data/test/multipart/fail_16384_nofile +0 -814
  113. data/test/multipart/file1.txt +0 -1
  114. data/test/multipart/filename_and_modification_param +0 -7
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  121. data/test/multipart/filename_with_unescaped_quotes +0 -6
  122. data/test/multipart/ie +0 -6
  123. data/test/multipart/mixed_files +0 -21
  124. data/test/multipart/nested +0 -10
  125. data/test/multipart/none +0 -9
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  129. data/test/multipart/webkit +0 -32
  130. data/test/rackup/config.ru +0 -31
  131. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  132. data/test/spec_auth.rb +0 -57
  133. data/test/spec_auth_basic.rb +0 -81
  134. data/test/spec_auth_digest.rb +0 -259
  135. data/test/spec_body_proxy.rb +0 -69
  136. data/test/spec_builder.rb +0 -207
  137. data/test/spec_cascade.rb +0 -61
  138. data/test/spec_cgi.rb +0 -102
  139. data/test/spec_chunked.rb +0 -87
  140. data/test/spec_commonlogger.rb +0 -57
  141. data/test/spec_conditionalget.rb +0 -102
  142. data/test/spec_config.rb +0 -22
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -45
  145. data/test/spec_deflater.rb +0 -187
  146. data/test/spec_directory.rb +0 -88
  147. data/test/spec_etag.rb +0 -98
  148. data/test/spec_fastcgi.rb +0 -107
  149. data/test/spec_file.rb +0 -200
  150. data/test/spec_handler.rb +0 -59
  151. data/test/spec_head.rb +0 -48
  152. data/test/spec_lint.rb +0 -515
  153. data/test/spec_lobster.rb +0 -58
  154. data/test/spec_lock.rb +0 -167
  155. data/test/spec_logger.rb +0 -23
  156. data/test/spec_methodoverride.rb +0 -72
  157. data/test/spec_mock.rb +0 -269
  158. data/test/spec_mongrel.rb +0 -182
  159. data/test/spec_multipart.rb +0 -479
  160. data/test/spec_nulllogger.rb +0 -23
  161. data/test/spec_recursive.rb +0 -72
  162. data/test/spec_request.rb +0 -955
  163. data/test/spec_response.rb +0 -313
  164. data/test/spec_rewindable_input.rb +0 -118
  165. data/test/spec_runtime.rb +0 -49
  166. data/test/spec_sendfile.rb +0 -90
  167. data/test/spec_server.rb +0 -121
  168. data/test/spec_session_abstract_id.rb +0 -43
  169. data/test/spec_session_cookie.rb +0 -361
  170. data/test/spec_session_memcache.rb +0 -321
  171. data/test/spec_session_pool.rb +0 -209
  172. data/test/spec_showexceptions.rb +0 -92
  173. data/test/spec_showstatus.rb +0 -84
  174. data/test/spec_static.rb +0 -145
  175. data/test/spec_thin.rb +0 -86
  176. data/test/spec_urlmap.rb +0 -213
  177. data/test/spec_utils.rb +0 -554
  178. data/test/spec_webrick.rb +0 -143
  179. data/test/static/another/index.html +0 -1
  180. data/test/static/index.html +0 -1
  181. data/test/testrequest.rb +0 -78
  182. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  183. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/Rakefile CHANGED
@@ -1,7 +1,9 @@
1
- # Rakefile for Rack. -*-ruby-*-
1
+ # frozen_string_literal: true
2
+
3
+ require "rake/testtask"
2
4
 
3
5
  desc "Run all the tests"
4
- task :default => [:test]
6
+ task default: :test
5
7
 
6
8
  desc "Install gem dependencies"
7
9
  task :deps do
@@ -16,7 +18,7 @@ task :deps do
16
18
  end
17
19
 
18
20
  desc "Make an archive as .tar.gz"
19
- task :dist => %w[chmod ChangeLog SPEC rdoc] do
21
+ task dist: %w[chmod changelog spec rdoc] do
20
22
  sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
21
23
  sh "pax -waf #{release}.tar -s ':^:#{release}/:' SPEC ChangeLog doc rack.gemspec"
22
24
  sh "gzip -f -9 #{release}.tar"
@@ -31,27 +33,29 @@ task :officialrelease do
31
33
  sh "mv stage/#{release}.tar.gz stage/#{release}.gem ."
32
34
  end
33
35
 
34
- task :officialrelease_really => %w[SPEC dist gem] do
35
- sh "sha1sum #{release}.tar.gz #{release}.gem"
36
+ task officialrelease_really: %w[spec dist gem] do
37
+ sh "shasum #{release}.tar.gz #{release}.gem"
36
38
  end
37
39
 
38
40
  def release
39
- "rack-#{File.read("rack.gemspec")[/s.version *= *"(.*?)"/, 1]}"
41
+ "rack-" + File.read('lib/rack.rb')[/RELEASE += +([\"\'])([\d][\w\.]+)\1/, 2]
40
42
  end
41
43
 
42
44
  desc "Make binaries executable"
43
45
  task :chmod do
44
- Dir["bin/*"].each { |binary| File.chmod(0775, binary) }
45
- Dir["test/cgi/test*"].each { |binary| File.chmod(0775, binary) }
46
+ Dir["bin/*"].each { |binary| File.chmod(0755, binary) }
47
+ Dir["test/cgi/test*"].each { |binary| File.chmod(0755, binary) }
46
48
  end
47
49
 
48
50
  desc "Generate a ChangeLog"
49
- task :changelog => %w[ChangeLog]
51
+ task changelog: "ChangeLog"
50
52
 
51
53
  file '.git/index'
52
54
  file "ChangeLog" => '.git/index' do
53
55
  File.open("ChangeLog", "w") { |out|
54
- `git log -z`.split("\0").map { |chunk|
56
+ log = `git log -z`
57
+ log.force_encoding(Encoding::BINARY)
58
+ log.split("\0").map { |chunk|
55
59
  author = chunk[/Author: (.*)/, 1].strip
56
60
  date = chunk[/Date: (.*)/, 1].strip
57
61
  desc, detail = $'.strip.split("\n", 2)
@@ -66,8 +70,10 @@ file "ChangeLog" => '.git/index' do
66
70
  }
67
71
  end
68
72
 
69
- file 'lib/rack/lint.rb'
70
73
  desc "Generate Rack Specification"
74
+ task spec: "SPEC"
75
+
76
+ file 'lib/rack/lint.rb'
71
77
  file "SPEC" => 'lib/rack/lint.rb' do
72
78
  File.open("SPEC", "wb") { |file|
73
79
  IO.foreach("lib/rack/lint.rb") { |line|
@@ -78,32 +84,27 @@ file "SPEC" => 'lib/rack/lint.rb' do
78
84
  }
79
85
  end
80
86
 
81
- desc "Run all the fast + platform agnostic tests"
82
- task :test => 'SPEC' do
83
- opts = ENV['TEST'] || '-a'
84
- specopts = ENV['TESTOPTS'] ||
85
- "-q -t '^(?!Rack::Adapter|Rack::Session::Memcache|Rack::Server|Rack::Handler)'"
86
-
87
- sh "bacon -I./lib:./test #{opts} #{specopts}"
87
+ Rake::TestTask.new("test:regular") do |t|
88
+ t.libs << "test"
89
+ t.test_files = FileList["test/**/*_test.rb", "test/**/spec_*.rb", "test/gemloader.rb"]
90
+ t.warning = false
91
+ t.verbose = true
88
92
  end
89
93
 
90
- desc "Run all the tests we run on CI"
91
- task :ci => :test
94
+ desc "Run all the fast + platform agnostic tests"
95
+ task test: %w[spec test:regular]
92
96
 
93
- desc "Run all the tests"
94
- task :fulltest => %w[SPEC chmod] do
95
- opts = ENV['TEST'] || '-a'
96
- specopts = ENV['TESTOPTS'] || '-q'
97
- sh "bacon -r./test/gemloader -I./lib:./test -w #{opts} #{specopts}"
98
- end
97
+ desc "Run all the tests we run on CI"
98
+ task ci: :test
99
99
 
100
- task :gem => ["SPEC"] do
100
+ task gem: :spec do
101
101
  sh "gem build rack.gemspec"
102
102
  end
103
103
 
104
- task :doc => :rdoc
104
+ task doc: :rdoc
105
+
105
106
  desc "Generate RDoc documentation"
106
- task :rdoc => %w[ChangeLog SPEC] do
107
+ task rdoc: %w[changelog spec] do
107
108
  sh(*%w{rdoc --line-numbers --main README.rdoc
108
109
  --title 'Rack\ Documentation' --charset utf-8 -U -o doc} +
109
110
  %w{README.rdoc KNOWN-ISSUES SPEC ChangeLog} +
@@ -111,11 +112,11 @@ task :rdoc => %w[ChangeLog SPEC] do
111
112
  cp "contrib/rdoc.css", "doc/rdoc.css"
112
113
  end
113
114
 
114
- task :pushdoc => %w[rdoc] do
115
+ task pushdoc: :rdoc do
115
116
  sh "rsync -avz doc/ rack.rubyforge.org:/var/www/gforge-projects/rack/doc/"
116
117
  end
117
118
 
118
- task :pushsite => %w[pushdoc] do
119
+ task pushsite: :pushdoc do
119
120
  sh "cd site && git gc"
120
121
  sh "rsync -avz site/ rack.rubyforge.org:/var/www/gforge-projects/rack/"
121
122
  sh "cd site && git push"
data/SPEC CHANGED
@@ -35,12 +35,22 @@ below.
35
35
  empty string, if the request URL targets
36
36
  the application root and does not have a
37
37
  trailing slash. This value may be
38
- percent-encoded when I originating from
38
+ percent-encoded when originating from
39
39
  a URL.
40
40
  <tt>QUERY_STRING</tt>:: The portion of the request URL that
41
41
  follows the <tt>?</tt>, if any. May be
42
42
  empty, but is always required!
43
- <tt>SERVER_NAME</tt>, <tt>SERVER_PORT</tt>:: When combined with <tt>SCRIPT_NAME</tt> and <tt>PATH_INFO</tt>, these variables can be used to complete the URL. Note, however, that <tt>HTTP_HOST</tt>, if present, should be used in preference to <tt>SERVER_NAME</tt> for reconstructing the request URL. <tt>SERVER_NAME</tt> and <tt>SERVER_PORT</tt> can never be empty strings, and so are always required.
43
+ <tt>SERVER_NAME</tt>, <tt>SERVER_PORT</tt>::
44
+ When combined with <tt>SCRIPT_NAME</tt> and
45
+ <tt>PATH_INFO</tt>, these variables can be
46
+ used to complete the URL. Note, however,
47
+ that <tt>HTTP_HOST</tt>, if present,
48
+ should be used in preference to
49
+ <tt>SERVER_NAME</tt> for reconstructing
50
+ the request URL.
51
+ <tt>SERVER_NAME</tt> and <tt>SERVER_PORT</tt>
52
+ can never be empty strings, and so
53
+ are always required.
44
54
  <tt>HTTP_</tt> Variables:: Variables corresponding to the
45
55
  client-supplied HTTP request
46
56
  headers (i.e., variables whose
@@ -49,20 +59,46 @@ below.
49
59
  variables should correspond with
50
60
  the presence or absence of the
51
61
  appropriate HTTP header in the
52
- request.
62
+ request. See
63
+ {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18]
64
+ for specific behavior.
53
65
  In addition to this, the Rack environment must include these
54
66
  Rack-specific variables:
55
- <tt>rack.version</tt>:: The Array [1,1], representing this version of Rack.
56
- <tt>rack.url_scheme</tt>:: +http+ or +https+, depending on the request URL.
67
+ <tt>rack.version</tt>:: The Array representing this version of Rack
68
+ See Rack::VERSION, that corresponds to
69
+ the version of this SPEC.
70
+ <tt>rack.url_scheme</tt>:: +http+ or +https+, depending on the
71
+ request URL.
57
72
  <tt>rack.input</tt>:: See below, the input stream.
58
73
  <tt>rack.errors</tt>:: See below, the error stream.
59
- <tt>rack.multithread</tt>:: true if the application object may be simultaneously invoked by another thread in the same process, false otherwise.
60
- <tt>rack.multiprocess</tt>:: true if an equivalent application object may be simultaneously invoked by another process, false otherwise.
61
- <tt>rack.run_once</tt>:: true if the server expects (but does not guarantee!) that the application will only be invoked this one time during the life of its containing process. Normally, this will only be true for a server based on CGI (or something similar).
74
+ <tt>rack.multithread</tt>:: true if the application object may be
75
+ simultaneously invoked by another thread
76
+ in the same process, false otherwise.
77
+ <tt>rack.multiprocess</tt>:: true if an equivalent application object
78
+ may be simultaneously invoked by another
79
+ process, false otherwise.
80
+ <tt>rack.run_once</tt>:: true if the server expects
81
+ (but does not guarantee!) that the
82
+ application will only be invoked this one
83
+ time during the life of its containing
84
+ process. Normally, this will only be true
85
+ for a server based on CGI
86
+ (or something similar).
87
+ <tt>rack.hijack?</tt>:: present and true if the server supports
88
+ connection hijacking. See below, hijacking.
89
+ <tt>rack.hijack</tt>:: an object responding to #call that must be
90
+ called at least once before using
91
+ rack.hijack_io.
92
+ It is recommended #call return rack.hijack_io
93
+ as well as setting it in env if necessary.
94
+ <tt>rack.hijack_io</tt>:: if rack.hijack? is true, and rack.hijack
95
+ has received #call, this will contain
96
+ an object resembling an IO. See hijacking.
62
97
  Additional environment specifications have approved to
63
98
  standardized middleware APIs. None of these are required to
64
99
  be implemented by the server.
65
- <tt>rack.session</tt>:: A hash like interface for storing request session data.
100
+ <tt>rack.session</tt>:: A hash like interface for storing
101
+ request session data.
66
102
  The store must implement:
67
103
  store(key, value) (aliased as []=);
68
104
  fetch(key, default = nil) (aliased as []);
@@ -75,6 +111,8 @@ be implemented by the server.
75
111
  warn(message, &block)
76
112
  error(message, &block)
77
113
  fatal(message, &block)
114
+ <tt>rack.multipart.buffer_size</tt>:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes.
115
+ <tt>rack.multipart.tempfile_factory</tt>:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile.
78
116
  The server or the application can store their own data in the
79
117
  environment, too. The keys must contain at least one dot,
80
118
  and should be prefixed uniquely. The prefix <tt>rack.</tt>
@@ -89,6 +127,7 @@ There are the following restrictions:
89
127
  * <tt>rack.url_scheme</tt> must either be +http+ or +https+.
90
128
  * There must be a valid input stream in <tt>rack.input</tt>.
91
129
  * There must be a valid error stream in <tt>rack.errors</tt>.
130
+ * There may be a valid hijack stream in <tt>rack.hijack_io</tt>
92
131
  * The <tt>REQUEST_METHOD</tt> must be a valid token.
93
132
  * The <tt>SCRIPT_NAME</tt>, if non-empty, must start with <tt>/</tt>
94
133
  * The <tt>PATH_INFO</tt>, if non-empty, must start with <tt>/</tt>
@@ -105,15 +144,18 @@ must be opened in binary mode, for Ruby 1.9 compatibility.
105
144
  The input stream must respond to +gets+, +each+, +read+ and +rewind+.
106
145
  * +gets+ must be called without arguments and return a string,
107
146
  or +nil+ on EOF.
108
- * +read+ behaves like IO#read. Its signature is <tt>read([length, [buffer]])</tt>.
109
- If given, +length+ must be a non-negative Integer (>= 0) or +nil+, and +buffer+ must
110
- be a String and may not be nil. If +length+ is given and not nil, then this method
111
- reads at most +length+ bytes from the input stream. If +length+ is not given or nil,
112
- then this method reads all data until EOF.
113
- When EOF is reached, this method returns nil if +length+ is given and not nil, or ""
114
- if +length+ is not given or is nil.
115
- If +buffer+ is given, then the read data will be placed into +buffer+ instead of a
116
- newly created String object.
147
+ * +read+ behaves like IO#read.
148
+ Its signature is <tt>read([length, [buffer]])</tt>.
149
+ If given, +length+ must be a non-negative Integer (>= 0) or +nil+,
150
+ and +buffer+ must be a String and may not be nil.
151
+ If +length+ is given and not nil, then this method reads at most
152
+ +length+ bytes from the input stream.
153
+ If +length+ is not given or nil, then this method reads
154
+ all data until EOF.
155
+ When EOF is reached, this method returns nil if +length+ is given
156
+ and not nil, or "" if +length+ is not given or is nil.
157
+ If +buffer+ is given, then the read data will be placed
158
+ into +buffer+ instead of a newly created String object.
117
159
  * +each+ must be called without arguments and only yield Strings.
118
160
  * +rewind+ must be called without arguments. It rewinds the input
119
161
  stream back to the beginning. It must not raise Errno::ESPIPE:
@@ -128,6 +170,55 @@ The error stream must respond to +puts+, +write+ and +flush+.
128
170
  * +flush+ must be called without arguments and must be called
129
171
  in order to make the error appear for sure.
130
172
  * +close+ must never be called on the error stream.
173
+ === Hijacking
174
+ ==== Request (before status)
175
+ If rack.hijack? is true then rack.hijack must respond to #call.
176
+ rack.hijack must return the io that will also be assigned (or is
177
+ already present, in rack.hijack_io.
178
+ rack.hijack_io must respond to:
179
+ <tt>read, write, read_nonblock, write_nonblock, flush, close,
180
+ close_read, close_write, closed?</tt>
181
+ The semantics of these IO methods must be a best effort match to
182
+ those of a normal ruby IO or Socket object, using standard
183
+ arguments and raising standard exceptions. Servers are encouraged
184
+ to simply pass on real IO objects, although it is recognized that
185
+ this approach is not directly compatible with SPDY and HTTP 2.0.
186
+ IO provided in rack.hijack_io should preference the
187
+ IO::WaitReadable and IO::WaitWritable APIs wherever supported.
188
+ There is a deliberate lack of full specification around
189
+ rack.hijack_io, as semantics will change from server to server.
190
+ Users are encouraged to utilize this API with a knowledge of their
191
+ server choice, and servers may extend the functionality of
192
+ hijack_io to provide additional features to users. The purpose of
193
+ rack.hijack is for Rack to "get out of the way", as such, Rack only
194
+ provides the minimum of specification and support.
195
+ If rack.hijack? is false, then rack.hijack should not be set.
196
+ If rack.hijack? is false, then rack.hijack_io should not be set.
197
+ ==== Response (after headers)
198
+ It is also possible to hijack a response after the status and headers
199
+ have been sent.
200
+ In order to do this, an application may set the special header
201
+ <tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
202
+ accepting an argument that conforms to the <tt>rack.hijack_io</tt>
203
+ protocol.
204
+ After the headers have been sent, and this hijack callback has been
205
+ called, the application is now responsible for the remaining lifecycle
206
+ of the IO. The application is also responsible for maintaining HTTP
207
+ semantics. Of specific note, in almost all cases in the current SPEC,
208
+ applications will have wanted to specify the header Connection:close in
209
+ HTTP/1.1, and not Connection:keep-alive, as there is no protocol for
210
+ returning hijacked sockets to the web server. For that purpose, use the
211
+ body streaming API instead (progressively yielding strings via each).
212
+ Servers must ignore the <tt>body</tt> part of the response tuple when
213
+ the <tt>rack.hijack</tt> response API is in use.
214
+ The special response header <tt>rack.hijack</tt> must only be set
215
+ if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
216
+ ==== Conventions
217
+ * Middleware should not use hijack unless it is handling the whole
218
+ response.
219
+ * Middleware may wrap the IO object for the response pattern.
220
+ * Middleware should not wrap the IO object for the request pattern. The
221
+ request pattern is intended to provide the hijacker with "raw tcp".
131
222
  == The Response
132
223
  === The Status
133
224
  This is an HTTP status. When parsed as integer (+to_i+), it must be
@@ -135,22 +226,21 @@ greater than or equal to 100.
135
226
  === The Headers
136
227
  The header must respond to +each+, and yield values of key and value.
137
228
  The header keys must be Strings.
138
- The header must not contain a +Status+ key,
139
- contain keys with <tt>:</tt> or newlines in their name,
140
- contain keys names that end in <tt>-</tt> or <tt>_</tt>,
141
- but only contain keys that consist of
142
- letters, digits, <tt>_</tt> or <tt>-</tt> and start with a letter.
229
+ Special headers starting "rack." are for communicating with the
230
+ server, and must not be sent back to the client.
231
+ The header must not contain a +Status+ key.
232
+ The header must conform to RFC7230 token specification, i.e. cannot
233
+ contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}".
143
234
  The values of the header must be Strings,
144
235
  consisting of lines (for multiple header values, e.g. multiple
145
- <tt>Set-Cookie</tt> values) seperated by "\n".
236
+ <tt>Set-Cookie</tt> values) separated by "\\n".
146
237
  The lines must not contain characters below 037.
147
238
  === The Content-Type
148
- There must be a <tt>Content-Type</tt>, except when the
149
- +Status+ is 1xx, 204, 205 or 304, in which case there must be none
150
- given.
239
+ There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
240
+ 204 or 304.
151
241
  === The Content-Length
152
242
  There must not be a <tt>Content-Length</tt> header when the
153
- +Status+ is 1xx, 204, 205 or 304.
243
+ +Status+ is 1xx, 204 or 304.
154
244
  === The Body
155
245
  The Body must respond to +each+
156
246
  and must only yield String values.
@@ -158,7 +248,7 @@ The Body itself should not be an instance of String, as this will
158
248
  break in Ruby 1.9.
159
249
  If the Body responds to +close+, it will be called after iteration. If
160
250
  the body is replaced by a middleware after action, the original body
161
- must be closed first, if it repsonds to close.
251
+ must be closed first, if it responds to close.
162
252
  If the Body responds to +to_path+, it must return a String
163
253
  identifying the location of a file whose contents are identical
164
254
  to that produced by calling +each+; this may be used by the
data/bin/rackup CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "rack"
4
5
  Rack::Server.start