glebtv-httpclient 3.0.0

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +108 -0
  3. data/bin/httpclient +65 -0
  4. data/lib/glebtv-httpclient.rb +1 -0
  5. data/lib/hexdump.rb +50 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/http-access2.rb +55 -0
  9. data/lib/httpclient/auth.rb +899 -0
  10. data/lib/httpclient/cacert.p7s +1912 -0
  11. data/lib/httpclient/connection.rb +88 -0
  12. data/lib/httpclient/cookie.rb +438 -0
  13. data/lib/httpclient/http.rb +1050 -0
  14. data/lib/httpclient/include_client.rb +83 -0
  15. data/lib/httpclient/session.rb +1031 -0
  16. data/lib/httpclient/ssl_config.rb +403 -0
  17. data/lib/httpclient/timeout.rb +140 -0
  18. data/lib/httpclient/util.rb +186 -0
  19. data/lib/httpclient/version.rb +3 -0
  20. data/lib/httpclient.rb +1157 -0
  21. data/lib/oauthclient.rb +110 -0
  22. data/sample/async.rb +8 -0
  23. data/sample/auth.rb +11 -0
  24. data/sample/cookie.rb +18 -0
  25. data/sample/dav.rb +103 -0
  26. data/sample/howto.rb +49 -0
  27. data/sample/oauth_buzz.rb +57 -0
  28. data/sample/oauth_friendfeed.rb +59 -0
  29. data/sample/oauth_twitter.rb +61 -0
  30. data/sample/ssl/0cert.pem +22 -0
  31. data/sample/ssl/0key.pem +30 -0
  32. data/sample/ssl/1000cert.pem +19 -0
  33. data/sample/ssl/1000key.pem +18 -0
  34. data/sample/ssl/htdocs/index.html +10 -0
  35. data/sample/ssl/ssl_client.rb +22 -0
  36. data/sample/ssl/webrick_httpsd.rb +29 -0
  37. data/sample/stream.rb +21 -0
  38. data/sample/thread.rb +27 -0
  39. data/sample/wcat.rb +21 -0
  40. data/test/ca-chain.cert +44 -0
  41. data/test/ca.cert +23 -0
  42. data/test/client.cert +19 -0
  43. data/test/client.key +15 -0
  44. data/test/helper.rb +129 -0
  45. data/test/htdigest +1 -0
  46. data/test/htpasswd +2 -0
  47. data/test/runner.rb +2 -0
  48. data/test/server.cert +19 -0
  49. data/test/server.key +15 -0
  50. data/test/sslsvr.rb +65 -0
  51. data/test/subca.cert +21 -0
  52. data/test/test_auth.rb +321 -0
  53. data/test/test_cookie.rb +412 -0
  54. data/test/test_hexdump.rb +14 -0
  55. data/test/test_http-access2.rb +507 -0
  56. data/test/test_httpclient.rb +1801 -0
  57. data/test/test_include_client.rb +52 -0
  58. data/test/test_ssl.rb +235 -0
  59. metadata +102 -0
