unicorn 3.3.1 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,24 +7,11 @@ require 'tmpdir'
7
7
 
8
8
  default_port = 8080
9
9
  addr = ENV['UNICORN_TEST_ADDR'] || '127.0.0.1'
10
- retries = 100
11
- base = 5000
12
10
  port = sock = lock_path = nil
13
11
 
14
12
  begin
15
- begin
16
- port = base + rand(32768 - base)
17
- while port == default_port
18
- port = base + rand(32768 - base)
19
- end
20
-
21
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
22
- sock.bind(Socket.pack_sockaddr_in(port, addr))
23
- sock.listen(5)
24
- rescue Errno::EADDRINUSE, Errno::EACCES
25
- sock.close rescue nil
26
- retry if (retries -= 1) >= 0
27
- end
13
+ sock = TCPServer.new(addr, 0)
14
+ port = sock.addr[1]
28
15
 
29
16
  # since we'll end up closing the random port we just got, there's a race
30
17
  # condition could allow the random port we just chose to reselect itself
@@ -797,7 +797,6 @@ EOF
797
797
 
798
798
  def test_daemonize_redirect_fail
799
799
  pid_file = "#{@tmpdir}/test.pid"
800
- log = Tempfile.new('unicorn_test_log')
801
800
  ucfg = Tempfile.new('unicorn_test_config')
802
801
  ucfg.syswrite("pid #{pid_file}\"\n")
803
802
  err = Tempfile.new('stderr')
@@ -1040,7 +1039,7 @@ EOF
1040
1039
  lock_path = "#{Dir::tmpdir}/unicorn_test." \
1041
1040
  "#{Unicorn::Const::DEFAULT_LISTEN}.lock"
1042
1041
  begin
1043
- lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
1042
+ File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
1044
1043
  yield
1045
1044
  rescue Errno::EEXIST
1046
1045
  lock_path = nil
@@ -265,7 +265,7 @@ logger Logger.new('#{COMMON_TMP.path}')
265
265
 
266
266
  if @pid
267
267
  Process.kill(:QUIT, @pid)
268
- pid2, status = Process.waitpid2(@pid)
268
+ _, status = Process.waitpid2(@pid)
269
269
  assert status.success?
270
270
  end
271
271
 
@@ -100,30 +100,17 @@ end
100
100
  # for a race condition is very small). You may also set UNICORN_TEST_ADDR
101
101
  # to override the default test address (127.0.0.1).
102
102
  def unused_port(addr = '127.0.0.1')
103
- retries = 100
104
- base = 5000
105
103
  port = sock = nil
106
104
  begin
107
- begin
108
- port = base + rand(32768 - base)
109
- while port == Unicorn::Const::DEFAULT_PORT
110
- port = base + rand(32768 - base)
111
- end
112
-
113
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
114
- sock.bind(Socket.pack_sockaddr_in(port, addr))
115
- sock.listen(5)
116
- rescue Errno::EADDRINUSE, Errno::EACCES
117
- sock.close rescue nil
118
- retry if (retries -= 1) >= 0
119
- end
105
+ sock = TCPServer.new(addr, 0)
106
+ port = sock.addr[1]
120
107
 
121
108
  # since we'll end up closing the random port we just got, there's a race
122
109
  # condition could allow the random port we just chose to reselect itself
123
110
  # when running tests in parallel with gmake. Create a lock file while
124
111
  # we have the port here to ensure that does not happen .
125
112
  lock_path = "#{Dir::tmpdir}/unicorn_test.#{addr}:#{port}.lock"
126
- lock = File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
113
+ File.open(lock_path, File::WRONLY|File::CREAT|File::EXCL, 0600)
127
114
  at_exit { File.unlink(lock_path) rescue nil }
128
115
  rescue Errno::EEXIST
129
116
  sock.close rescue nil
@@ -33,6 +33,14 @@ class TestConfigurator < Test::Unit::TestCase
33
33
  assert_equal "0.0.0.0:2007", meth.call('2007')
34
34
  assert_equal "0.0.0.0:2007", meth.call(2007)
35
35
 
36
+ %w([::1]:2007 [::]:2007).each do |addr|
37
+ assert_equal addr, meth.call(addr.dup)
38
+ end
39
+
40
+ # for Rainbows! users only
41
+ assert_equal "[::]:80", meth.call("[::]")
42
+ assert_equal "127.6.6.6:80", meth.call("127.6.6.6")
43
+
36
44
  # the next two aren't portable, consider them unsupported for now
37
45
  # assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('1:2007')
38
46
  # assert_match %r{\A\d+\.\d+\.\d+\.\d+:2007\z}, meth.call('2:2007')
@@ -14,9 +14,10 @@ class HttpParserTest < Test::Unit::TestCase
14
14
 
15
15
  def test_parse_simple
16
16
  parser = HttpParser.new
17
- req = {}
18
- http = "GET / HTTP/1.1\r\n\r\n"
19
- assert_equal req, parser.headers(req, http)
17
+ req = parser.env
18
+ http = parser.buf
19
+ http << "GET / HTTP/1.1\r\n\r\n"
20
+ assert_equal req, parser.parse
20
21
  assert_equal '', http
