unicorn-lb-patch 4.3.1.11.g21b8.dirty

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. data/.CHANGELOG.old +25 -0
  2. data/.document +29 -0
  3. data/.gitignore +25 -0
  4. data/.mailmap +26 -0
  5. data/.wrongdoc.yml +10 -0
  6. data/Application_Timeouts +77 -0
  7. data/CONTRIBUTORS +35 -0
  8. data/COPYING +674 -0
  9. data/DESIGN +97 -0
  10. data/Documentation/.gitignore +5 -0
  11. data/Documentation/GNUmakefile +30 -0
  12. data/Documentation/unicorn.1.txt +174 -0
  13. data/Documentation/unicorn_rails.1.txt +175 -0
  14. data/FAQ +53 -0
  15. data/GIT-VERSION-GEN +40 -0
  16. data/GNUmakefile +294 -0
  17. data/HACKING +134 -0
  18. data/ISSUES +36 -0
  19. data/KNOWN_ISSUES +79 -0
  20. data/LICENSE +64 -0
  21. data/Links +56 -0
  22. data/PHILOSOPHY +145 -0
  23. data/README +149 -0
  24. data/Rakefile +97 -0
  25. data/SIGNALS +114 -0
  26. data/Sandbox +96 -0
  27. data/TODO +5 -0
  28. data/TUNING +98 -0
  29. data/bin/unicorn +121 -0
  30. data/bin/unicorn_rails +209 -0
  31. data/examples/big_app_gc.rb +2 -0
  32. data/examples/echo.ru +27 -0
  33. data/examples/git.ru +13 -0
  34. data/examples/init.sh +74 -0
  35. data/examples/logger_mp_safe.rb +25 -0
  36. data/examples/logrotate.conf +29 -0
  37. data/examples/nginx.conf +156 -0
  38. data/examples/unicorn.conf.minimal.rb +13 -0
  39. data/examples/unicorn.conf.rb +94 -0
  40. data/ext/unicorn_http/CFLAGS +13 -0
  41. data/ext/unicorn_http/c_util.h +124 -0
  42. data/ext/unicorn_http/common_field_optimization.h +111 -0
  43. data/ext/unicorn_http/ext_help.h +86 -0
  44. data/ext/unicorn_http/extconf.rb +10 -0
  45. data/ext/unicorn_http/global_variables.h +97 -0
  46. data/ext/unicorn_http/httpdate.c +82 -0
  47. data/ext/unicorn_http/unicorn_http.rl +1036 -0
  48. data/ext/unicorn_http/unicorn_http_common.rl +76 -0
  49. data/lib/unicorn.rb +107 -0
  50. data/lib/unicorn/app/exec_cgi.rb +154 -0
  51. data/lib/unicorn/app/inetd.rb +109 -0
  52. data/lib/unicorn/app/old_rails.rb +35 -0
  53. data/lib/unicorn/app/old_rails/static.rb +59 -0
  54. data/lib/unicorn/cgi_wrapper.rb +147 -0
  55. data/lib/unicorn/configurator.rb +630 -0
  56. data/lib/unicorn/const.rb +40 -0
  57. data/lib/unicorn/http_request.rb +77 -0
  58. data/lib/unicorn/http_response.rb +45 -0
  59. data/lib/unicorn/http_server.rb +755 -0
  60. data/lib/unicorn/launcher.rb +62 -0
  61. data/lib/unicorn/oob_gc.rb +71 -0
  62. data/lib/unicorn/preread_input.rb +33 -0
  63. data/lib/unicorn/socket_helper.rb +208 -0
  64. data/lib/unicorn/ssl_client.rb +11 -0
  65. data/lib/unicorn/ssl_configurator.rb +104 -0
  66. data/lib/unicorn/ssl_server.rb +42 -0
  67. data/lib/unicorn/stream_input.rb +149 -0
  68. data/lib/unicorn/tee_input.rb +126 -0
  69. data/lib/unicorn/tmpio.rb +29 -0
  70. data/lib/unicorn/util.rb +68 -0
  71. data/lib/unicorn/worker.rb +88 -0
  72. data/local.mk.sample +59 -0
  73. data/script/isolate_for_tests +50 -0
  74. data/setup.rb +1586 -0
  75. data/t/.gitignore +5 -0
  76. data/t/GNUmakefile +82 -0
  77. data/t/README +42 -0
  78. data/t/bin/content-md5-put +36 -0
  79. data/t/bin/sha1sum.rb +17 -0
  80. data/t/bin/unused_listen +40 -0
  81. data/t/bin/utee +12 -0
  82. data/t/broken-app.ru +12 -0
  83. data/t/detach.ru +11 -0
  84. data/t/env.ru +3 -0
  85. data/t/heartbeat-timeout.ru +12 -0
  86. data/t/listener_names.ru +4 -0
  87. data/t/my-tap-lib.sh +201 -0
  88. data/t/oob_gc.ru +21 -0
  89. data/t/oob_gc_path.ru +21 -0
  90. data/t/pid.ru +3 -0
  91. data/t/preread_input.ru +17 -0
  92. data/t/rack-input-tests.ru +21 -0
  93. data/t/rails3-app/.gitignore +4 -0
  94. data/t/rails3-app/Gemfile +26 -0
  95. data/t/rails3-app/Rakefile +10 -0
  96. data/t/rails3-app/app/controllers/application_controller.rb +4 -0
  97. data/t/rails3-app/app/helpers/application_helper.rb +2 -0
  98. data/t/rails3-app/app/views/layouts/application.html.erb +14 -0
  99. data/t/rails3-app/config.ru +4 -0
  100. data/t/rails3-app/config/application.rb +46 -0
  101. data/t/rails3-app/config/boot.rb +6 -0
  102. data/t/rails3-app/config/database.yml +22 -0
  103. data/t/rails3-app/config/environment.rb +5 -0
  104. data/t/rails3-app/config/environments/development.rb +19 -0
  105. data/t/rails3-app/config/environments/production.rb +42 -0
  106. data/t/rails3-app/config/environments/test.rb +32 -0
  107. data/t/rails3-app/config/initializers/backtrace_silencers.rb +7 -0
  108. data/t/rails3-app/config/initializers/inflections.rb +10 -0
  109. data/t/rails3-app/config/initializers/mime_types.rb +5 -0
  110. data/t/rails3-app/config/initializers/secret_token.rb +7 -0
  111. data/t/rails3-app/config/initializers/session_store.rb +8 -0
  112. data/t/rails3-app/config/locales/en.yml +5 -0
  113. data/t/rails3-app/config/routes.rb +58 -0
  114. data/t/rails3-app/db/seeds.rb +7 -0
  115. data/t/rails3-app/doc/README_FOR_APP +2 -0
  116. data/t/rails3-app/lib/tasks/.gitkeep +0 -0
  117. data/t/rails3-app/public/404.html +1 -0
  118. data/t/rails3-app/public/500.html +1 -0
  119. data/t/rails3-app/public/x.txt +1 -0
  120. data/t/rails3-app/script/rails +9 -0
  121. data/t/rails3-app/test/performance/browsing_test.rb +9 -0
  122. data/t/rails3-app/test/test_helper.rb +13 -0
  123. data/t/rails3-app/vendor/plugins/.gitkeep +0 -0
  124. data/t/sslgen.sh +71 -0
  125. data/t/t0000-http-basic.sh +50 -0
  126. data/t/t0001-reload-bad-config.sh +53 -0
  127. data/t/t0002-config-conflict.sh +49 -0
  128. data/t/t0002-parser-error.sh +94 -0
  129. data/t/t0003-working_directory.sh +51 -0
  130. data/t/t0004-heartbeat-timeout.sh +69 -0
  131. data/t/t0004-working_directory_broken.sh +24 -0
  132. data/t/t0005-working_directory_app.rb.sh +37 -0
  133. data/t/t0006-reopen-logs.sh +83 -0
  134. data/t/t0006.ru +13 -0
  135. data/t/t0007-working_directory_no_embed_cli.sh +44 -0
  136. data/t/t0008-back_out_of_upgrade.sh +110 -0
  137. data/t/t0009-broken-app.sh +56 -0
  138. data/t/t0009-winch_ttin.sh +59 -0
  139. data/t/t0010-reap-logging.sh +55 -0
  140. data/t/t0011-active-unix-socket.sh +79 -0
  141. data/t/t0012-reload-empty-config.sh +85 -0
  142. data/t/t0013-rewindable-input-false.sh +24 -0
  143. data/t/t0013.ru +12 -0
  144. data/t/t0014-rewindable-input-true.sh +24 -0
  145. data/t/t0014.ru +12 -0
  146. data/t/t0015-configurator-internals.sh +25 -0
  147. data/t/t0016-trust-x-forwarded-false.sh +30 -0
  148. data/t/t0017-trust-x-forwarded-true.sh +30 -0
  149. data/t/t0018-write-on-close.sh +23 -0
  150. data/t/t0019-max_header_len.sh +49 -0
  151. data/t/t0020-at_exit-handler.sh +49 -0
  152. data/t/t0021-process_detach.sh +29 -0
  153. data/t/t0022-listener-names-preload_app.sh +32 -0
  154. data/t/t0100-rack-input-tests.sh +124 -0
  155. data/t/t0116-client_body_buffer_size.sh +80 -0
  156. data/t/t0116.ru +16 -0
  157. data/t/t0300-rails3-basic.sh +28 -0
  158. data/t/t0301-rails3-missing-config-ru.sh +33 -0
  159. data/t/t0302-rails3-alt-working_directory.sh +32 -0
  160. data/t/t0303-rails3-alt-working_directory_config.ru.sh +56 -0
  161. data/t/t0304-rails3-alt-working_directory_no_embed_cli.sh +52 -0
  162. data/t/t0600-https-server-basic.sh +48 -0
  163. data/t/t9000-preread-input.sh +48 -0
  164. data/t/t9001-oob_gc.sh +47 -0
  165. data/t/t9002-oob_gc-path.sh +75 -0
  166. data/t/test-lib.sh +113 -0
  167. data/t/test-rails3.sh +27 -0
  168. data/t/write-on-close.ru +11 -0
  169. data/test/aggregate.rb +15 -0
  170. data/test/benchmark/README +50 -0
  171. data/test/benchmark/dd.ru +18 -0
  172. data/test/benchmark/stack.ru +8 -0
  173. data/test/exec/README +5 -0
  174. data/test/exec/test_exec.rb +1055 -0
  175. data/test/rails/app-1.2.3/.gitignore +2 -0
  176. data/test/rails/app-1.2.3/Rakefile +7 -0
  177. data/test/rails/app-1.2.3/app/controllers/application.rb +6 -0
  178. data/test/rails/app-1.2.3/app/controllers/foo_controller.rb +36 -0
  179. data/test/rails/app-1.2.3/app/helpers/application_helper.rb +4 -0
  180. data/test/rails/app-1.2.3/config/boot.rb +11 -0
  181. data/test/rails/app-1.2.3/config/database.yml +12 -0
  182. data/test/rails/app-1.2.3/config/environment.rb +13 -0
  183. data/test/rails/app-1.2.3/config/environments/development.rb +9 -0
  184. data/test/rails/app-1.2.3/config/environments/production.rb +5 -0
  185. data/test/rails/app-1.2.3/config/routes.rb +6 -0
  186. data/test/rails/app-1.2.3/db/.gitignore +0 -0
  187. data/test/rails/app-1.2.3/public/404.html +1 -0
  188. data/test/rails/app-1.2.3/public/500.html +1 -0
  189. data/test/rails/app-2.0.2/.gitignore +2 -0
  190. data/test/rails/app-2.0.2/Rakefile +7 -0
  191. data/test/rails/app-2.0.2/app/controllers/application.rb +4 -0
  192. data/test/rails/app-2.0.2/app/controllers/foo_controller.rb +36 -0
  193. data/test/rails/app-2.0.2/app/helpers/application_helper.rb +4 -0
  194. data/test/rails/app-2.0.2/config/boot.rb +11 -0
  195. data/test/rails/app-2.0.2/config/database.yml +12 -0
  196. data/test/rails/app-2.0.2/config/environment.rb +17 -0
  197. data/test/rails/app-2.0.2/config/environments/development.rb +8 -0
  198. data/test/rails/app-2.0.2/config/environments/production.rb +5 -0
  199. data/test/rails/app-2.0.2/config/routes.rb +6 -0
  200. data/test/rails/app-2.0.2/db/.gitignore +0 -0
  201. data/test/rails/app-2.0.2/public/404.html +1 -0
  202. data/test/rails/app-2.0.2/public/500.html +1 -0
  203. data/test/rails/app-2.1.2/.gitignore +2 -0
  204. data/test/rails/app-2.1.2/Rakefile +7 -0
  205. data/test/rails/app-2.1.2/app/controllers/application.rb +4 -0
  206. data/test/rails/app-2.1.2/app/controllers/foo_controller.rb +36 -0
  207. data/test/rails/app-2.1.2/app/helpers/application_helper.rb +4 -0
  208. data/test/rails/app-2.1.2/config/boot.rb +111 -0
  209. data/test/rails/app-2.1.2/config/database.yml +12 -0
  210. data/test/rails/app-2.1.2/config/environment.rb +17 -0
  211. data/test/rails/app-2.1.2/config/environments/development.rb +7 -0
  212. data/test/rails/app-2.1.2/config/environments/production.rb +5 -0
  213. data/test/rails/app-2.1.2/config/routes.rb +6 -0
  214. data/test/rails/app-2.1.2/db/.gitignore +0 -0
  215. data/test/rails/app-2.1.2/public/404.html +1 -0
  216. data/test/rails/app-2.1.2/public/500.html +1 -0
  217. data/test/rails/app-2.2.2/.gitignore +2 -0
  218. data/test/rails/app-2.2.2/Rakefile +7 -0
  219. data/test/rails/app-2.2.2/app/controllers/application.rb +4 -0
  220. data/test/rails/app-2.2.2/app/controllers/foo_controller.rb +36 -0
  221. data/test/rails/app-2.2.2/app/helpers/application_helper.rb +4 -0
  222. data/test/rails/app-2.2.2/config/boot.rb +111 -0
  223. data/test/rails/app-2.2.2/config/database.yml +12 -0
  224. data/test/rails/app-2.2.2/config/environment.rb +17 -0
  225. data/test/rails/app-2.2.2/config/environments/development.rb +7 -0
  226. data/test/rails/app-2.2.2/config/environments/production.rb +5 -0
  227. data/test/rails/app-2.2.2/config/routes.rb +6 -0
  228. data/test/rails/app-2.2.2/db/.gitignore +0 -0
  229. data/test/rails/app-2.2.2/public/404.html +1 -0
  230. data/test/rails/app-2.2.2/public/500.html +1 -0
  231. data/test/rails/test_rails.rb +287 -0
  232. data/test/test_helper.rb +300 -0
  233. data/test/unit/test_configurator.rb +158 -0
  234. data/test/unit/test_droplet.rb +28 -0
  235. data/test/unit/test_http_parser.rb +860 -0
  236. data/test/unit/test_http_parser_ng.rb +716 -0
  237. data/test/unit/test_http_parser_xftrust.rb +38 -0
  238. data/test/unit/test_request.rb +197 -0
  239. data/test/unit/test_response.rb +99 -0
  240. data/test/unit/test_server.rb +289 -0
  241. data/test/unit/test_signals.rb +207 -0
  242. data/test/unit/test_sni_hostnames.rb +47 -0
  243. data/test/unit/test_socket_helper.rb +192 -0
  244. data/test/unit/test_stream_input.rb +204 -0
  245. data/test/unit/test_tee_input.rb +296 -0
  246. data/test/unit/test_upload.rb +306 -0
  247. data/test/unit/test_util.rb +100 -0
  248. data/unicorn-lb-patch.gemspec +27 -0
  249. metadata +561 -0