@@ -0,0 +1,1801 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('helper', File.dirname(__FILE__))
3
+
4
+
5
+ class TestHTTPClient < Test::Unit::TestCase
6
+ include Helper
7
+ include HTTPClient::Util
8
+
9
+ def setup
10
+ super
11
+ setup_server
12
+ setup_client
13
+ end
14
+
15
+ def teardown
16
+ super
17
+ end
18
+
19
+ def test_initialize
20
+ setup_proxyserver
21
+ escape_noproxy do
22
+ @proxyio.string = ""
23
+ @client = HTTPClient.new(proxyurl)
24
+ assert_equal(urify(proxyurl), @client.proxy)
25
+ assert_equal(200, @client.head(serverurl).status)
26
+ assert(/accept/ =~ @proxyio.string)
27
+ end
28
+ end
29
+
30
+ def test_agent_name
31
+ @client = HTTPClient.new(nil, "agent_name_foo")
32
+ str = ""
33
+ @client.debug_dev = str
34
+ @client.get(serverurl)
35
+ lines = str.split(/(?:\r?\n)+/)
36
+ assert_equal("= Request", lines[0])
37
+ assert_match(/^User-Agent: agent_name_foo \(#{HTTPClient::VERSION}/, lines[4])
38
+ end
39
+
40
+ def test_from
41
+ @client = HTTPClient.new(nil, nil, "from_bar")
42
+ str = ""
43
+ @client.debug_dev = str
44
+ @client.get(serverurl)
45
+ lines = str.split(/(?:\r?\n)+/)
46
+ assert_equal("= Request", lines[0])
47
+ assert_match(/^From: from_bar/, lines[5])
48
+ end
49
+
50
+ def test_debug_dev
51
+ str = ""
52
+ @client.debug_dev = str
53
+ assert_equal(str.object_id, @client.debug_dev.object_id)
54
+ assert(str.empty?)
55
+ @client.get(serverurl)
56
+ assert(!str.empty?)
57
+ end
58
+
59
+ def test_debug_dev_stream
60
+ str = ""
61
+ @client.debug_dev = str
62
+ conn = @client.get_async(serverurl)
63
+ Thread.pass while !conn.finished?
64
+ assert(!str.empty?)
65
+ end
66
+
67
+ def test_protocol_version_http09
68
+ @client.protocol_version = 'HTTP/0.9'
69
+ @client.debug_dev = str = ''
70
+ @client.test_loopback_http_response << "hello\nworld\n"
71
+ res = @client.get(serverurl + 'hello')
72
+ assert_equal('0.9', res.http_version)
73
+ assert_equal(nil, res.status)
74
+ assert_equal(nil, res.reason)
75
+ assert_equal("hello\nworld\n", res.content)
76
+ lines = str.split(/(?:\r?\n)+/)
77
+ assert_equal("= Request", lines[0])
78
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
79
+ assert_equal("GET /hello HTTP/0.9", lines[3])
80
+ assert_equal("Connection: close", lines[7])
81
+ assert_equal("= Response", lines[8])
82
+ assert_match(/^hello$/, lines[9])
83
+ assert_match(/^world$/, lines[10])
84
+ end
85
+
86
+ def test_protocol_version_http10
87
+ assert_equal(nil, @client.protocol_version)
88
+ @client.protocol_version = 'HTTP/1.0'
89
+ assert_equal('HTTP/1.0', @client.protocol_version)
90
+ str = ""
91
+ @client.debug_dev = str
92
+ @client.get(serverurl + 'hello')
93
+ lines = str.split(/(?:\r?\n)+/)
94
+ assert_equal("= Request", lines[0])
95
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
96
+ assert_equal("GET /hello HTTP/1.0", lines[3])
97
+ assert_equal("Connection: close", lines[7])
98
+ assert_equal("= Response", lines[8])
99
+ end
100
+
101
+ def test_header_accept_by_default
102
+ str = ""
103
+ @client.debug_dev = str
104
+ @client.get(serverurl)
105
+ lines = str.split(/(?:\r?\n)+/)
106
+ assert_equal("Accept: */*", lines[5])
107
+ end
108
+
109
+ def test_header_accept
110
+ str = ""
111
+ @client.debug_dev = str
112
+ @client.get(serverurl, :header => {:Accept => 'text/html'})
113
+ lines = str.split(/(?:\r?\n)+/)
114
+ assert_equal("Accept: text/html", lines[4])
115
+ end
116
+
117
+ def test_host_given
118
+ str = ""
119
+ @client.debug_dev = str
120
+ @client.get(serverurl)
121
+ lines = str.split(/(?:\r?\n)+/)
122
+ assert_equal("= Request", lines[0])
123
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
124
+ assert_equal("GET / HTTP/1.1", lines[3])
125
+ assert_equal("Host: localhost:#{serverport}", lines[7])
126
+ #
127
+ @client.reset_all
128
+ str = ""
129
+ @client.debug_dev = str
130
+ @client.get(serverurl, nil, {'Host' => 'foo'})
131
+ lines = str.split(/(?:\r?\n)+/)
132
+ assert_equal("= Request", lines[0])
133
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
134
+ assert_equal("GET / HTTP/1.1", lines[3])
135
+ assert_equal("Host: foo", lines[4]) # use given param
136
+ end
137
+
138
+ def test_redirect_returns_not_modified
139
+ assert_nothing_raised do
140
+ timeout(2) do
141
+ @client.get(serverurl + 'status', {:status => 306}, {:follow_redirect => true})
142
+ end
143
+ end
144
+ end
145
+
146
+ def test_protocol_version_http11
147
+ assert_equal(nil, @client.protocol_version)
148
+ str = ""
149
+ @client.debug_dev = str
150
+ @client.get(serverurl)
151
+ lines = str.split(/(?:\r?\n)+/)
152
+ assert_equal("= Request", lines[0])
153
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
154
+ assert_equal("GET / HTTP/1.1", lines[3])
155
+ assert_equal("Host: localhost:#{serverport}", lines[7])
156
+ @client.protocol_version = 'HTTP/1.1'
157
+ assert_equal('HTTP/1.1', @client.protocol_version)
158
+ str = ""
159
+ @client.debug_dev = str
160
+ @client.get(serverurl)
161
+ lines = str.split(/(?:\r?\n)+/)
162
+ assert_equal("= Request", lines[0])
163
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
164
+ assert_equal("GET / HTTP/1.1", lines[3])
165
+ @client.protocol_version = 'HTTP/1.0'
166
+ str = ""
167
+ @client.debug_dev = str
168
+ @client.get(serverurl)
169
+ lines = str.split(/(?:\r?\n)+/)
170
+ assert_equal("= Request", lines[0])
171
+ assert_equal("! CONNECTION ESTABLISHED", lines[2])
172
+ assert_equal("GET / HTTP/1.0", lines[3])
173
+ end
174
+
175
+ def test_proxy
176
+ setup_proxyserver
177
+ escape_noproxy do
178
+ begin
179
+ @client.proxy = "http://"
180
+ rescue
181
+ assert_match(/InvalidURIError/, $!.class.to_s)
182
+ end
183
+ @client.proxy = ""
184
+ assert_nil(@client.proxy)
185
+ @client.proxy = "http://admin:admin@foo:1234"
186
+ assert_equal(urify("http://admin:admin@foo:1234"), @client.proxy)
187
+ uri = urify("http://bar:2345")
188
+ @client.proxy = uri
189
+ assert_equal(uri, @client.proxy)
190
+ #
191
+ @proxyio.string = ""
192
+ @client.proxy = nil
193
+ assert_equal(200, @client.head(serverurl).status)
194
+ assert(/accept/ !~ @proxyio.string)
195
+ #
196
+ @proxyio.string = ""
197
+ @client.proxy = proxyurl
198
+ @client.debug_dev = str = ""
199
+ assert_equal(200, @client.head(serverurl).status)
200
+ assert(/accept/ =~ @proxyio.string)
201
+ assert(/Host: localhost:#{serverport}/ =~ str)
202
+ end
203
+ end
204
+
205
+ def test_host_header
206
+ @client.proxy = proxyurl
207
+ @client.debug_dev = str = ""
208
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
209
+ assert_equal(200, @client.head('http://www.example.com/foo').status)
210
+ # ensure no ':80' is added. some servers dislike that.
211
+ assert(/\r\nHost: www\.example\.com\r\n/ =~ str)
212
+ #
213
+ @client.debug_dev = str = ""
214
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
215
+ assert_equal(200, @client.head('http://www.example.com:12345/foo').status)
216
+ # ensure ':12345' exists.
217
+ assert(/\r\nHost: www\.example\.com:12345\r\n/ =~ str)
218
+ end
219
+
220
+ def test_proxy_env
221
+ setup_proxyserver
222
+ escape_env do
223
+ ENV['http_proxy'] = "http://admin:admin@foo:1234"
224
+ ENV['NO_PROXY'] = "foobar"
225
+ client = HTTPClient.new
226
+ assert_equal(urify("http://admin:admin@foo:1234"), client.proxy)
227
+ assert_equal('foobar', client.no_proxy)
228
+ end
229
+ end
230
+
231
+ def test_proxy_env_cgi
232
+ setup_proxyserver
233
+ escape_env do
234
+ ENV['REQUEST_METHOD'] = 'GET' # CGI environment emulation
235
+ ENV['http_proxy'] = "http://admin:admin@foo:1234"
236
+ ENV['no_proxy'] = "foobar"
237
+ client = HTTPClient.new
238
+ assert_equal(nil, client.proxy)
239
+ ENV['CGI_HTTP_PROXY'] = "http://admin:admin@foo:1234"
240
+ client = HTTPClient.new
241
+ assert_equal(urify("http://admin:admin@foo:1234"), client.proxy)
242
+ end
243
+ end
244
+
245
+ def test_empty_proxy_env
246
+ setup_proxyserver
247
+ escape_env do
248
+ ENV['http_proxy'] = ""
249
+ client = HTTPClient.new
250
+ assert_equal(nil, client.proxy)
251
+ end
252
+ end
253
+
254
+ def test_noproxy_for_localhost
255
+ @proxyio.string = ""
256
+ @client.proxy = proxyurl
257
+ assert_equal(200, @client.head(serverurl).status)
258
+ assert(/accept/ !~ @proxyio.string)
259
+ end
260
+
261
+ def test_no_proxy
262
+ setup_proxyserver
263
+ escape_noproxy do
264
+ # proxy is not set.
265
+ assert_equal(nil, @client.no_proxy)
266
+ @client.no_proxy = 'localhost'
267
+ assert_equal('localhost', @client.no_proxy)
268
+ @proxyio.string = ""
269
+ @client.proxy = nil
270
+ assert_equal(200, @client.head(serverurl).status)
271
+ assert(/accept/ !~ @proxyio.string)
272
+ #
273
+ @proxyio.string = ""
274
+ @client.proxy = proxyurl
275
+ assert_equal(200, @client.head(serverurl).status)
276
+ assert(/accept/ !~ @proxyio.string)
277
+ #
278
+ @client.no_proxy = 'foobar'
279
+ @proxyio.string = ""
280
+ @client.proxy = proxyurl
281
+ assert_equal(200, @client.head(serverurl).status)
282
+ assert(/accept/ =~ @proxyio.string)
283
+ #
284
+ @client.no_proxy = 'foobar,localhost:baz'
285
+ @proxyio.string = ""
286
+ @client.proxy = proxyurl
287
+ assert_equal(200, @client.head(serverurl).status)
288
+ assert(/accept/ !~ @proxyio.string)
289
+ #
290
+ @client.no_proxy = 'foobar,localhost:443'
291
+ @proxyio.string = ""
292
+ @client.proxy = proxyurl
293
+ assert_equal(200, @client.head(serverurl).status)
294
+ assert(/accept/ =~ @proxyio.string)
295
+ #
296
+ @client.no_proxy = "foobar,localhost:443:localhost:#{serverport},baz"
297
+ @proxyio.string = ""
298
+ @client.proxy = proxyurl
299
+ assert_equal(200, @client.head(serverurl).status)
300
+ assert(/accept/ !~ @proxyio.string)
301
+ end
302
+ end
303
+
304
+ def test_no_proxy_with_initial_dot
305
+ @client.debug_dev = str = ""
306
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
307
+ @client.no_proxy = ''
308
+ @client.proxy = proxyurl
309
+ @client.head('http://www.foo.com')
310
+ assert(/CONNECT TO localhost/ =~ str, 'via proxy')
311
+ #
312
+ @client.debug_dev = str = ""
313
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
314
+ @client.no_proxy = '.foo.com'
315
+ @client.proxy = proxyurl
316
+ @client.head('http://www.foo.com')
317
+ assert(/CONNECT TO www.foo.com/ =~ str, 'no proxy because .foo.com matches with www.foo.com')
318
+ #
319
+ @client.debug_dev = str = ""
320
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
321
+ @client.no_proxy = '.foo.com'
322
+ @client.proxy = proxyurl
323
+ @client.head('http://foo.com')
324
+ assert(/CONNECT TO localhost/ =~ str, 'via proxy because .foo.com does not matche with foo.com')
325
+ #
326
+ @client.debug_dev = str = ""
327
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\n\r\n"
328
+ @client.no_proxy = 'foo.com'
329
+ @client.proxy = proxyurl
330
+ @client.head('http://foo.com')
331
+ assert(/CONNECT TO foo.com/ =~ str, 'no proxy because foo.com matches with foo.com')
332
+ end
333
+
334
+ def test_cookie_update_while_authentication
335
+ escape_noproxy do
336
+ @client.test_loopback_http_response << <<EOS
337
+ HTTP/1.0 401\r
338
+ Date: Fri, 19 Dec 2008 11:57:29 GMT\r
339
+ Content-Type: text/plain\r
340
+ Content-Length: 0\r
341
+ WWW-Authenticate: Basic realm="hello"\r
342
+ Set-Cookie: foo=bar; path=/; domain=.example.org; expires=#{Time.at(1924873200).httpdate}\r
343
+ \r
344
+ EOS
345
+ @client.test_loopback_http_response << <<EOS
346
+ HTTP/1.1 200 OK\r
347
+ Content-Length: 5\r
348
+ Connection: close\r
349
+ \r
350
+ hello
351
+ EOS
352
+ @client.debug_dev = str = ''
353
+ @client.set_auth("http://www.example.org/baz/", 'admin', 'admin')
354
+ assert_equal('hello', @client.get('http://www.example.org/baz/foo').content)
355
+ assert_match(/^Cookie: foo=bar/, str)
356
+ assert_match(/^Authorization: Basic YWRtaW46YWRtaW4=/, str)
357
+ end
358
+ end
359
+
360
+
361
+ def test_proxy_ssl
362
+ escape_noproxy do
363
+ @client.proxy = 'http://admin:admin@localhost:8080/'
364
+ # disconnected at initial 'CONNECT' so there're 2 loopback responses
365
+ @client.test_loopback_http_response << <<EOS
366
+ HTTP/1.0 407 Proxy Authentication Required\r
367
+ Date: Fri, 19 Dec 2008 11:57:29 GMT\r
368
+ Content-Type: text/plain\r
369
+ Content-Length: 0\r
370
+ Proxy-Authenticate: Basic realm="hello"\r
371
+ Proxy-Connection: close\r
372
+ \r
373
+ EOS
374
+ @client.test_loopback_http_response << <<EOS
375
+ HTTP/1.0 200 Connection established\r
376
+ \r
377
+ HTTP/1.1 200 OK\r
378
+ Content-Length: 5\r
379
+ Connection: close\r
380
+ \r
381
+ hello
382
+ EOS
383
+ assert_equal('hello', @client.get('https://localhost:17171/baz').content)
384
+ end
385
+ end
386
+
387
+ def test_loopback_response
388
+ @client.test_loopback_response << 'message body 1'
389
+ @client.test_loopback_response << 'message body 2'
390
+ assert_equal('message body 1', @client.get_content('http://somewhere'))
391
+ assert_equal('message body 2', @client.get_content('http://somewhere'))
392
+ #
393
+ @client.debug_dev = str = ''
394
+ @client.test_loopback_response << 'message body 3'
395
+ assert_equal('message body 3', @client.get_content('http://somewhere'))
396
+ assert_match(/message body 3/, str)
397
+ end
398
+
399
+ def test_loopback_response_stream
400
+ @client.test_loopback_response << 'message body 1'
401
+ @client.test_loopback_response << 'message body 2'
402
+ conn = @client.get_async('http://somewhere')
403
+ Thread.pass while !conn.finished?
404
+ assert_equal('message body 1', conn.pop.content.read)
405
+ conn = @client.get_async('http://somewhere')
406
+ Thread.pass while !conn.finished?
407
+ assert_equal('message body 2', conn.pop.content.read)
408
+ end
409
+
410
+ def test_loopback_http_response
411
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\ncontent-length: 100\n\nmessage body 1"
412
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\ncontent-length: 100\n\nmessage body 2"
413
+ assert_equal('message body 1', @client.get_content('http://somewhere'))
414
+ assert_equal('message body 2', @client.get_content('http://somewhere'))
415
+ end
416
+
417
+ def test_multiline_header
418
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\nX-Foo: XXX\n YYY\nX-Bar: \n XXX\n\tYYY\ncontent-length: 100\n\nmessage body 1"
419
+ res = @client.get('http://somewhere')
420
+ assert_equal('message body 1', res.content)
421
+ assert_equal(['XXX YYY'], res.header['x-foo'])
422
+ assert_equal(['XXX YYY'], res.header['x-bar'])
423
+ end
424
+
425
+ def test_broken_header
426
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\nXXXXX\ncontent-length: 100\n\nmessage body 1"
427
+ res = @client.get('http://somewhere')
428
+ assert_equal('message body 1', res.content)
429
+ end
430
+
431
+ def test_request_uri_in_response
432
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\ncontent-length: 100\n\nmessage body"
433
+ assert_equal(urify('http://google.com/'), @client.get('http://google.com/').header.request_uri)
434
+ end
435
+
436
+ def test_request_uri_in_response_when_redirect
437
+ expected = urify(serverurl + 'hello')
438
+ assert_equal(expected, @client.get(serverurl + 'redirect1', :follow_redirect => true).header.request_uri)
439
+ assert_equal(expected, @client.get(serverurl + 'redirect2', :follow_redirect => true).header.request_uri)
440
+ end
441
+
442
+ def test_redirect_non_https
443
+ url = serverurl + 'redirect1'
444
+ https_url = urify(url)
445
+ https_url.scheme = 'https'
446
+ #
447
+ redirect_to_http = "HTTP/1.0 302 OK\nLocation: #{url}\n\n"
448
+ redirect_to_https = "HTTP/1.0 302 OK\nLocation: #{https_url}\n\n"
449
+ #
450
+ # https -> http is denied
451
+ @client.test_loopback_http_response << redirect_to_http
452
+ assert_raises(HTTPClient::BadResponseError) do
453
+ @client.get_content(https_url)
454
+ end
455
+ #
456
+ # http -> http is OK
457
+ @client.reset_all
458
+ @client.test_loopback_http_response << redirect_to_http
459
+ assert_equal('hello', @client.get_content(url))
460
+ #
461
+ # http -> https is OK
462
+ @client.reset_all
463
+ @client.test_loopback_http_response << redirect_to_https
464
+ assert_raises(OpenSSL::SSL::SSLError) do
465
+ # trying to normal endpoint with SSL -> SSL negotiation failure
466
+ @client.get_content(url)
467
+ end
468
+ #
469
+ # https -> https is OK
470
+ @client.reset_all
471
+ @client.test_loopback_http_response << redirect_to_https
472
+ assert_raises(OpenSSL::SSL::SSLError) do
473
+ # trying to normal endpoint with SSL -> SSL negotiation failure
474
+ @client.get_content(https_url)
475
+ end
476
+ #
477
+ # https -> http with strict_redirect_uri_callback
478
+ @client.redirect_uri_callback = @client.method(:strict_redirect_uri_callback)
479
+ @client.test_loopback_http_response << redirect_to_http
480
+ assert_raises(HTTPClient::BadResponseError) do
481
+ @client.get_content(https_url)
482
+ end
483
+ end
484
+
485
+ def test_redirect_see_other
486
+ assert_equal('hello', @client.post_content(serverurl + 'redirect_see_other'))
487
+ end
488
+
489
+ def test_redirect_relative
490
+ @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: hello\n\n"
491
+ silent do
492
+ assert_equal('hello', @client.get_content(serverurl + 'redirect1'))
493
+ end
494
+ #
495
+ @client.reset_all
496
+ @client.redirect_uri_callback = @client.method(:strict_redirect_uri_callback)
497
+ assert_equal('hello', @client.get_content(serverurl + 'redirect1'))
498
+ @client.reset_all
499
+ @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: hello\n\n"
500
+ begin
501
+ @client.get_content(serverurl + 'redirect1')
502
+ assert(false)
503
+ rescue HTTPClient::BadResponseError => e
504
+ assert_equal(302, e.res.status)
505
+ end
506
+ end
507
+
508
+ def test_redirect_https_relative
509
+ url = serverurl + 'redirect1'
510
+ https_url = urify(url)
511
+ https_url.scheme = 'https'
512
+ @client.test_loopback_http_response << "HTTP/1.0 302 OK\nLocation: /foo\n\n"
513
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\n\nhello"
514
+ silent do
515
+ assert_equal('hello', @client.get_content(https_url))
516
+ end
517
+ end
518
+
519
+ def test_no_content
520
+ assert_nothing_raised do
521
+ timeout(2) do
522
+ @client.get(serverurl + 'status', :status => 101)
523
+ @client.get(serverurl + 'status', :status => 204)
524
+ @client.get(serverurl + 'status', :status => 304)
525
+ end
526
+ end
527
+ end
528
+
529
+ def test_get_content
530
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
531
+ assert_equal('hello', @client.get_content(serverurl + 'redirect1'))
532
+ assert_equal('hello', @client.get_content(serverurl + 'redirect2'))
533
+ url = serverurl.sub(/localhost/, '127.0.0.1')
534
+ assert_equal('hello', @client.get_content(url + 'hello'))
535
+ assert_equal('hello', @client.get_content(url + 'redirect1'))
536
+ assert_equal('hello', @client.get_content(url + 'redirect2'))
537
+ @client.reset(serverurl)
538
+ @client.reset(url)
539
+ @client.reset(serverurl)
540
+ @client.reset(url)
541
+ assert_raises(HTTPClient::BadResponseError) do
542
+ @client.get_content(serverurl + 'notfound')
543
+ end
544
+ assert_raises(HTTPClient::BadResponseError) do
545
+ @client.get_content(serverurl + 'redirect_self')
546
+ end
547
+ called = false
548
+ @client.redirect_uri_callback = lambda { |uri, res|
549
+ newuri = res.header['location'][0]
550
+ called = true
551
+ newuri
552
+ }
553
+ assert_equal('hello', @client.get_content(serverurl + 'relative_redirect'))
554
+ assert(called)
555
+ end
556
+
557
+ GZIP_CONTENT = "\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00"
558
+ DEFLATE_CONTENT = "\x78\x9c\xcb\x48\xcd\xc9\xc9\x07\x00\x06\x2c\x02\x15"
559
+ GZIP_CONTENT.force_encoding('BINARY') if GZIP_CONTENT.respond_to?(:force_encoding)
560
+ DEFLATE_CONTENT.force_encoding('BINARY') if DEFLATE_CONTENT.respond_to?(:force_encoding)
561
+ def test_get_gzipped_content
562
+ @client.transparent_gzip_decompression = false
563
+ content = @client.get_content(serverurl + 'compressed?enc=gzip')
564
+ assert_not_equal('hello', content)
565
+ assert_equal(GZIP_CONTENT, content)
566
+ @client.transparent_gzip_decompression = true
567
+ assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=gzip'))
568
+ assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=deflate'))
569
+ @client.transparent_gzip_decompression = false
570
+ end
571
+
572
+ def test_get_content_with_block
573
+ @client.get_content(serverurl + 'hello') do |str|
574
+ assert_equal('hello', str)
575
+ end
576
+ @client.get_content(serverurl + 'redirect1') do |str|
577
+ assert_equal('hello', str)
578
+ end
579
+ @client.get_content(serverurl + 'redirect2') do |str|
580
+ assert_equal('hello', str)
581
+ end
582
+ end
583
+
584
+ def test_post_content
585
+ assert_equal('hello', @client.post_content(serverurl + 'hello'))
586
+ assert_equal('hello', @client.post_content(serverurl + 'redirect1'))
587
+ assert_equal('hello', @client.post_content(serverurl + 'redirect2'))
588
+ assert_raises(HTTPClient::BadResponseError) do
589
+ @client.post_content(serverurl + 'notfound')
590
+ end
591
+ assert_raises(HTTPClient::BadResponseError) do
592
+ @client.post_content(serverurl + 'redirect_self')
593
+ end
594
+ called = false
595
+ @client.redirect_uri_callback = lambda { |uri, res|
596
+ newuri = res.header['location'][0]
597
+ called = true
598
+ newuri
599
+ }
600
+ assert_equal('hello', @client.post_content(serverurl + 'relative_redirect'))
601
+ assert(called)
602
+ end
603
+
604
+ def test_post_content_io
605
+ post_body = StringIO.new("1234567890")
606
+ assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet', post_body))
607
+ post_body = StringIO.new("1234567890")
608
+ # all browsers use GET for 302
609
+ assert_equal('get', @client.post_content(serverurl + 'servlet_redirect', post_body))
610
+ post_body = StringIO.new("1234567890")
611
+ assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet_temporary_redirect', post_body))
612
+ post_body = StringIO.new("1234567890")
613
+ assert_equal('get', @client.post_content(serverurl + 'servlet_see_other', post_body))
614
+ #
615
+ post_body = StringIO.new("1234567890")
616
+ post_body.read(5)
617
+ assert_equal('post,67890', @client.post_content(serverurl + 'servlet_temporary_redirect', post_body))
618
+ end
619
+
620
+ def test_head
621
+ assert_equal("head", @client.head(serverurl + 'servlet').header["x-head"][0])
622
+ param = {'1'=>'2', '3'=>'4'}
623
+ res = @client.head(serverurl + 'servlet', param)
624
+ assert_equal(param, params(res.header["x-query"][0]))
625
+ end
626
+
627
+ def test_head_async
628
+ param = {'1'=>'2', '3'=>'4'}
629
+ conn = @client.head_async(serverurl + 'servlet', param)
630
+ Thread.pass while !conn.finished?
631
+ res = conn.pop
632
+ assert_equal(param, params(res.header["x-query"][0]))
633
+ end
634
+
635
+ def test_get
636
+ assert_equal("get", @client.get(serverurl + 'servlet').content)
637
+ param = {'1'=>'2', '3'=>'4'}
638
+ res = @client.get(serverurl + 'servlet', param)
639
+ assert_equal(param, params(res.header["x-query"][0]))
640
+ assert_nil(res.contenttype)
641
+ #
642
+ url = serverurl.to_s + 'servlet?5=6&7=8'
643
+ res = @client.get(url, param)
644
+ assert_equal(param.merge("5"=>"6", "7"=>"8"), params(res.header["x-query"][0]))
645
+ assert_nil(res.contenttype)
646
+ end
647
+
648
+ def test_head_follow_redirect
649
+ expected = urify(serverurl + 'hello')
650
+ assert_equal(expected, @client.head(serverurl + 'hello', :follow_redirect => true).header.request_uri)
651
+ assert_equal(expected, @client.head(serverurl + 'redirect1', :follow_redirect => true).header.request_uri)
652
+ assert_equal(expected, @client.head(serverurl + 'redirect2', :follow_redirect => true).header.request_uri)
653
+ end
654
+
655
+ def test_get_follow_redirect
656
+ assert_equal('hello', @client.get(serverurl + 'hello', :follow_redirect => true).body)
657
+ assert_equal('hello', @client.get(serverurl + 'redirect1', :follow_redirect => true).body)
658
+ assert_equal('hello', @client.get(serverurl + 'redirect2', :follow_redirect => true).body)
659
+ end
660
+
661
+ def test_get_async
662
+ param = {'1'=>'2', '3'=>'4'}
663
+ conn = @client.get_async(serverurl + 'servlet', param)
664
+ Thread.pass while !conn.finished?
665
+ res = conn.pop
666
+ assert_equal(param, params(res.header["x-query"][0]))
667
+ end
668
+
669
+ def test_get_async_for_largebody
670
+ conn = @client.get_async(serverurl + 'largebody')
671
+ res = conn.pop
672
+ assert_equal(1000*1000, res.content.read.length)
673
+ end
674
+
675
+ def test_get_with_block
676
+ called = false
677
+ res = @client.get(serverurl + 'servlet') { |str|
678
+ assert_equal('get', str)
679
+ called = true
680
+ }
681
+ assert(called)
682
+ # res does not have a content
683
+ assert_nil(res.content)
684
+ end
685
+
686
+ def test_get_with_block_chunk_string_recycle
687
+ @client.read_block_size = 2
688
+ body = []
689
+ res = @client.get(serverurl + 'servlet') { |str|
690
+ body << str
691
+ }
692
+ assert_equal(2, body.size)
693
+ assert_equal("get", body.join) # Was "tt" by String object recycle...
694
+ end
695
+
696
+ def test_post
697
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4])
698
+ param = {'1'=>'2', '3'=>'4'}
699
+ res = @client.post(serverurl + 'servlet', param)
700
+ assert_equal(param, params(res.header["x-query"][0]))
701
+ end
702
+
703
+ def test_post_follow_redirect
704
+ assert_equal('hello', @client.post(serverurl + 'hello', :follow_redirect => true).body)
705
+ assert_equal('hello', @client.post(serverurl + 'redirect1', :follow_redirect => true).body)
706
+ assert_equal('hello', @client.post(serverurl + 'redirect2', :follow_redirect => true).body)
707
+ end
708
+
709
+ def test_post_with_content_type
710
+ param = [['1', '2'], ['3', '4']]
711
+ ext = {'content-type' => 'application/x-www-form-urlencoded', 'hello' => 'world'}
712
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
713
+ res = @client.post(serverurl + 'servlet', param, ext)
714
+ assert_equal(Hash[param], params(res.header["x-query"][0]))
715
+ #
716
+ ext = [['content-type', 'multipart/form-data'], ['hello', 'world']]
717
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
718
+ res = @client.post(serverurl + 'servlet', param, ext)
719
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
720
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
721
+ #
722
+ ext = {'content-type' => 'multipart/form-data; boundary=hello'}
723
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
724
+ res = @client.post(serverurl + 'servlet', param, ext)
725
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
726
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
727
+ assert_equal("post,--hello\r\nContent-Disposition: form-data; name=\"1\"\r\n\r\n2\r\n--hello\r\nContent-Disposition: form-data; name=\"3\"\r\n\r\n4\r\n--hello--\r\n\r\n", res.content)
728
+ end
729
+
730
+ def test_post_with_custom_multipart_and_boolean_params
731
+ param = [['boolean_true', true]]
732
+ ext = { 'content-type' => 'multipart/form-data' }
733
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
734
+ res = @client.post(serverurl + 'servlet', param, ext)
735
+ assert_match(/Content-Disposition: form-data; name="boolean_true"\r\n\r\ntrue\r\n/, res.content)
736
+ #
737
+ param = [['boolean_false', false]]
738
+ res = @client.post(serverurl + 'servlet', param, ext)
739
+ assert_match(/Content-Disposition: form-data; name="boolean_false"\r\n\r\nfalse\r\n/, res.content)
740
+ #
741
+ param = [['nil', nil]]
742
+ res = @client.post(serverurl + 'servlet', param, ext)
743
+ assert_match(/Content-Disposition: form-data; name="nil"\r\n\r\n\r\n/, res.content)
744
+ end
745
+
746
+ def test_post_with_file
747
+ STDOUT.sync = true
748
+ File.open(__FILE__) do |file|
749
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>file})
750
+ assert_match(/^Content-Disposition: form-data; name="1"\r\n/nm, res.content)
751
+ assert_match(/^Content-Disposition: form-data; name="3";/, res.content)
752
+ assert_match(/FIND_TAG_IN_THIS_FILE/, res.content)
753
+ end
754
+ end
755
+
756
+ def test_post_with_file_without_size
757
+ STDOUT.sync = true
758
+ File.open(__FILE__) do |file|
759
+ def file.size
760
+ # Simulates some strange Windows behaviour
761
+ raise SystemCallError.new "Unknown Error (20047)"
762
+ end
763
+ assert_nothing_raised do
764
+ @client.post(serverurl + 'servlet', {1=>2, 3=>file})
765
+ end
766
+ end
767
+ end
768
+
769
+ def test_post_with_io # streaming, but not chunked
770
+ myio = StringIO.new("X" * (HTTP::Message::Body::DEFAULT_CHUNK_SIZE + 1))
771
+ def myio.read(*args)
772
+ @called ||= 0
773
+ @called += 1
774
+ super
775
+ end
776
+ def myio.called
777
+ @called
778
+ end
779
+ @client.debug_dev = str = StringIO.new
780
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio})
781
+ assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content)
782
+ assert_match(/\r\n2\r\n/m, res.content)
783
+ assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content)
784
+ assert_match(/\r\nContent-Length:/m, str.string)
785
+ assert_equal(3, myio.called)
786
+ end
787
+
788
+ def test_post_with_io_nosize # streaming + chunked post
789
+ myio = StringIO.new("4")
790
+ def myio.size
791
+ nil
792
+ end
793
+ @client.debug_dev = str = StringIO.new
794
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio})
795
+ assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content)
796
+ assert_match(/\r\n2\r\n/m, res.content)
797
+ assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content)
798
+ assert_match(/\r\n4\r\n/m, res.content)
799
+ assert_match(/\r\nTransfer-Encoding: chunked\r\n/m, str.string)
800
+ end
801
+
802
+ def test_post_async
803
+ param = {'1'=>'2', '3'=>'4'}
804
+ conn = @client.post_async(serverurl + 'servlet', param)
805
+ Thread.pass while !conn.finished?
806
+ res = conn.pop
807
+ assert_equal(param, params(res.header["x-query"][0]))
808
+ end
809
+
810
+ def test_post_with_block
811
+ called = false
812
+ res = @client.post(serverurl + 'servlet') { |str|
813
+ assert_equal('post,', str)
814
+ called = true
815
+ }
816
+ assert(called)
817
+ assert_nil(res.content)
818
+ #
819
+ called = false
820
+ param = [['1', '2'], ['3', '4']]
821
+ res = @client.post(serverurl + 'servlet', param) { |str|
822
+ assert_equal('post,1=2&3=4', str)
823
+ called = true
824
+ }
825
+ assert(called)
826
+ assert_equal('1=2&3=4', res.header["x-query"][0])
827
+ assert_nil(res.content)
828
+ end
829
+
830
+ def test_post_with_custom_multipart
831
+ ext = {'content-type' => 'multipart/form-data'}
832
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
833
+ body = [{ 'Content-Disposition' => 'form-data; name="1"', :content => "2"},
834
+ { 'Content-Disposition' => 'form-data; name="3"', :content => "4"}]
835
+ res = @client.post(serverurl + 'servlet', body, ext)
836
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
837
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
838
+ #
839
+ ext = {'content-type' => 'multipart/form-data; boundary=hello'}
840
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
841
+ res = @client.post(serverurl + 'servlet', body, ext)
842
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
843
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
844
+ assert_equal("post,--hello\r\nContent-Disposition: form-data; name=\"1\"\r\n\r\n2\r\n--hello\r\nContent-Disposition: form-data; name=\"3\"\r\n\r\n4\r\n--hello--\r\n\r\n", res.content)
845
+ end
846
+
847
+ def test_post_with_custom_multipart_and_file
848
+ STDOUT.sync = true
849
+ File.open(__FILE__) do |file|
850
+ ext = { 'Content-Type' => 'multipart/alternative' }
851
+ body = [{ 'Content-Type' => 'text/plain', :content => "this is only a test" },
852
+ { 'Content-Type' => 'application/x-ruby', :content => file }]
853
+ res = @client.post(serverurl + 'servlet', body, ext)
854
+ assert_match(/^Content-Type: text\/plain\r\n/m, res.content)
855
+ assert_match(/^this is only a test\r\n/m, res.content)
856
+ assert_match(/^Content-Type: application\/x-ruby\r\n/m, res.content)
857
+ assert_match(/FIND_TAG_IN_THIS_FILE/, res.content)
858
+ end
859
+ end
860
+
861
+ def test_put
862
+ assert_equal("put", @client.put(serverurl + 'servlet').content)
863
+ param = {'1'=>'2', '3'=>'4'}
864
+ @client.debug_dev = str = ''
865
+ res = @client.put(serverurl + 'servlet', param)
866
+ assert_equal(param, params(res.header["x-query"][0]))
867
+ assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5])
868
+ end
869
+
870
+ def test_put_bytesize
871
+ res = @client.put(serverurl + 'servlet', 'txt' => 'あいうえお')
872
+ assert_equal('txt=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A', res.header["x-query"][0])
873
+ assert_equal('15', res.header["x-size"][0])
874
+ end
875
+
876
+ def test_put_async
877
+ param = {'1'=>'2', '3'=>'4'}
878
+ conn = @client.put_async(serverurl + 'servlet', param)
879
+ Thread.pass while !conn.finished?
880
+ res = conn.pop
881
+ assert_equal(param, params(res.header["x-query"][0]))
882
+ end
883
+
884
+ def test_delete
885
+ assert_equal("delete", @client.delete(serverurl + 'servlet').content)
886
+ end
887
+
888
+ # Not prohibited by spec, but normally it's ignored
889
+ def test_delete_with_body
890
+ param = {'1'=>'2', '3'=>'4'}
891
+ @client.debug_dev = str = ''
892
+ assert_equal("delete", @client.delete(serverurl + 'servlet', param).content)
893
+ assert_equal({'1' => ['2'], '3' => ['4']}, HTTP::Message.parse(str.split(/\r?\n\r?\n/)[2]))
894
+ end
895
+
896
+ def test_delete_async
897
+ conn = @client.delete_async(serverurl + 'servlet')
898
+ Thread.pass while !conn.finished?
899
+ res = conn.pop
900
+ assert_equal('delete', res.content.read)
901
+ end
902
+
903
+ def test_options
904
+ assert_equal("options", @client.options(serverurl + 'servlet').content)
905
+ end
906
+
907
+ def test_options_async
908
+ conn = @client.options_async(serverurl + 'servlet')
909
+ Thread.pass while !conn.finished?
910
+ res = conn.pop
911
+ assert_equal('options', res.content.read)
912
+ end
913
+
914
+ def test_propfind
915
+ assert_equal("propfind", @client.propfind(serverurl + 'servlet').content)
916
+ end
917
+
918
+ def test_propfind_async
919
+ conn = @client.propfind_async(serverurl + 'servlet')
920
+ Thread.pass while !conn.finished?
921
+ res = conn.pop
922
+ assert_equal('propfind', res.content.read)
923
+ end
924
+
925
+ def test_proppatch
926
+ assert_equal("proppatch", @client.proppatch(serverurl + 'servlet').content)
927
+ param = {'1'=>'2', '3'=>'4'}
928
+ res = @client.proppatch(serverurl + 'servlet', param)
929
+ assert_equal('proppatch', res.content)
930
+ assert_equal(param, params(res.header["x-query"][0]))
931
+ end
932
+
933
+ def test_proppatch_async
934
+ param = {'1'=>'2', '3'=>'4'}
935
+ conn = @client.proppatch_async(serverurl + 'servlet', param)
936
+ Thread.pass while !conn.finished?
937
+ res = conn.pop
938
+ assert_equal('proppatch', res.content.read)
939
+ assert_equal(param, params(res.header["x-query"][0]))
940
+ end
941
+
942
+ def test_trace
943
+ assert_equal("trace", @client.trace(serverurl + 'servlet').content)
944
+ param = {'1'=>'2', '3'=>'4'}
945
+ res = @client.trace(serverurl + 'servlet', param)
946
+ assert_equal(param, params(res.header["x-query"][0]))
947
+ end
948
+
949
+ def test_trace_async
950
+ param = {'1'=>'2', '3'=>'4'}
951
+ conn = @client.trace_async(serverurl + 'servlet', param)
952
+ Thread.pass while !conn.finished?
953
+ res = conn.pop
954
+ assert_equal(param, params(res.header["x-query"][0]))
955
+ end
956
+
957
+ def test_chunked
958
+ assert_equal('chunked', @client.get_content(serverurl + 'chunked', { 'msg' => 'chunked' }))
959
+ end
960
+
961
+ def test_chunked_empty
962
+ assert_equal('', @client.get_content(serverurl + 'chunked', { 'msg' => '' }))
963
+ end
964
+
965
+ def test_get_query
966
+ assert_equal({'1'=>'2'}, check_query_get({1=>2}))
967
+ assert_equal({'a'=>'A', 'B'=>'b'}, check_query_get({"a"=>"A", "B"=>"b"}))
968
+ assert_equal({'&'=>'&'}, check_query_get({"&"=>"&"}))
969
+ assert_equal({'= '=>' =+'}, check_query_get({"= "=>" =+"}))
970
+ assert_equal(
971
+ ['=', '&'].sort,
972
+ check_query_get([["=", "="], ["=", "&"]])['='].to_ary.sort
973
+ )
974
+ assert_equal({'123'=>'45'}, check_query_get('123=45'))
975
+ assert_equal({'12 3'=>'45', ' '=>' '}, check_query_get('12+3=45&+=+'))
976
+ assert_equal({}, check_query_get(''))
977
+ assert_equal({'1'=>'2'}, check_query_get({1=>StringIO.new('2')}))
978
+ assert_equal({'1'=>'2', '3'=>'4'}, check_query_get(StringIO.new('3=4&1=2')))
979
+
980
+ hash = check_query_get({"a"=>["A","a"], "B"=>"b"})
981
+ assert_equal({'a'=>'A', 'B'=>'b'}, hash)
982
+ assert_equal(['A','a'], hash['a'].to_ary)
983
+
984
+ hash = check_query_get({"a"=>WEBrick::HTTPUtils::FormData.new("A","a"), "B"=>"b"})
985
+ assert_equal({'a'=>'A', 'B'=>'b'}, hash)
986
+ assert_equal(['A','a'], hash['a'].to_ary)
987
+
988
+ hash = check_query_get({"a"=>[StringIO.new("A"),StringIO.new("a")], "B"=>StringIO.new("b")})
989
+ assert_equal({'a'=>'A', 'B'=>'b'}, hash)
990
+ assert_equal(['A','a'], hash['a'].to_ary)
991
+ end
992
+
993
+ def test_post_body
994
+ assert_equal({'1'=>'2'}, check_query_post({1=>2}))
995
+ assert_equal({'a'=>'A', 'B'=>'b'}, check_query_post({"a"=>"A", "B"=>"b"}))
996
+ assert_equal({'&'=>'&'}, check_query_post({"&"=>"&"}))
997
+ assert_equal({'= '=>' =+'}, check_query_post({"= "=>" =+"}))
998
+ assert_equal(
999
+ ['=', '&'].sort,
1000
+ check_query_post([["=", "="], ["=", "&"]])['='].to_ary.sort
1001
+ )
1002
+ assert_equal({'123'=>'45'}, check_query_post('123=45'))
1003
+ assert_equal({'12 3'=>'45', ' '=>' '}, check_query_post('12+3=45&+=+'))
1004
+ assert_equal({}, check_query_post(''))
1005
+ #
1006
+ post_body = StringIO.new("foo=bar&foo=baz")
1007
+ assert_equal(
1008
+ ["bar", "baz"],
1009
+ check_query_post(post_body)["foo"].to_ary.sort
1010
+ )
1011
+ end
1012
+
1013
+ def test_extra_headers
1014
+ str = ""
1015
+ @client.debug_dev = str
1016
+ @client.head(serverurl, nil, {"ABC" => "DEF"})
1017
+ lines = str.split(/(?:\r?\n)+/)
1018
+ assert_equal("= Request", lines[0])
1019
+ assert_match("ABC: DEF", lines[4])
1020
+ #
1021
+ str = ""
1022
+ @client.debug_dev = str
1023
+ @client.get(serverurl, nil, [["ABC", "DEF"], ["ABC", "DEF"]])
1024
+ lines = str.split(/(?:\r?\n)+/)
1025
+ assert_equal("= Request", lines[0])
1026
+ assert_match("ABC: DEF", lines[4])
1027
+ assert_match("ABC: DEF", lines[5])
1028
+ end
1029
+
1030
+ def test_http_custom_date_header
1031
+ @client.debug_dev = (str = "")
1032
+ res = @client.get(serverurl + 'hello', :header => {'Date' => 'foo'})
1033
+ lines = str.split(/(?:\r?\n)+/)
1034
+ assert_equal('Date: foo', lines[4])
1035
+ end
1036
+
1037
+ def test_timeout
1038
+ assert_equal(60, @client.connect_timeout)
1039
+ assert_equal(120, @client.send_timeout)
1040
+ assert_equal(60, @client.receive_timeout)
1041
+ #
1042
+ @client.connect_timeout = 1
1043
+ @client.send_timeout = 2
1044
+ @client.receive_timeout = 3
1045
+ assert_equal(1, @client.connect_timeout)
1046
+ assert_equal(2, @client.send_timeout)
1047
+ assert_equal(3, @client.receive_timeout)
1048
+ end
1049
+
1050
+ def test_connect_timeout
1051
+ # ToDo
1052
+ end
1053
+
1054
+ def test_send_timeout
1055
+ # ToDo
1056
+ end
1057
+
1058
+ def test_receive_timeout
1059
+ # this test takes 2 sec
1060
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1061
+ @client.receive_timeout = 1
1062
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0'))
1063
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
1064
+ @client.get_content(serverurl + 'sleep?sec=2')
1065
+ end
1066
+ @client.receive_timeout = 3
1067
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1068
+ end
1069
+
1070
+ def test_receive_timeout_post
1071
+ # this test takes 2 sec
1072
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1073
+ @client.receive_timeout = 1
1074
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 0).content)
1075
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
1076
+ @client.post(serverurl + 'sleep', :sec => 2)
1077
+ end
1078
+ @client.receive_timeout = 3
1079
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1080
+ end
1081
+
1082
+ # disable for now -- does not work
1083
+ #def test_async_error
1084
+ # assert_raise( SocketError ) do
1085
+ # conn = @client.get_async("http://non-existing-host/")
1086
+ # conn.pop
1087
+ # end
1088
+ #end
1089
+
1090
+ def test_reset
1091
+ url = serverurl + 'servlet'
1092
+ assert_nothing_raised do
1093
+ 5.times do
1094
+ @client.get(url)
1095
+ @client.reset(url)
1096
+ end
1097
+ end
1098
+ end
1099
+
1100
+ def test_reset_all
1101
+ assert_nothing_raised do
1102
+ 5.times do
1103
+ @client.get(serverurl + 'servlet')
1104
+ @client.reset_all
1105
+ end
1106
+ end
1107
+ end
1108
+
1109
+ def test_cookies
1110
+ cookiefile = File.join(File.dirname(File.expand_path(__FILE__)), 'test_cookies_file')
1111
+ File.open(cookiefile, "wb") do |f|
1112
+ f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\t.rubyforge.org\t/\t13\n"
1113
+ end
1114
+ @client.set_cookie_store(cookiefile)
1115
+ cookie = @client.cookie_manager.cookies.first
1116
+ url = cookie.url
1117
+ assert(cookie.domain_match(url.host, cookie.domain))
1118
+ #
1119
+ @client.reset_all
1120
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\nSet-Cookie: foo=bar; expires=#{Time.at(1924873200).gmtime.httpdate}\n\nOK"
1121
+ @client.get_content('http://rubyforge.org/account/login.php')
1122
+ @client.save_cookie_store
1123
+ str = File.read(cookiefile)
1124
+ assert_match(%r(http://rubyforge.org/account/login.php\tfoo\tbar\t1924873200\trubyforge.org\t/account\t1), str)
1125
+ File.unlink(cookiefile)
1126
+ end
1127
+
1128
+ def test_eof_error_length
1129
+ io = StringIO.new('')
1130
+ def io.gets(*arg)
1131
+ @buf ||= ["HTTP/1.0 200 OK\n", "content-length: 123\n", "\n"]
1132
+ @buf.shift
1133
+ end
1134
+ def io.readpartial(size, buf)
1135
+ @second ||= false
1136
+ if !@second
1137
+ @second = '1st'
1138
+ buf << "abc"
1139
+ buf
1140
+ elsif @second == '1st'
1141
+ @second = '2nd'
1142
+ raise EOFError.new
1143
+ else
1144
+ raise Exception.new
1145
+ end
1146
+ end
1147
+ def io.eof?
1148
+ true
1149
+ end
1150
+ @client.test_loopback_http_response << io
1151
+ assert_nothing_raised do
1152
+ @client.get('http://foo/bar')
1153
+ end
1154
+ end
1155
+
1156
+ def test_eof_error_rest
1157
+ io = StringIO.new('')
1158
+ def io.gets(*arg)
1159
+ @buf ||= ["HTTP/1.0 200 OK\n", "\n"]
1160
+ @buf.shift
1161
+ end
1162
+ def io.readpartial(size, buf)
1163
+ @second ||= false
1164
+ if !@second
1165
+ @second = '1st'
1166
+ buf << "abc"
1167
+ buf
1168
+ elsif @second == '1st'
1169
+ @second = '2nd'
1170
+ raise EOFError.new
1171
+ else
1172
+ raise Exception.new
1173
+ end
1174
+ end
1175
+ def io.eof?
1176
+ true
1177
+ end
1178
+ @client.test_loopback_http_response << io
1179
+ assert_nothing_raised do
1180
+ @client.get('http://foo/bar')
1181
+ end
1182
+ end
1183
+
1184
+ def test_urify
1185
+ extend HTTPClient::Util
1186
+ assert_nil(urify(nil))
1187
+ uri = 'http://foo'
1188
+ assert_equal(urify(uri), urify(uri))
1189
+ assert_equal(urify(uri), urify(urify(uri)))
1190
+ end
1191
+
1192
+ def test_connection
1193
+ c = HTTPClient::Connection.new
1194
+ assert(c.finished?)
1195
+ assert_nil(c.join)
1196
+ end
1197
+
1198
+ def test_site
1199
+ site = HTTPClient::Site.new
1200
+ assert_equal('tcp', site.scheme)
1201
+ assert_equal('0.0.0.0', site.host)
1202
+ assert_equal(0, site.port)
1203
+ assert_equal('tcp://0.0.0.0:0', site.addr)
1204
+ assert_equal('tcp://0.0.0.0:0', site.to_s)
1205
+ assert_nothing_raised do
1206
+ site.inspect
1207
+ end
1208
+ #
1209
+ site = HTTPClient::Site.new(urify('http://localhost:12345/foo'))
1210
+ assert_equal('http', site.scheme)
1211
+ assert_equal('localhost', site.host)
1212
+ assert_equal(12345, site.port)
1213
+ assert_equal('http://localhost:12345', site.addr)
1214
+ assert_equal('http://localhost:12345', site.to_s)
1215
+ assert_nothing_raised do
1216
+ site.inspect
1217
+ end
1218
+ #
1219
+ site1 = HTTPClient::Site.new(urify('http://localhost:12341/'))
1220
+ site2 = HTTPClient::Site.new(urify('http://localhost:12342/'))
1221
+ site3 = HTTPClient::Site.new(urify('http://localhost:12342/'))
1222
+ assert(!(site1 == site2))
1223
+ h = { site1 => 'site1', site2 => 'site2' }
1224
+ h[site3] = 'site3'
1225
+ assert_equal('site1', h[site1])
1226
+ assert_equal('site3', h[site2])
1227
+ end
1228
+
1229
+ def test_http_header
1230
+ res = @client.get(serverurl + 'hello')
1231
+ assert_equal('text/html', res.contenttype)
1232
+ assert_equal(5, res.header.get(nil).size)
1233
+ #
1234
+ res.header.delete('connection')
1235
+ assert_equal(4, res.header.get(nil).size)
1236
+ #
1237
+ res.header['foo'] = 'bar'
1238
+ assert_equal(['bar'], res.header['foo'])
1239
+ #
1240
+ assert_equal([['foo', 'bar']], res.header.get('foo'))
1241
+ res.header['foo'] = ['bar', 'bar2']
1242
+ assert_equal([['foo', 'bar'], ['foo', 'bar2']], res.header.get('foo'))
1243
+ end
1244
+
1245
+ def test_mime_type
1246
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1247
+ assert_equal('text/html', HTTP::Message.mime_type('foo.html'))
1248
+ assert_equal('text/html', HTTP::Message.mime_type('foo.htm'))
1249
+ assert_equal('application/msword', HTTP::Message.mime_type('foo.doc'))
1250
+ assert_equal('image/png', HTTP::Message.mime_type('foo.png'))
1251
+ assert_equal('image/gif', HTTP::Message.mime_type('foo.gif'))
1252
+ assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpg'))
1253
+ assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpeg'))
1254
+ assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.unknown'))
1255
+ #
1256
+ handler = lambda { |path| 'hello/world' }
1257
+ assert_nil(HTTP::Message.mime_type_handler)
1258
+ assert_nil(HTTP::Message.get_mime_type_func)
1259
+ HTTP::Message.mime_type_handler = handler
1260
+ assert_not_nil(HTTP::Message.mime_type_handler)
1261
+ assert_not_nil(HTTP::Message.get_mime_type_func)
1262
+ assert_equal('hello/world', HTTP::Message.mime_type('foo.txt'))
1263
+ HTTP::Message.mime_type_handler = nil
1264
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1265
+ HTTP::Message.set_mime_type_func(nil)
1266
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1267
+ #
1268
+ handler = lambda { |path| nil }
1269
+ HTTP::Message.mime_type_handler = handler
1270
+ assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.txt'))
1271
+ end
1272
+
1273
+ def test_connect_request
1274
+ req = HTTP::Message.new_connect_request(urify('https://foo/bar'))
1275
+ assert_equal("CONNECT foo:443 HTTP/1.0\r\n\r\n", req.dump)
1276
+ req = HTTP::Message.new_connect_request(urify('https://example.com/'))
1277
+ assert_equal("CONNECT example.com:443 HTTP/1.0\r\n\r\n", req.dump)
1278
+ end
1279
+
1280
+ def test_response
1281
+ res = HTTP::Message.new_response('response')
1282
+ res.contenttype = 'text/plain'
1283
+ res.header.body_date = Time.at(946652400)
1284
+ assert_equal(
1285
+ [
1286
+ "",
1287
+ "Content-Length: 8",
1288
+ "Content-Type: text/plain",
1289
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1290
+ "Status: 200 OK",
1291
+ "response"
1292
+ ],
1293
+ res.dump.split(/\r\n/).sort
1294
+ )
1295
+ assert_equal(['8'], res.header['Content-Length'])
1296
+ assert_equal('8', res.headers['Content-Length'])
1297
+ res.header.set('foo', 'bar')
1298
+ assert_equal(
1299
+ [
1300
+ "",
1301
+ "Content-Length: 8",
1302
+ "Content-Type: text/plain",
1303
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1304
+ "Status: 200 OK",
1305
+ "foo: bar",
1306
+ "response"
1307
+ ],
1308
+ res.dump.split(/\r\n/).sort
1309
+ )
1310
+ # nil body
1311
+ res = HTTP::Message.new_response(nil)
1312
+ assert_equal(
1313
+ [
1314
+ "Content-Length: 0",
1315
+ "Content-Type: text/html; charset=us-ascii",
1316
+ "Status: 200 OK"
1317
+ ],
1318
+ res.dump.split(/\r\n/).sort
1319
+ )
1320
+ # for mod_ruby env
1321
+ Object.const_set('Apache', nil)
1322
+ begin
1323
+ res = HTTP::Message.new_response('response')
1324
+ assert(res.dump.split(/\r\n/).any? { |line| /^Date/ =~ line })
1325
+ #
1326
+ res = HTTP::Message.new_response('response')
1327
+ res.contenttype = 'text/plain'
1328
+ res.header.body_date = Time.at(946652400)
1329
+ res.header['Date'] = Time.at(946652400).httpdate
1330
+ assert_equal(
1331
+ [
1332
+ "",
1333
+ "Content-Length: 8",
1334
+ "Content-Type: text/plain",
1335
+ "Date: Fri, 31 Dec 1999 15:00:00 GMT",
1336
+ "HTTP/1.1 200 OK",
1337
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1338
+ "response"
1339
+ ],
1340
+ res.dump.split(/\r\n/).sort
1341
+ )
1342
+ ensure
1343
+ Object.instance_eval { remove_const('Apache') }
1344
+ end
1345
+ end
1346
+
1347
+ def test_response_cookies
1348
+ res = HTTP::Message.new_response('response')
1349
+ res.contenttype = 'text/plain'
1350
+ res.header.body_date = Time.at(946652400)
1351
+ assert_nil(res.cookies)
1352
+ #
1353
+ res.header['Set-Cookie'] = [
1354
+ 'CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT',
1355
+ 'PART_NUMBER=ROCKET_LAUNCHER_0001; path=/'
1356
+ ]
1357
+ assert_equal(
1358
+ [
1359
+ "",
1360
+ "Content-Length: 8",
1361
+ "Content-Type: text/plain",
1362
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1363
+ "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT",
1364
+ "Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/",
1365
+ "Status: 200 OK",
1366
+ "response"
1367
+ ],
1368
+ res.dump.split(/\r\n/).sort
1369
+ )
1370
+ assert_equal(2, res.cookies.size)
1371
+ assert_equal('CUSTOMER', res.cookies[0].name)
1372
+ assert_equal('PART_NUMBER', res.cookies[1].name)
1373
+ end
1374
+
1375
+ def test_ok_response_success
1376
+ res = HTTP::Message.new_response('response')
1377
+ assert_equal(true, res.ok?)
1378
+ res.status = 404
1379
+ assert_equal(false, res.ok?)
1380
+ res.status = 500
1381
+ assert_equal(false, res.ok?)
1382
+ res.status = 302
1383
+ assert_equal(false, res.ok?)
1384
+ end
1385
+
1386
+ if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9'
1387
+ def test_timeout_scheduler
1388
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1389
+ status = HTTPClient.timeout_scheduler.instance_eval { @thread.kill; @thread.join; @thread.status }
1390
+ assert(!status) # dead
1391
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1392
+ end
1393
+ end
1394
+
1395
+ def test_session_manager
1396
+ mgr = HTTPClient::SessionManager.new(@client)
1397
+ assert_nil(mgr.instance_eval { @proxy })
1398
+ assert_nil(mgr.debug_dev)
1399
+ @client.debug_dev = Object.new
1400
+ @client.proxy = 'http://myproxy:12345'
1401
+ mgr = HTTPClient::SessionManager.new(@client)
1402
+ assert_equal('http://myproxy:12345', mgr.instance_eval { @proxy }.to_s)
1403
+ assert_equal(@client.debug_dev, mgr.debug_dev)
1404
+ end
1405
+
1406
+ def create_keepalive_disconnected_thread(idx, sock)
1407
+ Thread.new {
1408
+ # return "12345" for the first connection
1409
+ sock.gets
1410
+ sock.gets
1411
+ sock.write("HTTP/1.1 200 OK\r\n")
1412
+ sock.write("Content-Length: 5\r\n")
1413
+ sock.write("\r\n")
1414
+ sock.write("12345")
1415
+ # for the next connection, close while reading the request for emulating
1416
+ # KeepAliveDisconnected
1417
+ sock.gets
1418
+ sock.close
1419
+ }
1420
+ end
1421
+
1422
+ def test_keepalive_disconnected
1423
+ client = HTTPClient.new
1424
+ server = TCPServer.open('127.0.0.1', 0)
1425
+ server.listen(30) # set enough backlogs
1426
+ endpoint = "http://127.0.0.1:#{server.addr[1]}/"
1427
+ Thread.new {
1428
+ Thread.abort_on_exception = true
1429
+ # emulate 10 keep-alive connections
1430
+ 10.times do |idx|
1431
+ sock = server.accept
1432
+ create_keepalive_disconnected_thread(idx, sock)
1433
+ end
1434
+ # return "23456" for the request which gets KeepAliveDisconnected
1435
+ 5.times do
1436
+ sock = server.accept
1437
+ sock.gets
1438
+ sock.gets
1439
+ sock.write("HTTP/1.1 200 OK\r\n")
1440
+ sock.write("\r\n")
1441
+ sock.write("23456")
1442
+ sock.close
1443
+ end
1444
+ # return "34567" for the rest requests
1445
+ while true
1446
+ sock = server.accept
1447
+ sock.gets
1448
+ sock.gets
1449
+ sock.write("HTTP/1.1 200 OK\r\n")
1450
+ sock.write("Connection: close\r\n")
1451
+ sock.write("Content-Length: 5\r\n")
1452
+ sock.write("\r\n")
1453
+ sock.write("34567")
1454
+ sock.close
1455
+ end
1456
+ }
1457
+ # allocate 10 keep-alive connections
1458
+ (0...10).to_a.map {
1459
+ Thread.new {
1460
+ assert_equal("12345", client.get(endpoint).content)
1461
+ }
1462
+ }.each { |th| th.join }
1463
+ # send 5 requests, which should get KeepAliveDesconnected.
1464
+ # doing these requests, rest keep-alive connections are invalidated.
1465
+ (0...5).to_a.map {
1466
+ Thread.new {
1467
+ assert_equal("23456", client.get(endpoint).content)
1468
+ }
1469
+ }.each { |th| th.join }
1470
+ # rest requests won't get KeepAliveDisconnected; how can I check this?
1471
+ (0...10).to_a.map {
1472
+ Thread.new {
1473
+ assert_equal("34567", client.get(endpoint).content)
1474
+ }
1475
+ }.each { |th| th.join }
1476
+ end
1477
+
1478
+ def create_keepalive_thread(count, sock)
1479
+ Thread.new {
1480
+ Thread.abort_on_exception = true
1481
+ count.times do
1482
+ req = sock.gets
1483
+ while line = sock.gets
1484
+ break if line.chomp.empty?
1485
+ end
1486
+ case req
1487
+ when /chunked/
1488
+ sock.write("HTTP/1.1 200 OK\r\n")
1489
+ sock.write("Transfer-Encoding: chunked\r\n")
1490
+ sock.write("\r\n")
1491
+ sock.write("1a\r\n")
1492
+ sock.write("abcdefghijklmnopqrstuvwxyz\r\n")
1493
+ sock.write("10\r\n")
1494
+ sock.write("1234567890abcdef\r\n")
1495
+ sock.write("0\r\n")
1496
+ sock.write("\r\n")
1497
+ else
1498
+ sock.write("HTTP/1.1 200 OK\r\n")
1499
+ sock.write("Content-Length: 5\r\n")
1500
+ sock.write("\r\n")
1501
+ sock.write("12345")
1502
+ end
1503
+ end
1504
+ sock.close
1505
+ }
1506
+ end
1507
+
1508
+ def test_keepalive
1509
+ server = TCPServer.open('localhost', 0)
1510
+ server_thread = Thread.new {
1511
+ Thread.abort_on_exception = true
1512
+ sock = server.accept
1513
+ create_keepalive_thread(10, sock)
1514
+ }
1515
+ url = "http://localhost:#{server.addr[1]}/"
1516
+ begin
1517
+ # content-length
1518
+ 5.times do
1519
+ assert_equal('12345', @client.get(url).body)
1520
+ end
1521
+ # chunked
1522
+ 5.times do
1523
+ assert_equal('abcdefghijklmnopqrstuvwxyz1234567890abcdef', @client.get(url + 'chunked').body)
1524
+ end
1525
+ ensure
1526
+ server.close
1527
+ server_thread.join
1528
+ end
1529
+ end
1530
+
1531
+ def test_socket_local
1532
+ @client.socket_local.host = '127.0.0.1'
1533
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1534
+ @client.reset_all
1535
+ @client.socket_local.port = serverport
1536
+ begin
1537
+ @client.get_content(serverurl + 'hello')
1538
+ rescue Errno::EADDRINUSE, SocketError
1539
+ assert(true)
1540
+ end
1541
+ end
1542
+
1543
+ def test_body_param_order
1544
+ ary = ('b'..'d').map { |k| ['key2', k] } << ['key1', 'a'] << ['key3', 'z']
1545
+ assert_equal("key2=b&key2=c&key2=d&key1=a&key3=z", HTTP::Message.escape_query(ary))
1546
+ end
1547
+
1548
+ if RUBY_VERSION > "1.9"
1549
+ def test_charset
1550
+ body = @client.get(serverurl + 'charset').body
1551
+ assert_equal(Encoding::EUC_JP, body.encoding)
1552
+ assert_equal('あいうえお'.encode(Encoding::EUC_JP), body)
1553
+ end
1554
+ end
1555
+
1556
+ if RUBY_VERSION >= "1.9.3"
1557
+ def test_continue
1558
+ @client.debug_dev = str = ''
1559
+ res = @client.get(serverurl + 'continue', :header => {:Expect => '100-continue'})
1560
+ assert_equal(200, res.status)
1561
+ assert_equal('done!', res.body)
1562
+ assert_match(/Expect: 100-continue/, str)
1563
+ end
1564
+ end
1565
+
1566
+ def test_ipv6literaladdress_in_uri
1567
+ server = TCPServer.open('::1', 0) rescue return # Skip if IPv6 is unavailable.
1568
+ server_thread = Thread.new {
1569
+ Thread.abort_on_exception = true
1570
+ sock = server.accept
1571
+ while line = sock.gets
1572
+ break if line.chomp.empty?
1573
+ end
1574
+ sock.write("HTTP/1.1 200 OK\r\n")
1575
+ sock.write("Content-Length: 5\r\n")
1576
+ sock.write("\r\n")
1577
+ sock.write("12345")
1578
+ sock.close
1579
+ }
1580
+ uri = "http://[::1]:#{server.addr[1]}/"
1581
+ begin
1582
+ assert_equal('12345', @client.get(uri).body)
1583
+ ensure
1584
+ server.close
1585
+ server_thread.kill
1586
+ server_thread.join
1587
+ end
1588
+ end
1589
+
1590
+ private
1591
+
1592
+ def check_query_get(query)
1593
+ WEBrick::HTTPUtils.parse_query(
1594
+ @client.get(serverurl + 'servlet', query).header["x-query"][0]
1595
+ )
1596
+ end
1597
+
1598
+ def check_query_post(query)
1599
+ WEBrick::HTTPUtils.parse_query(
1600
+ @client.post(serverurl + 'servlet', query).header["x-query"][0]
1601
+ )
1602
+ end
1603
+
1604
+ def setup_server
1605
+ @server = WEBrick::HTTPServer.new(
1606
+ :BindAddress => "localhost",
1607
+ :Logger => @logger,
1608
+ :Port => 0,
1609
+ :AccessLog => [],
1610
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__))
1611
+ )
1612
+ @serverport = @server.config[:Port]
1613
+ [
1614
+ :hello, :sleep, :servlet_redirect, :servlet_temporary_redirect, :servlet_see_other,
1615
+ :redirect1, :redirect2, :redirect3,
1616
+ :redirect_self, :relative_redirect, :redirect_see_other, :chunked,
1617
+ :largebody, :status, :compressed, :charset, :continue
1618
+ ].each do |sym|
1619
+ @server.mount(
1620
+ "/#{sym}",
1621
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
1622
+ )
1623
+ end
1624
+ @server.mount('/servlet', TestServlet.new(@server))
1625
+ @server_thread = start_server_thread(@server)
1626
+ end
1627
+
1628
+ def escape_noproxy
1629
+ backup = HTTPClient::NO_PROXY_HOSTS.dup
1630
+ HTTPClient::NO_PROXY_HOSTS.clear
1631
+ yield
1632
+ ensure
1633
+ HTTPClient::NO_PROXY_HOSTS.replace(backup)
1634
+ end
1635
+
1636
+ def do_hello(req, res)
1637
+ res['content-type'] = 'text/html'
1638
+ res.body = "hello"
1639
+ end
1640
+
1641
+ def do_sleep(req, res)
1642
+ sec = req.query['sec'].to_i
1643
+ sleep sec
1644
+ res['content-type'] = 'text/html'
1645
+ res.body = "hello"
1646
+ end
1647
+
1648
+ def do_servlet_redirect(req, res)
1649
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet")
1650
+ end
1651
+ def do_servlet_temporary_redirect(req, res)
1652
+ res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "servlet")
1653
+ end
1654
+ def do_servlet_see_other(req, res)
1655
+ res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "servlet")
1656
+ end
1657
+
1658
+ def do_redirect1(req, res)
1659
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello")
1660
+ end
1661
+
1662
+ def do_redirect2(req, res)
1663
+ res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3")
1664
+ end
1665
+
1666
+ def do_redirect3(req, res)
1667
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello")
1668
+ end
1669
+
1670
+ def do_redirect_self(req, res)
1671
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self")
1672
+ end
1673
+
1674
+ def do_relative_redirect(req, res)
1675
+ res.set_redirect(WEBrick::HTTPStatus::Found, "hello")
1676
+ end
1677
+
1678
+ def do_redirect_see_other(req, res)
1679
+ if req.request_method == 'POST'
1680
+ res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other") # self
1681
+ else
1682
+ res.body = 'hello'
1683
+ end
1684
+ end
1685
+
1686
+ def do_chunked(req, res)
1687
+ res.chunked = true
1688
+ piper, pipew = IO.pipe
1689
+ res.body = piper
1690
+ pipew << req.query['msg']
1691
+ pipew.close
1692
+ end
1693
+
1694
+ def do_largebody(req, res)
1695
+ res['content-type'] = 'text/html'
1696
+ res.body = "a" * 1000 * 1000
1697
+ end
1698
+
1699
+ def do_compressed(req, res)
1700
+ res['content-type'] = 'application/octet-stream'
1701
+ if req.query['enc'] == 'gzip'
1702
+ res['content-encoding'] = 'gzip'
1703
+ res.body = GZIP_CONTENT
1704
+ elsif req.query['enc'] == 'deflate'
1705
+ res['content-encoding'] = 'deflate'
1706
+ res.body = DEFLATE_CONTENT
1707
+ end
1708
+ end
1709
+
1710
+ def do_charset(req, res)
1711
+ if RUBY_VERSION > "1.9"
1712
+ res.body = 'あいうえお'.encode("euc-jp")
1713
+ res['Content-Type'] = 'text/plain; charset=euc-jp'
1714
+ else
1715
+ res.body = 'this endpoint is for 1.9 or later'
1716
+ end
1717
+ end
1718
+
1719
+ def do_status(req, res)
1720
+ res.status = req.query['status'].to_i
1721
+ end
1722
+
1723
+ def do_continue(req, res)
1724
+ req.continue
1725
+ res.body = 'done!'
1726
+ end
1727
+
1728
+ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
1729
+ def get_instance(*arg)
1730
+ self
1731
+ end
1732
+
1733
+ def do_HEAD(req, res)
1734
+ res["x-head"] = 'head' # use this for test purpose only.
1735
+ res["x-query"] = query_response(req)
1736
+ end
1737
+
1738
+ def do_GET(req, res)
1739
+ res.body = 'get'
1740
+ res["x-query"] = query_response(req)
1741
+ end
1742
+
1743
+ def do_POST(req, res)
1744
+ res["content-type"] = "text/plain" # iso-8859-1, not US-ASCII
1745
+ res.body = 'post,' + req.body.to_s
1746
+ res["x-query"] = body_response(req)
1747
+ end
1748
+
1749
+ def do_PUT(req, res)
1750
+ res["x-query"] = body_response(req)
1751
+ param = WEBrick::HTTPUtils.parse_query(req.body) || {}
1752
+ res["x-size"] = (param['txt'] || '').size
1753
+ res.body = param['txt'] || 'put'
1754
+ end
1755
+
1756
+ def do_DELETE(req, res)
1757
+ res.body = 'delete'
1758
+ end
1759
+
1760
+ def do_OPTIONS(req, res)
1761
+ # check RFC for legal response.
1762
+ res.body = 'options'
1763
+ end
1764
+
1765
+ def do_PROPFIND(req, res)
1766
+ res.body = 'propfind'
1767
+ end
1768
+
1769
+ def do_PROPPATCH(req, res)
1770
+ res.body = 'proppatch'
1771
+ res["x-query"] = body_response(req)
1772
+ end
1773
+
1774
+ def do_TRACE(req, res)
1775
+ # client SHOULD reflect the message received back to the client as the
1776
+ # entity-body of a 200 (OK) response. [RFC2616]
1777
+ res.body = 'trace'
1778
+ res["x-query"] = query_response(req)
1779
+ end
1780
+
1781
+ private
1782
+
1783
+ def query_response(req)
1784
+ query_escape(WEBrick::HTTPUtils.parse_query(req.query_string))
1785
+ end
1786
+
1787
+ def body_response(req)
1788
+ query_escape(WEBrick::HTTPUtils.parse_query(req.body))
1789
+ end
1790
+
1791
+ def query_escape(query)
1792
+ escaped = []
1793
+ query.sort_by { |k, v| k }.collect do |k, v|
1794
+ v.to_ary.each do |ve|
1795
+ escaped << CGI.escape(k) + '=' + CGI.escape(ve)
1796
+ end
1797
+ end
1798
+ escaped.join('&')
1799
+ end
1800
+ end
1801
+ end