21
22
 
22
23
  assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL']
@@ -31,14 +32,14 @@ class HttpParserTest < Test::Unit::TestCase
31
32
  parser.clear
32
33
  req.clear
33
34
 
34
- http = "G"
35
- assert_nil parser.headers(req, http)
35
+ http << "G"
36
+ assert_nil parser.parse
36
37
  assert_equal "G", http
37
38
  assert req.empty?
38
39
 
39
40
  # try parsing again to ensure we were reset correctly
40
- http = "GET /hello-world HTTP/1.1\r\n\r\n"
41
- assert parser.headers(req, http)
41
+ http << "ET /hello-world HTTP/1.1\r\n\r\n"
42
+ assert parser.parse
42
43
 
43
44
  assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL']
44
45
  assert_equal '/hello-world', req['REQUEST_PATH']
@@ -53,161 +54,161 @@ class HttpParserTest < Test::Unit::TestCase
53
54
 
54
55
  def test_tab_lws
55
56
  parser = HttpParser.new
56
- req = {}
57
- tmp = "GET / HTTP/1.1\r\nHost:\tfoo.bar\r\n\r\n"
58
- assert_equal req.object_id, parser.headers(req, tmp).object_id
57
+ req = parser.env
58
+ parser.buf << "GET / HTTP/1.1\r\nHost:\tfoo.bar\r\n\r\n"
59
+ assert_equal req.object_id, parser.parse.object_id
59
60
  assert_equal "foo.bar", req['HTTP_HOST']
60
61
  end
61
62
 
62
63
  def test_connection_close_no_ka
63
64
  parser = HttpParser.new
64
- req = {}
65
- tmp = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
66
- assert_equal req.object_id, parser.headers(req, tmp).object_id
65
+ req = parser.env
66
+ parser.buf << "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"
67
+ assert_equal req.object_id, parser.parse.object_id
67
68
  assert_equal "GET", req['REQUEST_METHOD']
68
69
  assert ! parser.keepalive?
69
70
  end
70
71
 
71
72
  def test_connection_keep_alive_ka
72
73
  parser = HttpParser.new
73
- req = {}
74
- tmp = "HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
75
- assert_equal req.object_id, parser.headers(req, tmp).object_id
74
+ req = parser.env
75
+ parser.buf << "HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
76
+ assert_equal req.object_id, parser.parse.object_id
76
77
  assert parser.keepalive?
77
78
  end
78
79
 
79
80
  def test_connection_keep_alive_no_body
80
81
  parser = HttpParser.new
81
- req = {}
82
- tmp = "POST / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
83
- assert_equal req.object_id, parser.headers(req, tmp).object_id
82
+ req = parser.env
83
+ parser.buf << "POST / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"
84
+ assert_equal req.object_id, parser.parse.object_id
84
85
  assert parser.keepalive?
85
86
  end
86
87
 
87
88
  def test_connection_keep_alive_no_body_empty
88
89
  parser = HttpParser.new
89
- req = {}
90
- tmp = "POST / HTTP/1.1\r\n" \
91
- "Content-Length: 0\r\n" \
92
- "Connection: keep-alive\r\n\r\n"
93
- assert_equal req.object_id, parser.headers(req, tmp).object_id
90
+ req = parser.env
91
+ parser.buf << "POST / HTTP/1.1\r\n" \
92
+ "Content-Length: 0\r\n" \
93
+ "Connection: keep-alive\r\n\r\n"
94
+ assert_equal req.object_id, parser.parse.object_id
94
95
  assert parser.keepalive?
95
96
  end
96
97
 
97
98
  def test_connection_keep_alive_ka_bad_version
98
99
  parser = HttpParser.new
99
- req = {}
100
- tmp = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"
101
- assert_equal req.object_id, parser.headers(req, tmp).object_id
100
+ req = parser.env
101
+ parser.buf << "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"
102
+ assert_equal req.object_id, parser.parse.object_id
102
103
  assert parser.keepalive?
103
104
  end
104
105
 
105
106
  def test_parse_server_host_default_port
106
107
  parser = HttpParser.new
107
- req = {}
108
- tmp = "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"
109
- assert_equal req, parser.headers(req, tmp)
108
+ req = parser.env
109
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"
110
+ assert_equal req, parser.parse
110
111
  assert_equal 'foo', req['SERVER_NAME']
111
112
  assert_equal '80', req['SERVER_PORT']
112
- assert_equal '', tmp
113
+ assert_equal '', parser.buf
113
114
  assert parser.keepalive?
114
115
  end
115
116
 
116
117
  def test_parse_server_host_alt_port
117
118
  parser = HttpParser.new
118
- req = {}
119
- tmp = "GET / HTTP/1.1\r\nHost: foo:999\r\n\r\n"
120
- assert_equal req, parser.headers(req, tmp)
119
+ req = parser.env
120
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo:999\r\n\r\n"
121
+ assert_equal req, parser.parse
121
122
  assert_equal 'foo', req['SERVER_NAME']
122
123
  assert_equal '999', req['SERVER_PORT']
123
- assert_equal '', tmp
124
+ assert_equal '', parser.buf
124
125
  assert parser.keepalive?