@@ -0,0 +1,716 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ require 'test/test_helper'
4
+ require 'digest/md5'
5
+
6
+ include Unicorn
7
+
8
+ class HttpParserNgTest < Test::Unit::TestCase
9
+
10
+ def setup
11
+ HttpParser.keepalive_requests = HttpParser::KEEPALIVE_REQUESTS_DEFAULT
12
+ @parser = HttpParser.new
13
+ end
14
+
15
+ def test_keepalive_requests_default_constant
16
+ assert_kind_of Integer, HttpParser::KEEPALIVE_REQUESTS_DEFAULT
17
+ assert HttpParser::KEEPALIVE_REQUESTS_DEFAULT >= 0
18
+ end
19
+
20
+ def test_keepalive_requests_setting
21
+ HttpParser.keepalive_requests = 0
22
+ assert_equal 0, HttpParser.keepalive_requests
23
+ HttpParser.keepalive_requests = nil
24
+ assert HttpParser.keepalive_requests >= 0xffffffff
25
+ HttpParser.keepalive_requests = 1
26
+ assert_equal 1, HttpParser.keepalive_requests
27
+ HttpParser.keepalive_requests = 666
28
+ assert_equal 666, HttpParser.keepalive_requests
29
+
30
+ assert_raises(TypeError) { HttpParser.keepalive_requests = "666" }
31
+ assert_raises(TypeError) { HttpParser.keepalive_requests = [] }
32
+ end
33
+
34
+ def test_connection_TE
35
+ @parser.buf << "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: TE\r\n"
36
+ @parser.buf << "TE: trailers\r\n\r\n"
37
+ assert_nothing_raised { @parser.parse }
38
+ assert @parser.keepalive?
39
+ assert @parser.next?
40
+ end
41
+
42
+ def test_keepalive_requests_with_next?
43
+ req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
44
+ expect = {
45
+ "SERVER_NAME" => "example.com",
46
+ "HTTP_HOST" => "example.com",
47
+ "rack.url_scheme" => "http",
48
+ "REQUEST_PATH" => "/",
49
+ "SERVER_PROTOCOL" => "HTTP/1.1",
50
+ "PATH_INFO" => "/",
51
+ "HTTP_VERSION" => "HTTP/1.1",
52
+ "REQUEST_URI" => "/",
53
+ "SERVER_PORT" => "80",
54
+ "REQUEST_METHOD" => "GET",
55
+ "QUERY_STRING" => ""
56
+ }.freeze
57
+ HttpParser::KEEPALIVE_REQUESTS_DEFAULT.times do |nr|
58
+ @parser.buf << req
59
+ assert_equal expect, @parser.parse
60
+ assert @parser.next?
61
+ end
62
+ @parser.buf << req
63
+ assert_equal expect, @parser.parse
64
+ assert ! @parser.next?
65
+ end
66
+
67
+ def test_fewer_keepalive_requests_with_next?
68
+ HttpParser.keepalive_requests = 5
69
+ @parser = HttpParser.new
70
+ req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
71
+ expect = {
72
+ "SERVER_NAME" => "example.com",
73
+ "HTTP_HOST" => "example.com",
74
+ "rack.url_scheme" => "http",
75
+ "REQUEST_PATH" => "/",
76
+ "SERVER_PROTOCOL" => "HTTP/1.1",
77
+ "PATH_INFO" => "/",
78
+ "HTTP_VERSION" => "HTTP/1.1",
79
+ "REQUEST_URI" => "/",
80
+ "SERVER_PORT" => "80",
81
+ "REQUEST_METHOD" => "GET",
82
+ "QUERY_STRING" => ""
83
+ }.freeze
84
+ 5.times do |nr|
85
+ @parser.buf << req
86
+ assert_equal expect, @parser.parse
87
+ assert @parser.next?
88
+ end
89
+ @parser.buf << req
90
+ assert_equal expect, @parser.parse
91
+ assert ! @parser.next?
92
+ end
93
+
94
+ def test_default_keepalive_is_off
95
+ assert ! @parser.keepalive?
96
+ assert ! @parser.next?
97
+ assert_nothing_raised do
98
+ @parser.buf << "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
99
+ @parser.parse
100
+ end
101
+ assert @parser.keepalive?
102
+ @parser.clear
103
+ assert ! @parser.keepalive?
104
+ assert ! @parser.next?
105
+ end
106
+
107
+ def test_identity_byte_headers
108
+ req = @parser.env
109
+ str = "PUT / HTTP/1.1\r\n"
110
+ str << "Content-Length: 123\r\n"
111
+ str << "\r"
112
+ hdr = @parser.buf
113
+ str.each_byte { |byte|
114
+ hdr << byte.chr
115
+ assert_nil @parser.parse
116
+ }
117
+ hdr << "\n"
118
+ assert_equal req.object_id, @parser.parse.object_id
119
+ assert_equal '123', req['CONTENT_LENGTH']
120
+ assert_equal 0, hdr.size
121
+ assert ! @parser.keepalive?
122
+ assert @parser.headers?
123
+ assert_equal 123, @parser.content_length
124
+ dst = ""
125
+ buf = '.' * 123
126
+ @parser.filter_body(dst, buf)
127
+ assert_equal '.' * 123, dst
128
+ assert_equal "", buf
129
+ assert @parser.keepalive?
130
+ end
131
+
132
+ def test_identity_step_headers
133
+ req = @parser.env
134
+ str = @parser.buf
135
+ str << "PUT / HTTP/1.1\r\n"
136
+ assert ! @parser.parse
137
+ str << "Content-Length: 123\r\n"
138
+ assert ! @parser.parse
139
+ str << "\r\n"
140
+ assert_equal req.object_id, @parser.parse.object_id
141
+ assert_equal '123', req['CONTENT_LENGTH']
142
+ assert_equal 0, str.size
143
+ assert ! @parser.keepalive?
144
+ assert @parser.headers?
145
+ dst = ""
146
+ buf = '.' * 123
147
+ @parser.filter_body(dst, buf)
148
+ assert_equal '.' * 123, dst
149
+ assert_equal "", buf
150
+ assert @parser.keepalive?
151
+ end
152
+
153
+ def test_identity_oneshot_header
154
+ req = @parser.env
155
+ str = @parser.buf
156
+ str << "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\n"
157
+ assert_equal req.object_id, @parser.parse.object_id
158
+ assert_equal '123', req['CONTENT_LENGTH']
159
+ assert_equal 0, str.size
160
+ assert ! @parser.keepalive?
161
+ assert @parser.headers?
162
+ dst = ""
163
+ buf = '.' * 123
164
+ @parser.filter_body(dst, buf)
165
+ assert_equal '.' * 123, dst
166
+ assert_equal "", buf
167
+ end
168
+
169
+ def test_identity_oneshot_header_with_body
170
+ body = ('a' * 123).freeze
171
+ req = @parser.env
172
+ str = @parser.buf
173
+ str << "PUT / HTTP/1.1\r\n" \
174
+ "Content-Length: #{body.length}\r\n" \
175
+ "\r\n#{body}"
176
+ assert_equal req.object_id, @parser.parse.object_id
177
+ assert_equal '123', req['CONTENT_LENGTH']
178
+ assert_equal 123, str.size
179
+ assert_equal body, str
180
+ tmp = ''
181
+ assert_nil @parser.filter_body(tmp, str)
182
+ assert_equal 0, str.size
183
+ assert_equal tmp, body
184
+ assert_equal "", @parser.filter_body(tmp, str)
185
+ assert @parser.keepalive?
186
+ end
187
+
188
+ def test_identity_oneshot_header_with_body_partial
189
+ str = @parser.buf
190
+ str << "PUT / HTTP/1.1\r\nContent-Length: 123\r\n\r\na"
191
+ assert_equal Hash, @parser.parse.class
192
+ assert_equal 1, str.size
193
+ assert_equal 'a', str
194
+ tmp = ''
195
+ assert_nil @parser.filter_body(tmp, str)
196
+ assert_equal "", str
197
+ assert_equal "a", tmp
198
+ str << ' ' * 122
199
+ rv = @parser.filter_body(tmp, str)
200
+ assert_equal 122, tmp.size
201
+ assert_nil rv
202
+ assert_equal "", str
203
+ assert_equal str.object_id, @parser.filter_body(tmp, str).object_id
204
+ assert @parser.keepalive?
205
+ end
206
+
207
+ def test_identity_oneshot_header_with_body_slop
208
+ str = @parser.buf
209
+ str << "PUT / HTTP/1.1\r\nContent-Length: 1\r\n\r\naG"
210
+ assert_equal Hash, @parser.parse.class
211
+ assert_equal 2, str.size
212
+ assert_equal 'aG', str
213
+ tmp = ''
214
+ assert_nil @parser.filter_body(tmp, str)
215
+ assert_equal "G", str
216
+ assert_equal "G", @parser.filter_body(tmp, str)
217
+ assert_equal 1, tmp.size
218
+ assert_equal "a", tmp
219
+ assert @parser.keepalive?
220
+ end
221
+
222
+ def test_chunked
223
+ str = @parser.buf
224
+ req = @parser.env
225
+ str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
226
+ assert_equal req, @parser.parse, "msg=#{str}"
227
+ assert_equal 0, str.size
228
+ tmp = ""
229
+ assert_nil @parser.filter_body(tmp, str << "6")
230
+ assert_equal 0, tmp.size
231
+ assert_nil @parser.filter_body(tmp, str << "\r\n")
232
+ assert_equal 0, str.size
233
+ assert_equal 0, tmp.size
234
+ tmp = ""
235
+ assert_nil @parser.filter_body(tmp, str << "..")
236
+ assert_equal "..", tmp
237
+ assert_nil @parser.filter_body(tmp, str << "abcd\r\n0\r\n")
238
+ assert_equal "abcd", tmp
239
+ assert_equal str.object_id, @parser.filter_body(tmp, str << "PUT").object_id
240
+ assert_equal "PUT", str
241
+ assert ! @parser.keepalive?
242
+ str << "TY: FOO\r\n\r\n"
243
+ assert_equal req, @parser.parse
244
+ assert_equal "FOO", req["HTTP_PUTTY"]
245
+ assert @parser.keepalive?
246
+ end
247
+
248
+ def test_chunked_empty
249
+ str = @parser.buf
250
+ req = @parser.env
251
+ str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
252
+ assert_equal req, @parser.parse, "msg=#{str}"
253
+ assert_equal 0, str.size
254
+ tmp = ""
255
+ assert_equal str, @parser.filter_body(tmp, str << "0\r\n\r\n")
256
+ assert_equal "", tmp
257
+ end
258
+
259
+ def test_two_chunks
260
+ str = @parser.buf
261
+ str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
262
+ req = @parser.env
263
+ assert_equal req, @parser.parse
264
+ assert_equal 0, str.size
265
+ tmp = ""
266
+ assert_nil @parser.filter_body(tmp, str << "6")
267
+ assert_equal 0, tmp.size
268
+ assert_nil @parser.filter_body(tmp, str << "\r\n")
269
+ assert_equal "", str
270
+ assert_equal 0, tmp.size
271
+ tmp = ""
272
+ assert_nil @parser.filter_body(tmp, str << "..")
273
+ assert_equal 2, tmp.size
274
+ assert_equal "..", tmp
275
+ assert_nil @parser.filter_body(tmp, str << "abcd\r\n1")
276
+ assert_equal "abcd", tmp
277
+ assert_nil @parser.filter_body(tmp, str << "\r")
278
+ assert_equal "", tmp
279
+ assert_nil @parser.filter_body(tmp, str << "\n")
280
+ assert_equal "", tmp
281
+ assert_nil @parser.filter_body(tmp, str << "z")
282
+ assert_equal "z", tmp
283
+ assert_nil @parser.filter_body(tmp, str << "\r\n")
284
+ assert_nil @parser.filter_body(tmp, str << "0")
285
+ assert_nil @parser.filter_body(tmp, str << "\r")
286
+ rv = @parser.filter_body(tmp, str << "\nGET")
287
+ assert_equal "GET", rv
288
+ assert_equal str.object_id, rv.object_id
289
+ assert ! @parser.keepalive?
290
+ end
291
+
292
+ def test_big_chunk
293
+ str = @parser.buf
294
+ str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
295
+ "4000\r\nabcd"
296
+ req = @parser.env
297
+ assert_equal req, @parser.parse
298
+ tmp = ''
299
+ assert_nil @parser.filter_body(tmp, str)
300
+ assert_equal '', str
301
+ str << ' ' * 16300
302
+ assert_nil @parser.filter_body(tmp, str)
303
+ assert_equal '', str
304
+ str << ' ' * 80
305
+ assert_nil @parser.filter_body(tmp, str)
306
+ assert_equal '', str
307
+ assert ! @parser.body_eof?
308
+ assert_equal "", @parser.filter_body(tmp, str << "\r\n0\r\n")
309
+ assert_equal "", tmp
310
+ assert @parser.body_eof?
311
+ str << "\r\n"
312
+ assert_equal req, @parser.parse
313
+ assert_equal "", str
314
+ assert @parser.body_eof?
315
+ assert @parser.keepalive?
316
+ end
317
+
318
+ def test_two_chunks_oneshot
319
+ str = @parser.buf
320
+ req = @parser.env
321
+ str << "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n" \
322
+ "1\r\na\r\n2\r\n..\r\n0\r\n"
323
+ assert_equal req, @parser.parse
324
+ tmp = ''
325
+ assert_nil @parser.filter_body(tmp, str)
326
+ assert_equal 'a..', tmp
327
+ rv = @parser.filter_body(tmp, str)
328
+ assert_equal rv.object_id, str.object_id
329
+ assert ! @parser.keepalive?
330
+ end
331
+
332
+ def test_chunks_bytewise
333
+ chunked = "10\r\nabcdefghijklmnop\r\n11\r\n0123456789abcdefg\r\n0\r\n"
334
+ str = "PUT / HTTP/1.1\r\ntransfer-Encoding: chunked\r\n\r\n"
335
+ buf = @parser.buf
336
+ buf << str
337
+ req = @parser.env
338
+ assert_equal req, @parser.parse
339
+ assert_equal "", buf
340
+ tmp = ''
341
+ body = ''
342
+ str = chunked[0..-2]
343
+ str.each_byte { |byte|
344
+ assert_nil @parser.filter_body(tmp, buf << byte.chr)
345
+ body << tmp
346
+ }
347
+ assert_equal 'abcdefghijklmnop0123456789abcdefg', body
348
+ rv = @parser.filter_body(tmp, buf<< "\n")
349
+ assert_equal rv.object_id, buf.object_id
350
+ assert ! @parser.keepalive?
351
+ end
352
+
353
+ def test_trailers
354
+ req = @parser.env
355
+ str = @parser.buf
356
+ str << "PUT / HTTP/1.1\r\n" \
357
+ "Trailer: Content-MD5\r\n" \
358
+ "transfer-Encoding: chunked\r\n\r\n" \
359
+ "1\r\na\r\n2\r\n..\r\n0\r\n"
360
+ assert_equal req, @parser.parse
361
+ assert_equal 'Content-MD5', req['HTTP_TRAILER']
362
+ assert_nil req['HTTP_CONTENT_MD5']
363
+ tmp = ''
364
+ assert_nil @parser.filter_body(tmp, str)
365
+ assert_equal 'a..', tmp
366
+ md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
367
+ rv = @parser.filter_body(tmp, str)
368
+ assert_equal rv.object_id, str.object_id
369
+ assert_equal '', str
370
+ md5_hdr = "Content-MD5: #{md5_b64}\r\n".freeze
371
+ str << md5_hdr
372
+ assert_nil @parser.trailers(req, str)
373
+ assert_equal md5_b64, req['HTTP_CONTENT_MD5']
374
+ assert_equal "CONTENT_MD5: #{md5_b64}\r\n", str
375
+ str << "\r"
376
+ assert_nil @parser.parse
377
+ str << "\nGET / "
378
+ assert_equal req, @parser.parse
379
+ assert_equal "GET / ", str
380
+ assert @parser.keepalive?
381
+ end
382
+
383
+ def test_trailers_slowly
384
+ str = @parser.buf
385
+ str << "PUT / HTTP/1.1\r\n" \
386
+ "Trailer: Content-MD5\r\n" \
387
+ "transfer-Encoding: chunked\r\n\r\n" \
388
+ "1\r\na\r\n2\r\n..\r\n0\r\n"
389
+ req = @parser.env
390
+ assert_equal req, @parser.parse
391
+ assert_equal 'Content-MD5', req['HTTP_TRAILER']
392
+ assert_nil req['HTTP_CONTENT_MD5']
393
+ tmp = ''
394
+ assert_nil @parser.filter_body(tmp, str)
395
+ assert_equal 'a..', tmp
396
+ md5_b64 = [ Digest::MD5.digest(tmp) ].pack('m').strip.freeze
397
+ rv = @parser.filter_body(tmp, str)
398
+ assert_equal rv.object_id, str.object_id
399
+ assert_equal '', str
400
+ assert_nil @parser.trailers(req, str)
401
+ md5_hdr = "Content-MD5: #{md5_b64}\r\n".freeze
402
+ md5_hdr.each_byte { |byte|
403
+ str << byte.chr
404
+ assert_nil @parser.trailers(req, str)
405
+ }
406
+ assert_equal md5_b64, req['HTTP_CONTENT_MD5']
407
+ assert_equal "CONTENT_MD5: #{md5_b64}\r\n", str
408
+ str << "\r"
409
+ assert_nil @parser.parse
410
+ str << "\n"
411
+ assert_equal req, @parser.parse
412
+ end
413
+
414
+ def test_max_chunk
415
+ str = @parser.buf
416
+ str << "PUT / HTTP/1.1\r\n" \
417
+ "transfer-Encoding: chunked\r\n\r\n" \
418
+ "#{HttpParser::CHUNK_MAX.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
419
+ req = @parser.env
420
+ assert_equal req, @parser.parse
421
+ assert_nil @parser.content_length
422
+ assert_nothing_raised { @parser.filter_body('', str) }
423
+ assert ! @parser.keepalive?
424
+ end
425
+
426
+ def test_max_body
427
+ n = HttpParser::LENGTH_MAX
428
+ @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
429
+ req = @parser.env
430
+ assert_nothing_raised { @parser.headers(req, @parser.buf) }
431
+ assert_equal n, req['CONTENT_LENGTH'].to_i
432
+ assert ! @parser.keepalive?
433
+ end
434
+
435
+ def test_overflow_chunk
436
+ n = HttpParser::CHUNK_MAX + 1
437
+ str = @parser.buf
438
+ req = @parser.env
439
+ str << "PUT / HTTP/1.1\r\n" \
440
+ "transfer-Encoding: chunked\r\n\r\n" \
441
+ "#{n.to_s(16)}\r\na\r\n2\r\n..\r\n0\r\n"
442
+ assert_equal req, @parser.parse
443
+ assert_nil @parser.content_length
444
+ assert_raise(HttpParserError) { @parser.filter_body('', str) }
445
+ end
446
+
447
+ def test_overflow_content_length
448
+ n = HttpParser::LENGTH_MAX + 1
449
+ @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: #{n}\r\n\r\n"
450
+ assert_raise(HttpParserError) { @parser.parse }
451
+ end
452
+
453
+ def test_bad_chunk
454
+ @parser.buf << "PUT / HTTP/1.1\r\n" \
455
+ "transfer-Encoding: chunked\r\n\r\n" \
456
+ "#zzz\r\na\r\n2\r\n..\r\n0\r\n"
457
+ req = @parser.env
458
+ assert_equal req, @parser.parse
459
+ assert_nil @parser.content_length
460
+ assert_raise(HttpParserError) { @parser.filter_body("", @parser.buf) }
461
+ end
462
+
463
+ def test_bad_content_length
464
+ @parser.buf << "PUT / HTTP/1.1\r\nContent-Length: 7ff\r\n\r\n"
465
+ assert_raise(HttpParserError) { @parser.parse }
466
+ end
467
+
468
+ def test_bad_trailers
469
+ str = @parser.buf
470
+ req = @parser.env
471
+ str << "PUT / HTTP/1.1\r\n" \
472
+ "Trailer: Transfer-Encoding\r\n" \
473
+ "transfer-Encoding: chunked\r\n\r\n" \
474
+ "1\r\na\r\n2\r\n..\r\n0\r\n"
475
+ assert_equal req, @parser.parse
476
+ assert_equal 'Transfer-Encoding', req['HTTP_TRAILER']
477
+ tmp = ''
478
+ assert_nil @parser.filter_body(tmp, str)
479
+ assert_equal 'a..', tmp
480
+ assert_equal '', str
481
+ str << "Transfer-Encoding: identity\r\n\r\n"
482
+ assert_raise(HttpParserError) { @parser.parse }
483
+ end
484
+
485
+ def test_repeat_headers
486
+ str = "PUT / HTTP/1.1\r\n" \
487
+ "Trailer: Content-MD5\r\n" \
488
+ "Trailer: Content-SHA1\r\n" \
489
+ "transfer-Encoding: chunked\r\n\r\n" \
490
+ "1\r\na\r\n2\r\n..\r\n0\r\n"
491
+ req = @parser.env
492
+ @parser.buf << str
493
+ assert_equal req, @parser.parse
494
+ assert_equal 'Content-MD5,Content-SHA1', req['HTTP_TRAILER']
495
+ assert ! @parser.keepalive?
496
+ end
497
+
498
+ def test_parse_simple_request
499
+ parser = HttpParser.new
500
+ req = parser.env
501
+ parser.buf << "GET /read-rfc1945-if-you-dont-believe-me\r\n"
502
+ assert_equal req, parser.parse
503
+ assert_equal '', parser.buf
504
+ expect = {
505
+ "SERVER_NAME"=>"localhost",
506
+ "rack.url_scheme"=>"http",
507
+ "REQUEST_PATH"=>"/read-rfc1945-if-you-dont-believe-me",
508
+ "PATH_INFO"=>"/read-rfc1945-if-you-dont-believe-me",
509
+ "REQUEST_URI"=>"/read-rfc1945-if-you-dont-believe-me",
510
+ "SERVER_PORT"=>"80",
511
+ "SERVER_PROTOCOL"=>"HTTP/0.9",
512
+ "REQUEST_METHOD"=>"GET",
513
+ "QUERY_STRING"=>""
514
+ }
515
+ assert_equal expect, req
516
+ assert ! parser.headers?
517
+ end
518
+
519
+ def test_path_info_semicolon
520
+ qs = "QUERY_STRING"
521
+ pi = "PATH_INFO"
522
+ req = {}
523
+ str = "GET %s HTTP/1.1\r\nHost: example.com\r\n\r\n"
524
+ {
525
+ "/1;a=b?c=d&e=f" => { qs => "c=d&e=f", pi => "/1;a=b" },
526
+ "/1?c=d&e=f" => { qs => "c=d&e=f", pi => "/1" },
527
+ "/1;a=b" => { qs => "", pi => "/1;a=b" },
528
+ "/1;a=b?" => { qs => "", pi => "/1;a=b" },
529
+ "/1?a=b;c=d&e=f" => { qs => "a=b;c=d&e=f", pi => "/1" },
530
+ "*" => { qs => "", pi => "" },
531
+ }.each do |uri,expect|
532
+ assert_equal req, @parser.headers(req.clear, str % [ uri ])
533
+ req = req.dup
534
+ @parser.clear
535
+ assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
536
+ assert_equal expect[qs], req[qs], "#{qs} mismatch"
537
+ assert_equal expect[pi], req[pi], "#{pi} mismatch"
538
+ next if uri == "*"
539
+ uri = URI.parse("http://example.com#{uri}")
540
+ assert_equal uri.query.to_s, req[qs], "#{qs} mismatch URI.parse disagrees"
541
+ assert_equal uri.path, req[pi], "#{pi} mismatch URI.parse disagrees"
542
+ end
543
+ end
544
+
545
+ def test_path_info_semicolon_absolute
546
+ qs = "QUERY_STRING"
547
+ pi = "PATH_INFO"
548
+ req = {}
549
+ str = "GET http://example.com%s HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
550
+ {
551
+ "/1;a=b?c=d&e=f" => { qs => "c=d&e=f", pi => "/1;a=b" },
552
+ "/1?c=d&e=f" => { qs => "c=d&e=f", pi => "/1" },
553
+ "/1;a=b" => { qs => "", pi => "/1;a=b" },
554
+ "/1;a=b?" => { qs => "", pi => "/1;a=b" },
555
+ "/1?a=b;c=d&e=f" => { qs => "a=b;c=d&e=f", pi => "/1" },
556
+ }.each do |uri,expect|
557
+ assert_equal req, @parser.headers(req.clear, str % [ uri ])
558
+ req = req.dup
559
+ @parser.clear
560
+ assert_equal uri, req["REQUEST_URI"], "REQUEST_URI mismatch"
561
+ assert_equal "example.com", req["HTTP_HOST"], "Host: mismatch"
562
+ assert_equal expect[qs], req[qs], "#{qs} mismatch"
563
+ assert_equal expect[pi], req[pi], "#{pi} mismatch"
564
+ end
565
+ end
566
+
567
+ def test_negative_content_length
568
+ req = {}
569
+ str = "PUT / HTTP/1.1\r\n" \
570
+ "Content-Length: -1\r\n" \
571
+ "\r\n"
572
+ assert_raises(HttpParserError) do
573
+ @parser.headers(req, str)
574
+ end
575
+ end
576
+
577
+ def test_invalid_content_length
578
+ req = {}
579
+ str = "PUT / HTTP/1.1\r\n" \
580
+ "Content-Length: zzzzz\r\n" \
581
+ "\r\n"
582
+ assert_raises(HttpParserError) do
583
+ @parser.headers(req, str)
584
+ end
585
+ end
586
+
587
+ def test_backtrace_is_empty
588
+ begin
589
+ @parser.headers({}, "AAADFSFDSFD\r\n\r\n")
590
+ assert false, "should never get here line:#{__LINE__}"
591
+ rescue HttpParserError => e
592
+ assert_equal [], e.backtrace
593
+ return
594
+ end
595
+ assert false, "should never get here line:#{__LINE__}"
596
+ end
597
+
598
+ def test_ignore_version_header
599
+ @parser.buf << "GET / HTTP/1.1\r\nVersion: hello\r\n\r\n"
600
+ req = @parser.env
601
+ assert_equal req, @parser.parse
602
+ assert_equal '', @parser.buf
603
+ expect = {
604
+ "SERVER_NAME" => "localhost",
605
+ "rack.url_scheme" => "http",
606
+ "REQUEST_PATH" => "/",
607
+ "SERVER_PROTOCOL" => "HTTP/1.1",
608
+ "PATH_INFO" => "/",
609
+ "HTTP_VERSION" => "HTTP/1.1",
610
+ "REQUEST_URI" => "/",
611
+ "SERVER_PORT" => "80",
612
+ "REQUEST_METHOD" => "GET",
613
+ "QUERY_STRING" => ""
614
+ }
615
+ assert_equal expect, req
616
+ end
617
+
618
+ def test_pipelined_requests
619
+ host = "example.com"
620
+ expect = {
621
+ "HTTP_HOST" => host,
622
+ "SERVER_NAME" => host,
623
+ "REQUEST_PATH" => "/",
624
+ "rack.url_scheme" => "http",
625
+ "SERVER_PROTOCOL" => "HTTP/1.1",
626
+ "PATH_INFO" => "/",
627
+ "HTTP_VERSION" => "HTTP/1.1",
628
+ "REQUEST_URI" => "/",
629
+ "SERVER_PORT" => "80",
630
+ "REQUEST_METHOD" => "GET",
631
+ "QUERY_STRING" => ""
632
+ }
633
+ req1 = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
634
+ req2 = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"
635
+ @parser.buf << (req1 + req2)
636
+ env1 = @parser.parse.dup
637
+ assert_equal expect, env1
638
+ assert_equal req2, @parser.buf
639
+ assert ! @parser.env.empty?
640
+ assert @parser.next?
641
+ assert @parser.keepalive?
642
+ assert @parser.headers?
643
+ assert_equal expect, @parser.env
644
+ env2 = @parser.parse.dup
645
+ host.replace "www.example.com"
646
+ assert_equal "www.example.com", expect["HTTP_HOST"]
647
+ assert_equal "www.example.com", expect["SERVER_NAME"]
648
+ assert_equal expect, env2
649
+ assert_equal "", @parser.buf
650
+ end
651
+
652
+ def test_keepalive_requests_disabled
653
+ req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".freeze
654
+ expect = {
655
+ "SERVER_NAME" => "example.com",
656
+ "HTTP_HOST" => "example.com",
657
+ "rack.url_scheme" => "http",
658
+ "REQUEST_PATH" => "/",
659
+ "SERVER_PROTOCOL" => "HTTP/1.1",
660
+ "PATH_INFO" => "/",
661
+ "HTTP_VERSION" => "HTTP/1.1",
662
+ "REQUEST_URI" => "/",
663
+ "SERVER_PORT" => "80",
664
+ "REQUEST_METHOD" => "GET",
665
+ "QUERY_STRING" => ""
666
+ }.freeze
667
+ HttpParser.keepalive_requests = 0
668
+ @parser = HttpParser.new
669
+ @parser.buf << req
670
+ assert_equal expect, @parser.parse
671
+ assert ! @parser.next?
672
+ end
673
+
674
+ def test_chunk_only
675
+ tmp = ""
676
+ assert_equal @parser, @parser.dechunk!
677
+ assert_nil @parser.filter_body(tmp, "6\r\n")
678
+ assert_equal "", tmp
679
+ assert_nil @parser.filter_body(tmp, "abcdef")
680
+ assert_equal "abcdef", tmp
681
+ assert_nil @parser.filter_body(tmp, "\r\n")
682
+ assert_equal "", tmp
683
+ src = "0\r\n\r\n"
684
+ assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
685
+ assert_equal "", tmp
686
+ end
687
+
688
+ def test_chunk_only_bad_align
689
+ tmp = ""
690
+ assert_equal @parser, @parser.dechunk!
691
+ assert_nil @parser.filter_body(tmp, "6\r\na")
692
+ assert_equal "a", tmp
693
+ assert_nil @parser.filter_body(tmp, "bcde")
694
+ assert_equal "bcde", tmp
695
+ assert_nil @parser.filter_body(tmp, "f\r")
696
+ assert_equal "f", tmp
697
+ src = "\n0\r\n\r\n"
698
+ assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
699
+ assert_equal "", tmp
700
+ end
701
+
702
+ def test_chunk_only_reset_ok
703
+ tmp = ""
704
+ assert_equal @parser, @parser.dechunk!
705
+ src = "1\r\na\r\n0\r\n\r\n"
706
+ assert_nil @parser.filter_body(tmp, src)
707
+ assert_equal "a", tmp
708
+ assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
709
+
710
+ assert_equal @parser, @parser.dechunk!
711
+ src = "0\r\n\r\n"
712
+ assert_equal src.object_id, @parser.filter_body(tmp, src).object_id
713
+ assert_equal "", tmp
714
+ assert_equal src, @parser.filter_body(tmp, src)
715
+ end
716
+ end