125
126
  end
126
127
 
127
128
  def test_parse_server_host_empty_port
128
129
  parser = HttpParser.new
129
- req = {}
130
- tmp = "GET / HTTP/1.1\r\nHost: foo:\r\n\r\n"
131
- assert_equal req, parser.headers(req, tmp)
130
+ req = parser.env
131
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n\r\n"
132
+ assert_equal req, parser.parse
132
133
  assert_equal 'foo', req['SERVER_NAME']
133
134
  assert_equal '80', req['SERVER_PORT']
134
- assert_equal '', tmp
135
+ assert_equal '', parser.buf
135
136
  assert parser.keepalive?
136
137
  end
137
138
 
138
139
  def test_parse_server_host_xfp_https
139
140
  parser = HttpParser.new
140
- req = {}
141
- tmp = "GET / HTTP/1.1\r\nHost: foo:\r\n" \
142
- "X-Forwarded-Proto: https\r\n\r\n"
143
- assert_equal req, parser.headers(req, tmp)
141
+ req = parser.env
142
+ parser.buf << "GET / HTTP/1.1\r\nHost: foo:\r\n" \
143
+ "X-Forwarded-Proto: https\r\n\r\n"
144
+ assert_equal req, parser.parse
144
145
  assert_equal 'foo', req['SERVER_NAME']
145
146
  assert_equal '443', req['SERVER_PORT']
146
- assert_equal '', tmp
147
+ assert_equal '', parser.buf
147
148
  assert parser.keepalive?
148
149
  end
149
150
 
150
151
  def test_parse_xfp_https_chained
151
152
  parser = HttpParser.new
152
- req = {}
153
- tmp = "GET / HTTP/1.0\r\n" \
154
- "X-Forwarded-Proto: https,http\r\n\r\n"
155
- assert_equal req, parser.headers(req, tmp)
153
+ req = parser.env
154
+ parser.buf << "GET / HTTP/1.0\r\n" \
155
+ "X-Forwarded-Proto: https,http\r\n\r\n"
156
+ assert_equal req, parser.parse
156
157
  assert_equal '443', req['SERVER_PORT'], req.inspect
157
158
  assert_equal 'https', req['rack.url_scheme'], req.inspect
158
- assert_equal '', tmp
159
+ assert_equal '', parser.buf
159
160
  end
160
161
 
161
162
  def test_parse_xfp_https_chained_backwards
162
163
  parser = HttpParser.new
163
- req = {}
164
- tmp = "GET / HTTP/1.0\r\n" \
164
+ req = parser.env
165
+ parser.buf << "GET / HTTP/1.0\r\n" \
165
166
  "X-Forwarded-Proto: http,https\r\n\r\n"
166
- assert_equal req, parser.headers(req, tmp)
167
+ assert_equal req, parser.parse
167
168
  assert_equal '80', req['SERVER_PORT'], req.inspect
168
169
  assert_equal 'http', req['rack.url_scheme'], req.inspect
169
- assert_equal '', tmp
170
+ assert_equal '', parser.buf
170
171
  end
171
172
 
172
173
  def test_parse_xfp_gopher_is_ignored
173
174
  parser = HttpParser.new
174
- req = {}
175
- tmp = "GET / HTTP/1.0\r\n" \
176
- "X-Forwarded-Proto: gopher\r\n\r\n"
177
- assert_equal req, parser.headers(req, tmp)
175
+ req = parser.env
176
+ parser.buf << "GET / HTTP/1.0\r\n" \
177
+ "X-Forwarded-Proto: gopher\r\n\r\n"
178
+ assert_equal req, parser.parse
178
179
  assert_equal '80', req['SERVER_PORT'], req.inspect
179
180
  assert_equal 'http', req['rack.url_scheme'], req.inspect
180
- assert_equal '', tmp
181
+ assert_equal '', parser.buf
181
182
  end
182
183
 
183
184
  def test_parse_x_forwarded_ssl_on
184
185
  parser = HttpParser.new
185
- req = {}
186
- tmp = "GET / HTTP/1.0\r\n" \
187
- "X-Forwarded-Ssl: on\r\n\r\n"
188
- assert_equal req, parser.headers(req, tmp)
186
+ req = parser.env
187
+ parser.buf << "GET / HTTP/1.0\r\n" \
188
+ "X-Forwarded-Ssl: on\r\n\r\n"
189
+ assert_equal req, parser.parse
189
190
  assert_equal '443', req['SERVER_PORT'], req.inspect
190
191
  assert_equal 'https', req['rack.url_scheme'], req.inspect
191
- assert_equal '', tmp
192
+ assert_equal '', parser.buf
192
193
  end
193
194
 
194
195
  def test_parse_x_forwarded_ssl_off
195
196
  parser = HttpParser.new
196
- req = {}
197
- tmp = "GET / HTTP/1.0\r\n" \
198
- "X-Forwarded-Ssl: off\r\n\r\n"
199
- assert_equal req, parser.headers(req, tmp)
197
+ req = parser.env
198
+ parser.buf << "GET / HTTP/1.0\r\nX-Forwarded-Ssl: off\r\n\r\n"
199
+ assert_equal req, parser.parse
200
200
  assert_equal '80', req['SERVER_PORT'], req.inspect
201
201
  assert_equal 'http', req['rack.url_scheme'], req.inspect
202
- assert_equal '', tmp
202
+ assert_equal '', parser.buf
203
203
  end
204
204
 
205
205
  def test_parse_strange_headers
206
206
  parser = HttpParser.new
207
- req = {}
207
+ req = parser.env
208
208
  should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
209
- assert_equal req, parser.headers(req, should_be_good)
210
- assert_equal '', should_be_good
209
+ parser.buf << should_be_good
210
+ assert_equal req, parser.parse
211
+ assert_equal '', parser.buf
211
212
  assert parser.keepalive?
212
213
  end
213
214
 
@@ -217,14 +218,14 @@ class HttpParserTest < Test::Unit::TestCase
217
218
  def test_nasty_pound_header
218
219
  parser = HttpParser.new
219
220
  nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n"
220
- req = {}
221
- buf = nasty_pound_header.dup
221
+ req = parser.env
222
+ parser.buf << nasty_pound_header.dup
222
223
 
223
224
  assert nasty_pound_header =~ /(-----BEGIN .*--END CERTIFICATE-----)/m
224
225
  expect = $1.dup
225
226
  expect.gsub!(/\r\n\t/, ' ')
226
- assert_equal req, parser.headers(req, buf)
227
- assert_equal '', buf
227
+ assert_equal req, parser.parse
228
+ assert_equal '', parser.buf
228
229
  assert_equal expect, req['HTTP_X_SSL_BULLSHIT']
229
230
  end
230
231
 
@@ -235,9 +236,10 @@ class HttpParserTest < Test::Unit::TestCase
235
236
  "\t\r\n" \
236
237
  " \r\n" \
237
238
  " ASDF\r\n\r\n"
238
- req = {}
239
- assert_equal req, parser.headers(req, header)
240
- assert_equal '', header
239
+ parser.buf << header
240
+ req = parser.env
241
+ assert_equal req, parser.parse
242
+ assert_equal '', parser.buf
241
243
  assert_equal 'ASDF', req['HTTP_X_ASDF']
242
244
  end
243
245
 
@@ -249,9 +251,10 @@ class HttpParserTest < Test::Unit::TestCase
249
251
  "\t\r\n" \
250
252
  " x\r\n" \
251
253
  " ASDF\r\n\r\n"
252
- req = {}
253
- assert_equal req, parser.headers(req, header)
254
- assert_equal '', header
254
+ req = parser.env
255
+ parser.buf << header
256
+ assert_equal req, parser.parse
257
+ assert_equal '', parser.buf
255
258
  assert_equal 'hi y x ASDF', req['HTTP_X_ASDF']
256
259
  end
257
260
 
@@ -261,8 +264,9 @@ class HttpParserTest < Test::Unit::TestCase
261
264
  "Host: \r\n" \
262
265
  " YHBT.net\r\n" \
263
266
  "\r\n"
264
- req = {}
265
- assert_equal req, parser.headers(req, header)
267
+ parser.buf << header
268
+ req = parser.env
269
+ assert_equal req, parser.parse
266
270
  assert_equal 'example.com', req['HTTP_HOST']
267
271
  end
268
272
 
@@ -271,21 +275,22 @@ class HttpParserTest < Test::Unit::TestCase
271
275
  # in case we ever go multithreaded/evented...
272
276
  def test_resumable_continuations
273
277
  nr = 1000
274
- req = {}
275
278
  header = "GET / HTTP/1.1\r\n" \
276
279
  "X-ASDF: \r\n" \
277
280
  " hello\r\n"
278
281
  tmp = []
279
282
  nr.times { |i|
280
283
  parser = HttpParser.new
281
- assert parser.headers(req, "#{header} #{i}\r\n").nil?
284
+ req = parser.env
285
+ parser.buf << "#{header} #{i}\r\n"
286
+ assert parser.parse.nil?
282
287
  asdf = req['HTTP_X_ASDF']
283
288
  assert_equal "hello #{i}", asdf
284
289
  tmp << [ parser, asdf ]
285
- req.clear
286
290
  }
287
291
  tmp.each_with_index { |(parser, asdf), i|
288
- assert_equal req, parser.headers(req, "#{header} #{i}\r\n .\r\n\r\n")
292
+ parser.buf << " .\r\n\r\n"
293
+ assert parser.parse
289
294
  assert_equal "hello #{i} .", asdf
290
295
  }
291
296
  end
@@ -296,8 +301,9 @@ class HttpParserTest < Test::Unit::TestCase
296
301
  " y\r\n" \
297
302
  "Host: hello\r\n" \
298
303
  "\r\n"
299
- req = {}
300
- assert_raises(HttpParserError) { parser.headers(req, header) }
304
+ parser.buf << header
305
+ req = parser.env
306
+ assert_raises(HttpParserError) { parser.parse }
301
307
  end
302
308
 
303
309
  def test_parse_ie6_urls
@@ -309,7 +315,7 @@ class HttpParserTest < Test::Unit::TestCase
309
315
  /mal"formed"?
310
316
  ).each do |path|
311
317
  parser = HttpParser.new
312
- req = {}
318
+ req = parser.env
313
319
  sorta_safe = %(GET #{path} HTTP/1.1\r\n\r\n)
314
320
  assert_equal req, parser.headers(req, sorta_safe)
315
321
  assert_equal path, req['REQUEST_URI']
@@ -320,7 +326,7 @@ class HttpParserTest < Test::Unit::TestCase
320
326
 
321
327
  def test_parse_error
322
328
  parser = HttpParser.new
323
- req = {}
329
+ req = parser.env
324
330
  bad_http = "GET / SsUTF/1.1"
325
331
 
326
332
  assert_raises(HttpParserError) { parser.headers(req, bad_http) }
@@ -334,7 +340,7 @@ class HttpParserTest < Test::Unit::TestCase
334
340
 
335
341
  def test_piecemeal
336
342
  parser = HttpParser.new
337
- req = {}
343
+ req = parser.env
338
344
  http = "GET"
339
345
  assert_nil parser.headers(req, http)
340
346
  assert_nil parser.headers(req, http)
@@ -356,9 +362,10 @@ class HttpParserTest < Test::Unit::TestCase
356
362
  # not common, but underscores do appear in practice
357
363
  def test_absolute_uri_underscores
358
364
  parser = HttpParser.new
359
- req = {}
365
+ req = parser.env
360
366
  http = "GET http://under_score.example.com/foo?q=bar HTTP/1.0\r\n\r\n"
361
- assert_equal req, parser.headers(req, http)
367
+ parser.buf << http
368
+ assert_equal req, parser.parse
362
369
  assert_equal 'http', req['rack.url_scheme']
363
370
  assert_equal '/foo?q=bar', req['REQUEST_URI']
364
371
  assert_equal '/foo', req['REQUEST_PATH']
@@ -367,16 +374,17 @@ class HttpParserTest < Test::Unit::TestCase
367
374
  assert_equal 'under_score.example.com', req['HTTP_HOST']
368
375
  assert_equal 'under_score.example.com', req['SERVER_NAME']
369
376
  assert_equal '80', req['SERVER_PORT']
370
- assert_equal "", http
377
+ assert_equal "", parser.buf
371
378
  assert ! parser.keepalive?
372
379
  end
373
380
 
374
381
  # some dumb clients add users because they're stupid
375
382
  def test_absolute_uri_w_user
376
383
  parser = HttpParser.new
377
- req = {}
384
+ req = parser.env
378
385
  http = "GET http://user%20space@example.com/foo?q=bar HTTP/1.0\r\n\r\n"
379
- assert_equal req, parser.headers(req, http)
386
+ parser.buf << http
387
+ assert_equal req, parser.parse
380
388
  assert_equal 'http', req['rack.url_scheme']
381
389
  assert_equal '/foo?q=bar', req['REQUEST_URI']
382
390
  assert_equal '/foo', req['REQUEST_PATH']
@@ -385,7 +393,7 @@ class HttpParserTest < Test::Unit::TestCase
385
393
  assert_equal 'example.com', req['HTTP_HOST']
386
394
  assert_equal 'example.com', req['SERVER_NAME']
387
395
  assert_equal '80', req['SERVER_PORT']
388
- assert_equal "", http
396
+ assert_equal "", parser.buf
389
397
  assert ! parser.keepalive?
390
398
  end
391
399
 
@@ -394,7 +402,7 @@ class HttpParserTest < Test::Unit::TestCase
394
402
  def test_absolute_uri_uri_parse
395
403
  "#{URI::REGEXP::PATTERN::UNRESERVED};:&=+$,".split(//).each do |char|
396
404
  parser = HttpParser.new
397
- req = {}
405
+ req = parser.env
398
406
  http = "GET http://#{char}@example.com/ HTTP/1.0\r\n\r\n"
399
407
  assert_equal req, parser.headers(req, http)
400
408
  assert_equal 'http', req['rack.url_scheme']
@@ -412,9 +420,9 @@ class HttpParserTest < Test::Unit::TestCase
412
420
 
413
421
  def test_absolute_uri
414
422
  parser = HttpParser.new
415
- req = {}
416
- http = "GET http://example.com/foo?q=bar HTTP/1.0\r\n\r\n"
417
- assert_equal req, parser.headers(req, http)
423
+ req = parser.env
424
+ parser.buf << "GET http://example.com/foo?q=bar HTTP/1.0\r\n\r\n"
425
+ assert_equal req, parser.parse
418
426
  assert_equal 'http', req['rack.url_scheme']
419
427
  assert_equal '/foo?q=bar', req['REQUEST_URI']
420
428
  assert_equal '/foo', req['REQUEST_PATH']
@@ -423,17 +431,18 @@ class HttpParserTest < Test::Unit::TestCase
423
431
  assert_equal 'example.com', req['HTTP_HOST']
424
432
  assert_equal 'example.com', req['SERVER_NAME']
425
433
  assert_equal '80', req['SERVER_PORT']
426
- assert_equal "", http
434
+ assert_equal "", parser.buf
427
435
  assert ! parser.keepalive?
428
436
  end
429
437
 
430
438
  # X-Forwarded-Proto is not in rfc2616, absolute URIs are, however...
431
439
  def test_absolute_uri_https
432
440
  parser = HttpParser.new
433
- req = {}
441
+ req = parser.env
434
442
  http = "GET https://example.com/foo?q=bar HTTP/1.1\r\n" \
435
443
  "X-Forwarded-Proto: http\r\n\r\n"
436
- assert_equal req, parser.headers(req, http)
444
+ parser.buf << http
445
+ assert_equal req, parser.parse
437
446
  assert_equal 'https', req['rack.url_scheme']
438
447
  assert_equal '/foo?q=bar', req['REQUEST_URI']
439
448
  assert_equal '/foo', req['REQUEST_PATH']
@@ -442,17 +451,17 @@ class HttpParserTest < Test::Unit::TestCase
442
451
  assert_equal 'example.com', req['HTTP_HOST']
443
452
  assert_equal 'example.com', req['SERVER_NAME']
444
453
  assert_equal '443', req['SERVER_PORT']
445
- assert_equal "", http
454
+ assert_equal "", parser.buf
446
455
  assert parser.keepalive?
447
456
  end
448
457
 
449
458
  # Host: header should be ignored for absolute URIs
450
459
  def test_absolute_uri_with_port
451
460
  parser = HttpParser.new
452
- req = {}
453
- http = "GET http://example.com:8080/foo?q=bar HTTP/1.2\r\n" \
461
+ req = parser.env
462
+ parser.buf << "GET http://example.com:8080/foo?q=bar HTTP/1.2\r\n" \
454
463
  "Host: bad.example.com\r\n\r\n"
455
- assert_equal req, parser.headers(req, http)
464
+ assert_equal req, parser.parse
456
465
  assert_equal 'http', req['rack.url_scheme']
457
466
  assert_equal '/foo?q=bar', req['REQUEST_URI']
458
467
  assert_equal '/foo', req['REQUEST_PATH']
@@ -461,16 +470,16 @@ class HttpParserTest < Test::Unit::TestCase
461
470
  assert_equal 'example.com:8080', req['HTTP_HOST']
462
471
  assert_equal 'example.com', req['SERVER_NAME']
463
472
  assert_equal '8080', req['SERVER_PORT']
464
- assert_equal "", http
473
+ assert_equal "", parser.buf
465
474
  assert ! parser.keepalive? # TODO: read HTTP/1.2 when it's final
466
475
  end
467
476
 
468
477
  def test_absolute_uri_with_empty_port
469
478
  parser = HttpParser.new
470
- req = {}
471
- http = "GET https://example.com:/foo?q=bar HTTP/1.1\r\n" \
479
+ req = parser.env
480
+ parser.buf << "GET https://example.com:/foo?q=bar HTTP/1.1\r\n" \
472
481
  "Host: bad.example.com\r\n\r\n"
473
- assert_equal req, parser.headers(req, http)
482
+ assert_equal req, parser.parse
474
483
  assert_equal 'https', req['rack.url_scheme']
475
484
  assert_equal '/foo?q=bar', req['REQUEST_URI']
476
485
  assert_equal '/foo', req['REQUEST_PATH']
@@ -479,42 +488,192 @@ class HttpParserTest < Test::Unit::TestCase
479
488
  assert_equal 'example.com:', req['HTTP_HOST']
480
489
  assert_equal 'example.com', req['SERVER_NAME']
481
490
  assert_equal '443', req['SERVER_PORT']
491
+ assert_equal "", parser.buf
492
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
493
+ end
494
+
495
+ def test_absolute_ipv6_uri
496
+ parser = HttpParser.new
497
+ req = parser.env
498
+ url = "http://[::1]/foo?q=bar"
499
+ http = "GET #{url} HTTP/1.1\r\n" \
500
+ "Host: bad.example.com\r\n\r\n"
501
+ assert_equal req, parser.headers(req, http)
502
+ assert_equal 'http', req['rack.url_scheme']
503
+ assert_equal '/foo?q=bar', req['REQUEST_URI']
504
+ assert_equal '/foo', req['REQUEST_PATH']
505
+ assert_equal 'q=bar', req['QUERY_STRING']
506
+
507
+ uri = URI.parse(url)
508
+ assert_equal "[::1]", uri.host,
509
+ "URI.parse changed upstream for #{url}? host=#{uri.host}"
510
+ assert_equal "[::1]", req['HTTP_HOST']
511
+ assert_equal "[::1]", req['SERVER_NAME']
512
+ assert_equal '80', req['SERVER_PORT']
482
513
  assert_equal "", http
483
514
  assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
484
515
  end
485
516
 
486
- def test_put_body_oneshot
517
+ def test_absolute_ipv6_uri_alpha
518
+ parser = HttpParser.new
519
+ req = parser.env
520
+ url = "http://[::a]/"
521
+ http = "GET #{url} HTTP/1.1\r\n" \
522
+ "Host: bad.example.com\r\n\r\n"
523
+ assert_equal req, parser.headers(req, http)
524
+ assert_equal 'http', req['rack.url_scheme']
525
+
526
+ uri = URI.parse(url)
527
+ assert_equal "[::a]", uri.host,
528
+ "URI.parse changed upstream for #{url}? host=#{uri.host}"
529
+ assert_equal "[::a]", req['HTTP_HOST']
530
+ assert_equal "[::a]", req['SERVER_NAME']
531
+ assert_equal '80', req['SERVER_PORT']
532
+ end
533
+
534
+ def test_absolute_ipv6_uri_alpha_2
487
535
  parser = HttpParser.new
488
- req = {}
489
- http = "PUT / HTTP/1.0\r\nContent-Length: 5\r\n\r\nabcde"
536
+ req = parser.env
537
+ url = "http://[::B]/"
538
+ http = "GET #{url} HTTP/1.1\r\n" \
539
+ "Host: bad.example.com\r\n\r\n"
490
540
  assert_equal req, parser.headers(req, http)
541
+ assert_equal 'http', req['rack.url_scheme']
542
+
543
+ uri = URI.parse(url)
544
+ assert_equal "[::B]", uri.host,
545
+ "URI.parse changed upstream for #{url}? host=#{uri.host}"
546
+ assert_equal "[::B]", req['HTTP_HOST']
547
+ assert_equal "[::B]", req['SERVER_NAME']
548
+ assert_equal '80', req['SERVER_PORT']
549
+ end
550
+
551
+ def test_absolute_ipv6_uri_with_empty_port
552
+ parser = HttpParser.new
553
+ req = parser.env
554
+ url = "https://[::1]:/foo?q=bar"
555
+ http = "GET #{url} HTTP/1.1\r\n" \
556
+ "Host: bad.example.com\r\n\r\n"
557
+ assert_equal req, parser.headers(req, http)
558
+ assert_equal 'https', req['rack.url_scheme']
559
+ assert_equal '/foo?q=bar', req['REQUEST_URI']
560
+ assert_equal '/foo', req['REQUEST_PATH']
561
+ assert_equal 'q=bar', req['QUERY_STRING']
562
+
563
+ uri = URI.parse(url)
564
+ assert_equal "[::1]", uri.host,
565
+ "URI.parse changed upstream for #{url}? host=#{uri.host}"
566
+ assert_equal "[::1]:", req['HTTP_HOST']
567
+ assert_equal "[::1]", req['SERVER_NAME']
568
+ assert_equal '443', req['SERVER_PORT']
569
+ assert_equal "", http
570
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
571
+ end
572
+
573
+ def test_absolute_ipv6_uri_with_port
574
+ parser = HttpParser.new
575
+ req = parser.env
576
+ url = "https://[::1]:666/foo?q=bar"
577
+ http = "GET #{url} HTTP/1.1\r\n" \
578
+ "Host: bad.example.com\r\n\r\n"
579
+ assert_equal req, parser.headers(req, http)
580
+ assert_equal 'https', req['rack.url_scheme']
581
+ assert_equal '/foo?q=bar', req['REQUEST_URI']
582
+ assert_equal '/foo', req['REQUEST_PATH']
583
+ assert_equal 'q=bar', req['QUERY_STRING']
584
+
585
+ uri = URI.parse(url)
586
+ assert_equal "[::1]", uri.host,
587
+ "URI.parse changed upstream for #{url}? host=#{uri.host}"
588
+ assert_equal "[::1]:666", req['HTTP_HOST']
589
+ assert_equal "[::1]", req['SERVER_NAME']
590
+ assert_equal '666', req['SERVER_PORT']
591
+ assert_equal "", http
592
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
593
+ end
594
+
595
+ def test_ipv6_host_header
596
+ parser = HttpParser.new
597
+ req = parser.env
598
+ parser.buf << "GET / HTTP/1.1\r\n" \
599
+ "Host: [::1]\r\n\r\n"
600
+ assert_equal req, parser.parse
601
+ assert_equal "[::1]", req['HTTP_HOST']
602
+ assert_equal "[::1]", req['SERVER_NAME']
603
+ assert_equal '80', req['SERVER_PORT']
604
+ assert_equal "", parser.buf
605
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
606
+ end
607
+
608
+ def test_ipv6_host_header_with_port
609
+ parser = HttpParser.new
610
+ req = parser.env
611
+ parser.buf << "GET / HTTP/1.1\r\n" \
612
+ "Host: [::1]:666\r\n\r\n"
613
+ assert_equal req, parser.parse
614
+ assert_equal "[::1]", req['SERVER_NAME']
615
+ assert_equal '666', req['SERVER_PORT']
616
+ assert_equal "[::1]:666", req['HTTP_HOST']
617
+ assert_equal "", parser.buf
618
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
619
+ end
620
+
621
+ def test_ipv6_host_header_with_empty_port
622
+ parser = HttpParser.new
623
+ req = parser.env
624
+ parser.buf << "GET / HTTP/1.1\r\nHost: [::1]:\r\n\r\n"
625
+ assert_equal req, parser.parse
626
+ assert_equal "[::1]", req['SERVER_NAME']
627
+ assert_equal '80', req['SERVER_PORT']
628
+ assert_equal "[::1]:", req['HTTP_HOST']
629
+ assert_equal "", parser.buf
630
+ assert parser.keepalive? # TODO: read HTTP/1.2 when it's final
631
+ end
632
+
633
+ # XXX Highly unlikely..., just make sure we don't segfault or assert on it
634
+ def test_broken_ipv6_host_header
635
+ parser = HttpParser.new
636
+ req = parser.env
637
+ parser.buf << "GET / HTTP/1.1\r\nHost: [::1:\r\n\r\n"
638
+ assert_equal req, parser.parse
639
+ assert_equal "[", req['SERVER_NAME']
640
+ assert_equal ':1:', req['SERVER_PORT']
641
+ assert_equal "[::1:", req['HTTP_HOST']
642
+ assert_equal "", parser.buf
643
+ end
644
+
645
+ def test_put_body_oneshot
646
+ parser = HttpParser.new
647
+ req = parser.env
648
+ parser.buf << "PUT / HTTP/1.0\r\nContent-Length: 5\r\n\r\nabcde"
649
+ assert_equal req, parser.parse
491
650
  assert_equal '/', req['REQUEST_PATH']
492
651
  assert_equal '/', req['REQUEST_URI']
493
652
  assert_equal 'PUT', req['REQUEST_METHOD']
494
653
  assert_equal 'HTTP/1.0', req['HTTP_VERSION']
495
654
  assert_equal 'HTTP/1.0', req['SERVER_PROTOCOL']
496
- assert_equal "abcde", http
655
+ assert_equal "abcde", parser.buf
497
656
  assert ! parser.keepalive? # TODO: read HTTP/1.2 when it's final
498
657
  end
499
658
 
500
659
  def test_put_body_later
501
660
  parser = HttpParser.new
502
- req = {}
503
- http = "PUT /l HTTP/1.0\r\nContent-Length: 5\r\n\r\n"
504
- assert_equal req, parser.headers(req, http)
661
+ req = parser.env
662
+ parser.buf << "PUT /l HTTP/1.0\r\nContent-Length: 5\r\n\r\n"
663
+ assert_equal req, parser.parse
505
664
  assert_equal '/l', req['REQUEST_PATH']
506
665
  assert_equal '/l', req['REQUEST_URI']
507
666
  assert_equal 'PUT', req['REQUEST_METHOD']
508
667
  assert_equal 'HTTP/1.0', req['HTTP_VERSION']
509
668
  assert_equal 'HTTP/1.0', req['SERVER_PROTOCOL']
510
- assert_equal "", http
669
+ assert_equal "", parser.buf
511
670
  assert ! parser.keepalive? # TODO: read HTTP/1.2 when it's final
512
671
  end
513
672
 
514
673
  def test_unknown_methods
515
674
  %w(GETT HEADR XGET XHEAD).each { |m|
516
675
  parser = HttpParser.new
517
- req = {}
676
+ req = parser.env
518
677
  s = "#{m} /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
519
678
  ok = false
520
679
  assert_nothing_raised do
@@ -532,17 +691,18 @@ class HttpParserTest < Test::Unit::TestCase
532
691
 
533
692
  def test_fragment_in_uri
534
693
  parser = HttpParser.new
535
- req = {}
694
+ req = parser.env
536
695
  get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
696
+ parser.buf << get
537
697
  ok = false
538
698
  assert_nothing_raised do
539
- ok = parser.headers(req, get)
699
+ ok = parser.parse
540
700
  end
541
701
  assert ok
542
702
  assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
543
703
  assert_equal 'posts-17408', req['FRAGMENT']
544
704
  assert_equal 'page=1', req['QUERY_STRING']
545
- assert_equal '', get
705
+ assert_equal '', parser.buf
546
706
  assert parser.keepalive?
547
707
  end
548
708
 
@@ -568,7 +728,8 @@ class HttpParserTest < Test::Unit::TestCase
568
728
  10.times do |c|
569
729
  get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
570
730
  assert_raises Unicorn::HttpParserError do
571
- parser.headers({}, get)
731
+ parser.buf << get
732
+ parser.parse
572
733
  parser.clear
573
734
  end
574
735
  end
@@ -577,7 +738,8 @@ class HttpParserTest < Test::Unit::TestCase
577
738
  10.times do |c|
578
739
  get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
579
740
  assert_raises Unicorn::HttpParserError do
580
- parser.headers({}, get)
741
+ parser.buf << get
742
+ parser.parse
581
743
  parser.clear
582
744
  end
583
745
  end
@@ -585,16 +747,18 @@ class HttpParserTest < Test::Unit::TestCase
585
747
  # then large headers are rejected too
586
748
  get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
587
749
  get << "X-Test: test\r\n" * (80 * 1024)
750
+ parser.buf << get
588
751
  assert_raises Unicorn::HttpParserError do
589
- parser.headers({}, get)
590
- parser.clear
752
+ parser.parse
591
753
  end
754
+ parser.clear
592
755
 
593
756
  # finally just that random garbage gets blocked all the time
594
757
  10.times do |c|
595
758
  get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
596
759
  assert_raises Unicorn::HttpParserError do
597
- parser.headers({}, get)
760
+ parser.buf << get
761
+ parser.parse
598
762
  parser.clear
599
763
  end
600
764
  end