httpclient-jgraichen 2.3.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/README.txt +759 -0
  3. data/bin/httpclient +65 -0
  4. data/lib/hexdump.rb +50 -0
  5. data/lib/http-access2.rb +55 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/httpclient.rb +1156 -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 +1046 -0
  14. data/lib/httpclient/include_client.rb +83 -0
  15. data/lib/httpclient/session.rb +1028 -0
  16. data/lib/httpclient/ssl_config.rb +405 -0
  17. data/lib/httpclient/timeout.rb +140 -0
  18. data/lib/httpclient/util.rb +178 -0
  19. data/lib/httpclient/version.rb +3 -0
  20. data/lib/oauthclient.rb +110 -0
  21. data/sample/async.rb +8 -0
  22. data/sample/auth.rb +11 -0
  23. data/sample/cookie.rb +18 -0
  24. data/sample/dav.rb +103 -0
  25. data/sample/howto.rb +49 -0
  26. data/sample/oauth_buzz.rb +57 -0
  27. data/sample/oauth_friendfeed.rb +59 -0
  28. data/sample/oauth_twitter.rb +61 -0
  29. data/sample/ssl/0cert.pem +22 -0
  30. data/sample/ssl/0key.pem +30 -0
  31. data/sample/ssl/1000cert.pem +19 -0
  32. data/sample/ssl/1000key.pem +18 -0
  33. data/sample/ssl/htdocs/index.html +10 -0
  34. data/sample/ssl/ssl_client.rb +22 -0
  35. data/sample/ssl/webrick_httpsd.rb +29 -0
  36. data/sample/stream.rb +21 -0
  37. data/sample/thread.rb +27 -0
  38. data/sample/wcat.rb +21 -0
  39. data/test/ca-chain.cert +44 -0
  40. data/test/ca.cert +23 -0
  41. data/test/client.cert +19 -0
  42. data/test/client.key +15 -0
  43. data/test/helper.rb +129 -0
  44. data/test/htdigest +1 -0
  45. data/test/htpasswd +2 -0
  46. data/test/runner.rb +2 -0
  47. data/test/server.cert +19 -0
  48. data/test/server.key +15 -0
  49. data/test/sslsvr.rb +65 -0
  50. data/test/subca.cert +21 -0
  51. data/test/test_auth.rb +348 -0
  52. data/test/test_cookie.rb +412 -0
  53. data/test/test_hexdump.rb +14 -0
  54. data/test/test_http-access2.rb +507 -0
  55. data/test/test_httpclient.rb +1783 -0
  56. data/test/test_include_client.rb +52 -0
  57. data/test/test_ssl.rb +235 -0
  58. metadata +100 -0
@@ -0,0 +1,1783 @@
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
+ assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet_redirect', post_body))
609
+ #
610
+ post_body = StringIO.new("1234567890")
611
+ post_body.read(5)
612
+ assert_equal('post,67890', @client.post_content(serverurl + 'servlet_redirect', post_body))
613
+ end
614
+
615
+ def test_head
616
+ assert_equal("head", @client.head(serverurl + 'servlet').header["x-head"][0])
617
+ param = {'1'=>'2', '3'=>'4'}
618
+ res = @client.head(serverurl + 'servlet', param)
619
+ assert_equal(param, params(res.header["x-query"][0]))
620
+ end
621
+
622
+ def test_head_async
623
+ param = {'1'=>'2', '3'=>'4'}
624
+ conn = @client.head_async(serverurl + 'servlet', param)
625
+ Thread.pass while !conn.finished?
626
+ res = conn.pop
627
+ assert_equal(param, params(res.header["x-query"][0]))
628
+ end
629
+
630
+ def test_get
631
+ assert_equal("get", @client.get(serverurl + 'servlet').content)
632
+ param = {'1'=>'2', '3'=>'4'}
633
+ res = @client.get(serverurl + 'servlet', param)
634
+ assert_equal(param, params(res.header["x-query"][0]))
635
+ assert_nil(res.contenttype)
636
+ #
637
+ url = serverurl.to_s + 'servlet?5=6&7=8'
638
+ res = @client.get(url, param)
639
+ assert_equal(param.merge("5"=>"6", "7"=>"8"), params(res.header["x-query"][0]))
640
+ assert_nil(res.contenttype)
641
+ end
642
+
643
+ def test_head_follow_redirect
644
+ expected = urify(serverurl + 'hello')
645
+ assert_equal(expected, @client.head(serverurl + 'hello', :follow_redirect => true).header.request_uri)
646
+ assert_equal(expected, @client.head(serverurl + 'redirect1', :follow_redirect => true).header.request_uri)
647
+ assert_equal(expected, @client.head(serverurl + 'redirect2', :follow_redirect => true).header.request_uri)
648
+ end
649
+
650
+ def test_get_follow_redirect
651
+ assert_equal('hello', @client.get(serverurl + 'hello', :follow_redirect => true).body)
652
+ assert_equal('hello', @client.get(serverurl + 'redirect1', :follow_redirect => true).body)
653
+ assert_equal('hello', @client.get(serverurl + 'redirect2', :follow_redirect => true).body)
654
+ end
655
+
656
+ def test_get_async
657
+ param = {'1'=>'2', '3'=>'4'}
658
+ conn = @client.get_async(serverurl + 'servlet', param)
659
+ Thread.pass while !conn.finished?
660
+ res = conn.pop
661
+ assert_equal(param, params(res.header["x-query"][0]))
662
+ end
663
+
664
+ def test_get_async_for_largebody
665
+ conn = @client.get_async(serverurl + 'largebody')
666
+ res = conn.pop
667
+ assert_equal(1000*1000, res.content.read.length)
668
+ end
669
+
670
+ def test_get_with_block
671
+ called = false
672
+ res = @client.get(serverurl + 'servlet') { |str|
673
+ assert_equal('get', str)
674
+ called = true
675
+ }
676
+ assert(called)
677
+ # res does not have a content
678
+ assert_nil(res.content)
679
+ end
680
+
681
+ def test_get_with_block_chunk_string_recycle
682
+ @client.read_block_size = 2
683
+ body = []
684
+ res = @client.get(serverurl + 'servlet') { |str|
685
+ body << str
686
+ }
687
+ assert_equal(2, body.size)
688
+ assert_equal("get", body.join) # Was "tt" by String object recycle...
689
+ end
690
+
691
+ def test_post
692
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4])
693
+ param = {'1'=>'2', '3'=>'4'}
694
+ res = @client.post(serverurl + 'servlet', param)
695
+ assert_equal(param, params(res.header["x-query"][0]))
696
+ end
697
+
698
+ def test_post_follow_redirect
699
+ assert_equal('hello', @client.post(serverurl + 'hello', :follow_redirect => true).body)
700
+ assert_equal('hello', @client.post(serverurl + 'redirect1', :follow_redirect => true).body)
701
+ assert_equal('hello', @client.post(serverurl + 'redirect2', :follow_redirect => true).body)
702
+ end
703
+
704
+ def test_post_with_content_type
705
+ param = [['1', '2'], ['3', '4']]
706
+ ext = {'content-type' => 'application/x-www-form-urlencoded', 'hello' => 'world'}
707
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
708
+ res = @client.post(serverurl + 'servlet', param, ext)
709
+ assert_equal(Hash[param], params(res.header["x-query"][0]))
710
+ #
711
+ ext = [['content-type', 'multipart/form-data'], ['hello', 'world']]
712
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
713
+ res = @client.post(serverurl + 'servlet', param, ext)
714
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
715
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
716
+ #
717
+ ext = {'content-type' => 'multipart/form-data; boundary=hello'}
718
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
719
+ res = @client.post(serverurl + 'servlet', param, ext)
720
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
721
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
722
+ 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)
723
+ end
724
+
725
+ def test_post_with_custom_multipart_and_boolean_params
726
+ param = [['boolean_true', true]]
727
+ ext = { 'content-type' => 'multipart/form-data' }
728
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
729
+ res = @client.post(serverurl + 'servlet', param, ext)
730
+ assert_match(/Content-Disposition: form-data; name="boolean_true"\r\n\r\ntrue\r\n/, res.content)
731
+ #
732
+ param = [['boolean_false', false]]
733
+ res = @client.post(serverurl + 'servlet', param, ext)
734
+ assert_match(/Content-Disposition: form-data; name="boolean_false"\r\n\r\nfalse\r\n/, res.content)
735
+ #
736
+ param = [['nil', nil]]
737
+ res = @client.post(serverurl + 'servlet', param, ext)
738
+ assert_match(/Content-Disposition: form-data; name="nil"\r\n\r\n\r\n/, res.content)
739
+ end
740
+
741
+ def test_post_with_file
742
+ STDOUT.sync = true
743
+ File.open(__FILE__) do |file|
744
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>file})
745
+ assert_match(/^Content-Disposition: form-data; name="1"\r\n/nm, res.content)
746
+ assert_match(/^Content-Disposition: form-data; name="3";/, res.content)
747
+ assert_match(/FIND_TAG_IN_THIS_FILE/, res.content)
748
+ end
749
+ end
750
+
751
+ def test_post_with_file_without_size
752
+ STDOUT.sync = true
753
+ File.open(__FILE__) do |file|
754
+ def file.size
755
+ # Simulates some strange Windows behaviour
756
+ raise SystemCallError.new "Unknown Error (20047)"
757
+ end
758
+ assert_nothing_raised do
759
+ @client.post(serverurl + 'servlet', {1=>2, 3=>file})
760
+ end
761
+ end
762
+ end
763
+
764
+ def test_post_with_io # streaming, but not chunked
765
+ myio = StringIO.new("X" * (HTTP::Message::Body::DEFAULT_CHUNK_SIZE + 1))
766
+ def myio.read(*args)
767
+ @called ||= 0
768
+ @called += 1
769
+ super
770
+ end
771
+ def myio.called
772
+ @called
773
+ end
774
+ @client.debug_dev = str = StringIO.new
775
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio})
776
+ assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content)
777
+ assert_match(/\r\n2\r\n/m, res.content)
778
+ assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content)
779
+ assert_match(/\r\nContent-Length:/m, str.string)
780
+ assert_equal(3, myio.called)
781
+ end
782
+
783
+ def test_post_with_io_nosize # streaming + chunked post
784
+ myio = StringIO.new("4")
785
+ def myio.size
786
+ nil
787
+ end
788
+ @client.debug_dev = str = StringIO.new
789
+ res = @client.post(serverurl + 'servlet', {1=>2, 3=>myio})
790
+ assert_match(/\r\nContent-Disposition: form-data; name="1"\r\n/m, res.content)
791
+ assert_match(/\r\n2\r\n/m, res.content)
792
+ assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content)
793
+ assert_match(/\r\n4\r\n/m, res.content)
794
+ assert_match(/\r\nTransfer-Encoding: chunked\r\n/m, str.string)
795
+ end
796
+
797
+ def test_post_async
798
+ param = {'1'=>'2', '3'=>'4'}
799
+ conn = @client.post_async(serverurl + 'servlet', param)
800
+ Thread.pass while !conn.finished?
801
+ res = conn.pop
802
+ assert_equal(param, params(res.header["x-query"][0]))
803
+ end
804
+
805
+ def test_post_with_block
806
+ called = false
807
+ res = @client.post(serverurl + 'servlet') { |str|
808
+ assert_equal('post,', str)
809
+ called = true
810
+ }
811
+ assert(called)
812
+ assert_nil(res.content)
813
+ #
814
+ called = false
815
+ param = [['1', '2'], ['3', '4']]
816
+ res = @client.post(serverurl + 'servlet', param) { |str|
817
+ assert_equal('post,1=2&3=4', str)
818
+ called = true
819
+ }
820
+ assert(called)
821
+ assert_equal('1=2&3=4', res.header["x-query"][0])
822
+ assert_nil(res.content)
823
+ end
824
+
825
+ def test_post_with_custom_multipart
826
+ ext = {'content-type' => 'multipart/form-data'}
827
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
828
+ body = [{ 'Content-Disposition' => 'form-data; name="1"', :content => "2"},
829
+ { 'Content-Disposition' => 'form-data; name="3"', :content => "4"}]
830
+ res = @client.post(serverurl + 'servlet', body, ext)
831
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
832
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
833
+ #
834
+ ext = {'content-type' => 'multipart/form-data; boundary=hello'}
835
+ assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
836
+ res = @client.post(serverurl + 'servlet', body, ext)
837
+ assert_match(/Content-Disposition: form-data; name="1"/, res.content)
838
+ assert_match(/Content-Disposition: form-data; name="3"/, res.content)
839
+ 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)
840
+ end
841
+
842
+ def test_post_with_custom_multipart_and_file
843
+ STDOUT.sync = true
844
+ File.open(__FILE__) do |file|
845
+ ext = { 'Content-Type' => 'multipart/alternative' }
846
+ body = [{ 'Content-Type' => 'text/plain', :content => "this is only a test" },
847
+ { 'Content-Type' => 'application/x-ruby', :content => file }]
848
+ res = @client.post(serverurl + 'servlet', body, ext)
849
+ assert_match(/^Content-Type: text\/plain\r\n/m, res.content)
850
+ assert_match(/^this is only a test\r\n/m, res.content)
851
+ assert_match(/^Content-Type: application\/x-ruby\r\n/m, res.content)
852
+ assert_match(/FIND_TAG_IN_THIS_FILE/, res.content)
853
+ end
854
+ end
855
+
856
+ def test_put
857
+ assert_equal("put", @client.put(serverurl + 'servlet').content)
858
+ param = {'1'=>'2', '3'=>'4'}
859
+ @client.debug_dev = str = ''
860
+ res = @client.put(serverurl + 'servlet', param)
861
+ assert_equal(param, params(res.header["x-query"][0]))
862
+ assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5])
863
+ end
864
+
865
+ def test_put_bytesize
866
+ res = @client.put(serverurl + 'servlet', 'txt' => 'あいうえお')
867
+ assert_equal('txt=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A', res.header["x-query"][0])
868
+ assert_equal('15', res.header["x-size"][0])
869
+ end
870
+
871
+ def test_put_async
872
+ param = {'1'=>'2', '3'=>'4'}
873
+ conn = @client.put_async(serverurl + 'servlet', param)
874
+ Thread.pass while !conn.finished?
875
+ res = conn.pop
876
+ assert_equal(param, params(res.header["x-query"][0]))
877
+ end
878
+
879
+ def test_delete
880
+ assert_equal("delete", @client.delete(serverurl + 'servlet').content)
881
+ end
882
+
883
+ # Not prohibited by spec, but normally it's ignored
884
+ def test_delete_with_body
885
+ param = {'1'=>'2', '3'=>'4'}
886
+ @client.debug_dev = str = ''
887
+ assert_equal("delete", @client.delete(serverurl + 'servlet', param).content)
888
+ assert_equal({'1' => ['2'], '3' => ['4']}, HTTP::Message.parse(str.split(/\r?\n\r?\n/)[2]))
889
+ end
890
+
891
+ def test_delete_async
892
+ conn = @client.delete_async(serverurl + 'servlet')
893
+ Thread.pass while !conn.finished?
894
+ res = conn.pop
895
+ assert_equal('delete', res.content.read)
896
+ end
897
+
898
+ def test_options
899
+ assert_equal("options", @client.options(serverurl + 'servlet').content)
900
+ end
901
+
902
+ def test_options_async
903
+ conn = @client.options_async(serverurl + 'servlet')
904
+ Thread.pass while !conn.finished?
905
+ res = conn.pop
906
+ assert_equal('options', res.content.read)
907
+ end
908
+
909
+ def test_propfind
910
+ assert_equal("propfind", @client.propfind(serverurl + 'servlet').content)
911
+ end
912
+
913
+ def test_propfind_async
914
+ conn = @client.propfind_async(serverurl + 'servlet')
915
+ Thread.pass while !conn.finished?
916
+ res = conn.pop
917
+ assert_equal('propfind', res.content.read)
918
+ end
919
+
920
+ def test_proppatch
921
+ assert_equal("proppatch", @client.proppatch(serverurl + 'servlet').content)
922
+ param = {'1'=>'2', '3'=>'4'}
923
+ res = @client.proppatch(serverurl + 'servlet', param)
924
+ assert_equal('proppatch', res.content)
925
+ assert_equal(param, params(res.header["x-query"][0]))
926
+ end
927
+
928
+ def test_proppatch_async
929
+ param = {'1'=>'2', '3'=>'4'}
930
+ conn = @client.proppatch_async(serverurl + 'servlet', param)
931
+ Thread.pass while !conn.finished?
932
+ res = conn.pop
933
+ assert_equal('proppatch', res.content.read)
934
+ assert_equal(param, params(res.header["x-query"][0]))
935
+ end
936
+
937
+ def test_trace
938
+ assert_equal("trace", @client.trace(serverurl + 'servlet').content)
939
+ param = {'1'=>'2', '3'=>'4'}
940
+ res = @client.trace(serverurl + 'servlet', param)
941
+ assert_equal(param, params(res.header["x-query"][0]))
942
+ end
943
+
944
+ def test_trace_async
945
+ param = {'1'=>'2', '3'=>'4'}
946
+ conn = @client.trace_async(serverurl + 'servlet', param)
947
+ Thread.pass while !conn.finished?
948
+ res = conn.pop
949
+ assert_equal(param, params(res.header["x-query"][0]))
950
+ end
951
+
952
+ def test_chunked
953
+ assert_equal('chunked', @client.get_content(serverurl + 'chunked', { 'msg' => 'chunked' }))
954
+ assert_equal('あいうえお', @client.get_content(serverurl + 'chunked', { 'msg' => 'あいうえお' }))
955
+ end
956
+
957
+ def test_chunked_empty
958
+ assert_equal('', @client.get_content(serverurl + 'chunked', { 'msg' => '' }))
959
+ end
960
+
961
+ def test_get_query
962
+ assert_equal({'1'=>'2'}, check_query_get({1=>2}))
963
+ assert_equal({'a'=>'A', 'B'=>'b'}, check_query_get({"a"=>"A", "B"=>"b"}))
964
+ assert_equal({'&'=>'&'}, check_query_get({"&"=>"&"}))
965
+ assert_equal({'= '=>' =+'}, check_query_get({"= "=>" =+"}))
966
+ assert_equal(
967
+ ['=', '&'].sort,
968
+ check_query_get([["=", "="], ["=", "&"]])['='].to_ary.sort
969
+ )
970
+ assert_equal({'123'=>'45'}, check_query_get('123=45'))
971
+ assert_equal({'12 3'=>'45', ' '=>' '}, check_query_get('12+3=45&+=+'))
972
+ assert_equal({}, check_query_get(''))
973
+ assert_equal({'1'=>'2'}, check_query_get({1=>StringIO.new('2')}))
974
+ assert_equal({'1'=>'2', '3'=>'4'}, check_query_get(StringIO.new('3=4&1=2')))
975
+
976
+ hash = check_query_get({"a"=>["A","a"], "B"=>"b"})
977
+ assert_equal({'a'=>'A', 'B'=>'b'}, hash)
978
+ assert_equal(['A','a'], hash['a'].to_ary)
979
+
980
+ hash = check_query_get({"a"=>WEBrick::HTTPUtils::FormData.new("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"=>[StringIO.new("A"),StringIO.new("a")], "B"=>StringIO.new("b")})
985
+ assert_equal({'a'=>'A', 'B'=>'b'}, hash)
986
+ assert_equal(['A','a'], hash['a'].to_ary)
987
+ end
988
+
989
+ def test_post_body
990
+ assert_equal({'1'=>'2'}, check_query_post({1=>2}))
991
+ assert_equal({'a'=>'A', 'B'=>'b'}, check_query_post({"a"=>"A", "B"=>"b"}))
992
+ assert_equal({'&'=>'&'}, check_query_post({"&"=>"&"}))
993
+ assert_equal({'= '=>' =+'}, check_query_post({"= "=>" =+"}))
994
+ assert_equal(
995
+ ['=', '&'].sort,
996
+ check_query_post([["=", "="], ["=", "&"]])['='].to_ary.sort
997
+ )
998
+ assert_equal({'123'=>'45'}, check_query_post('123=45'))
999
+ assert_equal({'12 3'=>'45', ' '=>' '}, check_query_post('12+3=45&+=+'))
1000
+ assert_equal({}, check_query_post(''))
1001
+ #
1002
+ post_body = StringIO.new("foo=bar&foo=baz")
1003
+ assert_equal(
1004
+ ["bar", "baz"],
1005
+ check_query_post(post_body)["foo"].to_ary.sort
1006
+ )
1007
+ end
1008
+
1009
+ def test_extra_headers
1010
+ str = ""
1011
+ @client.debug_dev = str
1012
+ @client.head(serverurl, nil, {"ABC" => "DEF"})
1013
+ lines = str.split(/(?:\r?\n)+/)
1014
+ assert_equal("= Request", lines[0])
1015
+ assert_match("ABC: DEF", lines[4])
1016
+ #
1017
+ str = ""
1018
+ @client.debug_dev = str
1019
+ @client.get(serverurl, nil, [["ABC", "DEF"], ["ABC", "DEF"]])
1020
+ lines = str.split(/(?:\r?\n)+/)
1021
+ assert_equal("= Request", lines[0])
1022
+ assert_match("ABC: DEF", lines[4])
1023
+ assert_match("ABC: DEF", lines[5])
1024
+ end
1025
+
1026
+ def test_http_custom_date_header
1027
+ @client.debug_dev = (str = "")
1028
+ res = @client.get(serverurl + 'hello', :header => {'Date' => 'foo'})
1029
+ lines = str.split(/(?:\r?\n)+/)
1030
+ assert_equal('Date: foo', lines[4])
1031
+ end
1032
+
1033
+ def test_timeout
1034
+ assert_equal(60, @client.connect_timeout)
1035
+ assert_equal(120, @client.send_timeout)
1036
+ assert_equal(60, @client.receive_timeout)
1037
+ #
1038
+ @client.connect_timeout = 1
1039
+ @client.send_timeout = 2
1040
+ @client.receive_timeout = 3
1041
+ assert_equal(1, @client.connect_timeout)
1042
+ assert_equal(2, @client.send_timeout)
1043
+ assert_equal(3, @client.receive_timeout)
1044
+ end
1045
+
1046
+ def test_connect_timeout
1047
+ # ToDo
1048
+ end
1049
+
1050
+ def test_send_timeout
1051
+ # ToDo
1052
+ end
1053
+
1054
+ def test_receive_timeout
1055
+ # this test takes 2 sec
1056
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1057
+ @client.receive_timeout = 1
1058
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0'))
1059
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
1060
+ @client.get_content(serverurl + 'sleep?sec=2')
1061
+ end
1062
+ @client.receive_timeout = 3
1063
+ assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1064
+ end
1065
+
1066
+ def test_receive_timeout_post
1067
+ # this test takes 2 sec
1068
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1069
+ @client.receive_timeout = 1
1070
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 0).content)
1071
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
1072
+ @client.post(serverurl + 'sleep', :sec => 2)
1073
+ end
1074
+ @client.receive_timeout = 3
1075
+ assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1076
+ end
1077
+
1078
+ def test_reset
1079
+ url = serverurl + 'servlet'
1080
+ assert_nothing_raised do
1081
+ 5.times do
1082
+ @client.get(url)
1083
+ @client.reset(url)
1084
+ end
1085
+ end
1086
+ end
1087
+
1088
+ def test_reset_all
1089
+ assert_nothing_raised do
1090
+ 5.times do
1091
+ @client.get(serverurl + 'servlet')
1092
+ @client.reset_all
1093
+ end
1094
+ end
1095
+ end
1096
+
1097
+ def test_cookies
1098
+ cookiefile = File.join(File.dirname(File.expand_path(__FILE__)), 'test_cookies_file')
1099
+ File.open(cookiefile, "wb") do |f|
1100
+ f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\t.rubyforge.org\t/\t13\n"
1101
+ end
1102
+ @client.set_cookie_store(cookiefile)
1103
+ cookie = @client.cookie_manager.cookies.first
1104
+ url = cookie.url
1105
+ assert(cookie.domain_match(url.host, cookie.domain))
1106
+ #
1107
+ @client.reset_all
1108
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\nSet-Cookie: foo=bar; expires=#{Time.at(1924873200).gmtime.httpdate}\n\nOK"
1109
+ @client.get_content('http://rubyforge.org/account/login.php')
1110
+ @client.save_cookie_store
1111
+ str = File.read(cookiefile)
1112
+ assert_match(%r(http://rubyforge.org/account/login.php\tfoo\tbar\t1924873200\trubyforge.org\t/account\t1), str)
1113
+ File.unlink(cookiefile)
1114
+ end
1115
+
1116
+ def test_eof_error_length
1117
+ io = StringIO.new('')
1118
+ def io.gets(*arg)
1119
+ @buf ||= ["HTTP/1.0 200 OK\n", "content-length: 123\n", "\n"]
1120
+ @buf.shift
1121
+ end
1122
+ def io.readpartial(size, buf)
1123
+ @second ||= false
1124
+ if !@second
1125
+ @second = '1st'
1126
+ buf << "abc"
1127
+ buf
1128
+ elsif @second == '1st'
1129
+ @second = '2nd'
1130
+ raise EOFError.new
1131
+ else
1132
+ raise Exception.new
1133
+ end
1134
+ end
1135
+ def io.eof?
1136
+ true
1137
+ end
1138
+ @client.test_loopback_http_response << io
1139
+ assert_nothing_raised do
1140
+ @client.get('http://foo/bar')
1141
+ end
1142
+ end
1143
+
1144
+ def test_eof_error_rest
1145
+ io = StringIO.new('')
1146
+ def io.gets(*arg)
1147
+ @buf ||= ["HTTP/1.0 200 OK\n", "\n"]
1148
+ @buf.shift
1149
+ end
1150
+ def io.readpartial(size, buf)
1151
+ @second ||= false
1152
+ if !@second
1153
+ @second = '1st'
1154
+ buf << "abc"
1155
+ buf
1156
+ elsif @second == '1st'
1157
+ @second = '2nd'
1158
+ raise EOFError.new
1159
+ else
1160
+ raise Exception.new
1161
+ end
1162
+ end
1163
+ def io.eof?
1164
+ true
1165
+ end
1166
+ @client.test_loopback_http_response << io
1167
+ assert_nothing_raised do
1168
+ @client.get('http://foo/bar')
1169
+ end
1170
+ end
1171
+
1172
+ def test_urify
1173
+ extend HTTPClient::Util
1174
+ assert_nil(urify(nil))
1175
+ uri = 'http://foo'
1176
+ assert_equal(urify(uri), urify(uri))
1177
+ assert_equal(urify(uri), urify(urify(uri)))
1178
+ end
1179
+
1180
+ def test_connection
1181
+ c = HTTPClient::Connection.new
1182
+ assert(c.finished?)
1183
+ assert_nil(c.join)
1184
+ end
1185
+
1186
+ def test_site
1187
+ site = HTTPClient::Site.new
1188
+ assert_equal('tcp', site.scheme)
1189
+ assert_equal('0.0.0.0', site.host)
1190
+ assert_equal(0, site.port)
1191
+ assert_equal('tcp://0.0.0.0:0', site.addr)
1192
+ assert_equal('tcp://0.0.0.0:0', site.to_s)
1193
+ assert_nothing_raised do
1194
+ site.inspect
1195
+ end
1196
+ #
1197
+ site = HTTPClient::Site.new(urify('http://localhost:12345/foo'))
1198
+ assert_equal('http', site.scheme)
1199
+ assert_equal('localhost', site.host)
1200
+ assert_equal(12345, site.port)
1201
+ assert_equal('http://localhost:12345', site.addr)
1202
+ assert_equal('http://localhost:12345', site.to_s)
1203
+ assert_nothing_raised do
1204
+ site.inspect
1205
+ end
1206
+ #
1207
+ site1 = HTTPClient::Site.new(urify('http://localhost:12341/'))
1208
+ site2 = HTTPClient::Site.new(urify('http://localhost:12342/'))
1209
+ site3 = HTTPClient::Site.new(urify('http://localhost:12342/'))
1210
+ assert(!(site1 == site2))
1211
+ h = { site1 => 'site1', site2 => 'site2' }
1212
+ h[site3] = 'site3'
1213
+ assert_equal('site1', h[site1])
1214
+ assert_equal('site3', h[site2])
1215
+ end
1216
+
1217
+ def test_http_header
1218
+ res = @client.get(serverurl + 'hello')
1219
+ assert_equal('text/html', res.contenttype)
1220
+ assert_equal(5, res.header.get(nil).size)
1221
+ #
1222
+ res.header.delete('connection')
1223
+ assert_equal(4, res.header.get(nil).size)
1224
+ #
1225
+ res.header['foo'] = 'bar'
1226
+ assert_equal(['bar'], res.header['foo'])
1227
+ #
1228
+ assert_equal([['foo', 'bar']], res.header.get('foo'))
1229
+ res.header['foo'] = ['bar', 'bar2']
1230
+ assert_equal([['foo', 'bar'], ['foo', 'bar2']], res.header.get('foo'))
1231
+ end
1232
+
1233
+ def test_mime_type
1234
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1235
+ assert_equal('text/html', HTTP::Message.mime_type('foo.html'))
1236
+ assert_equal('text/html', HTTP::Message.mime_type('foo.htm'))
1237
+ assert_equal('application/msword', HTTP::Message.mime_type('foo.doc'))
1238
+ assert_equal('image/png', HTTP::Message.mime_type('foo.png'))
1239
+ assert_equal('image/gif', HTTP::Message.mime_type('foo.gif'))
1240
+ assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpg'))
1241
+ assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpeg'))
1242
+ assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.unknown'))
1243
+ #
1244
+ handler = lambda { |path| 'hello/world' }
1245
+ assert_nil(HTTP::Message.mime_type_handler)
1246
+ assert_nil(HTTP::Message.get_mime_type_func)
1247
+ HTTP::Message.mime_type_handler = handler
1248
+ assert_not_nil(HTTP::Message.mime_type_handler)
1249
+ assert_not_nil(HTTP::Message.get_mime_type_func)
1250
+ assert_equal('hello/world', HTTP::Message.mime_type('foo.txt'))
1251
+ HTTP::Message.mime_type_handler = nil
1252
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1253
+ HTTP::Message.set_mime_type_func(nil)
1254
+ assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1255
+ #
1256
+ handler = lambda { |path| nil }
1257
+ HTTP::Message.mime_type_handler = handler
1258
+ assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.txt'))
1259
+ end
1260
+
1261
+ def test_connect_request
1262
+ req = HTTP::Message.new_connect_request(urify('https://foo/bar'))
1263
+ assert_equal("CONNECT foo:443 HTTP/1.0\r\n\r\n", req.dump)
1264
+ req = HTTP::Message.new_connect_request(urify('https://example.com/'))
1265
+ assert_equal("CONNECT example.com:443 HTTP/1.0\r\n\r\n", req.dump)
1266
+ end
1267
+
1268
+ def test_response
1269
+ res = HTTP::Message.new_response('response')
1270
+ res.contenttype = 'text/plain'
1271
+ res.header.body_date = Time.at(946652400)
1272
+ assert_equal(
1273
+ [
1274
+ "",
1275
+ "Content-Length: 8",
1276
+ "Content-Type: text/plain",
1277
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1278
+ "Status: 200 OK",
1279
+ "response"
1280
+ ],
1281
+ res.dump.split(/\r\n/).sort
1282
+ )
1283
+ assert_equal(['8'], res.header['Content-Length'])
1284
+ assert_equal('8', res.headers['Content-Length'])
1285
+ res.header.set('foo', 'bar')
1286
+ assert_equal(
1287
+ [
1288
+ "",
1289
+ "Content-Length: 8",
1290
+ "Content-Type: text/plain",
1291
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1292
+ "Status: 200 OK",
1293
+ "foo: bar",
1294
+ "response"
1295
+ ],
1296
+ res.dump.split(/\r\n/).sort
1297
+ )
1298
+ # nil body
1299
+ res = HTTP::Message.new_response(nil)
1300
+ assert_equal(
1301
+ [
1302
+ "Content-Length: 0",
1303
+ "Content-Type: text/html; charset=us-ascii",
1304
+ "Status: 200 OK"
1305
+ ],
1306
+ res.dump.split(/\r\n/).sort
1307
+ )
1308
+ # for mod_ruby env
1309
+ Object.const_set('Apache', nil)
1310
+ begin
1311
+ res = HTTP::Message.new_response('response')
1312
+ assert(res.dump.split(/\r\n/).any? { |line| /^Date/ =~ line })
1313
+ #
1314
+ res = HTTP::Message.new_response('response')
1315
+ res.contenttype = 'text/plain'
1316
+ res.header.body_date = Time.at(946652400)
1317
+ res.header['Date'] = Time.at(946652400).httpdate
1318
+ assert_equal(
1319
+ [
1320
+ "",
1321
+ "Content-Length: 8",
1322
+ "Content-Type: text/plain",
1323
+ "Date: Fri, 31 Dec 1999 15:00:00 GMT",
1324
+ "HTTP/1.1 200 OK",
1325
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1326
+ "response"
1327
+ ],
1328
+ res.dump.split(/\r\n/).sort
1329
+ )
1330
+ ensure
1331
+ Object.instance_eval { remove_const('Apache') }
1332
+ end
1333
+ end
1334
+
1335
+ def test_response_cookies
1336
+ res = HTTP::Message.new_response('response')
1337
+ res.contenttype = 'text/plain'
1338
+ res.header.body_date = Time.at(946652400)
1339
+ assert_nil(res.cookies)
1340
+ #
1341
+ res.header['Set-Cookie'] = [
1342
+ 'CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT',
1343
+ 'PART_NUMBER=ROCKET_LAUNCHER_0001; path=/'
1344
+ ]
1345
+ assert_equal(
1346
+ [
1347
+ "",
1348
+ "Content-Length: 8",
1349
+ "Content-Type: text/plain",
1350
+ "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1351
+ "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT",
1352
+ "Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/",
1353
+ "Status: 200 OK",
1354
+ "response"
1355
+ ],
1356
+ res.dump.split(/\r\n/).sort
1357
+ )
1358
+ assert_equal(2, res.cookies.size)
1359
+ assert_equal('CUSTOMER', res.cookies[0].name)
1360
+ assert_equal('PART_NUMBER', res.cookies[1].name)
1361
+ end
1362
+
1363
+ def test_ok_response_success
1364
+ res = HTTP::Message.new_response('response')
1365
+ assert_equal(true, res.ok?)
1366
+ res.status = 404
1367
+ assert_equal(false, res.ok?)
1368
+ res.status = 500
1369
+ assert_equal(false, res.ok?)
1370
+ res.status = 302
1371
+ assert_equal(false, res.ok?)
1372
+ end
1373
+
1374
+ if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9'
1375
+ def test_timeout_scheduler
1376
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1377
+ status = HTTPClient.timeout_scheduler.instance_eval { @thread.kill; @thread.join; @thread.status }
1378
+ assert(!status) # dead
1379
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1380
+ end
1381
+ end
1382
+
1383
+ def test_session_manager
1384
+ mgr = HTTPClient::SessionManager.new(@client)
1385
+ assert_nil(mgr.instance_eval { @proxy })
1386
+ assert_nil(mgr.debug_dev)
1387
+ @client.debug_dev = Object.new
1388
+ @client.proxy = 'http://myproxy:12345'
1389
+ mgr = HTTPClient::SessionManager.new(@client)
1390
+ assert_equal('http://myproxy:12345', mgr.instance_eval { @proxy }.to_s)
1391
+ assert_equal(@client.debug_dev, mgr.debug_dev)
1392
+ end
1393
+
1394
+ def create_keepalive_disconnected_thread(idx, sock)
1395
+ Thread.new {
1396
+ # return "12345" for the first connection
1397
+ sock.gets
1398
+ sock.gets
1399
+ sock.write("HTTP/1.1 200 OK\r\n")
1400
+ sock.write("Content-Length: 5\r\n")
1401
+ sock.write("\r\n")
1402
+ sock.write("12345")
1403
+ # for the next connection, close while reading the request for emulating
1404
+ # KeepAliveDisconnected
1405
+ sock.gets
1406
+ sock.close
1407
+ }
1408
+ end
1409
+
1410
+ def test_keepalive_disconnected
1411
+ client = HTTPClient.new
1412
+ server = TCPServer.open('127.0.0.1', 0)
1413
+ server.listen(30) # set enough backlogs
1414
+ endpoint = "http://127.0.0.1:#{server.addr[1]}/"
1415
+ Thread.new {
1416
+ Thread.abort_on_exception = true
1417
+ # emulate 10 keep-alive connections
1418
+ 10.times do |idx|
1419
+ sock = server.accept
1420
+ create_keepalive_disconnected_thread(idx, sock)
1421
+ end
1422
+ # return "23456" for the request which gets KeepAliveDisconnected
1423
+ 5.times do
1424
+ sock = server.accept
1425
+ sock.gets
1426
+ sock.gets
1427
+ sock.write("HTTP/1.1 200 OK\r\n")
1428
+ sock.write("\r\n")
1429
+ sock.write("23456")
1430
+ sock.close
1431
+ end
1432
+ # return "34567" for the rest requests
1433
+ while true
1434
+ sock = server.accept
1435
+ sock.gets
1436
+ sock.gets
1437
+ sock.write("HTTP/1.1 200 OK\r\n")
1438
+ sock.write("Connection: close\r\n")
1439
+ sock.write("Content-Length: 5\r\n")
1440
+ sock.write("\r\n")
1441
+ sock.write("34567")
1442
+ sock.close
1443
+ end
1444
+ }
1445
+ # allocate 10 keep-alive connections
1446
+ (0...10).to_a.map {
1447
+ Thread.new {
1448
+ assert_equal("12345", client.get(endpoint).content)
1449
+ }
1450
+ }.each { |th| th.join }
1451
+ # send 5 requests, which should get KeepAliveDesconnected.
1452
+ # doing these requests, rest keep-alive connections are invalidated.
1453
+ (0...5).to_a.map {
1454
+ Thread.new {
1455
+ assert_equal("23456", client.get(endpoint).content)
1456
+ }
1457
+ }.each { |th| th.join }
1458
+ # rest requests won't get KeepAliveDisconnected; how can I check this?
1459
+ (0...10).to_a.map {
1460
+ Thread.new {
1461
+ assert_equal("34567", client.get(endpoint).content)
1462
+ }
1463
+ }.each { |th| th.join }
1464
+ end
1465
+
1466
+ def create_keepalive_thread(count, sock)
1467
+ Thread.new {
1468
+ Thread.abort_on_exception = true
1469
+ count.times do
1470
+ req = sock.gets
1471
+ while line = sock.gets
1472
+ break if line.chomp.empty?
1473
+ end
1474
+ case req
1475
+ when /chunked/
1476
+ sock.write("HTTP/1.1 200 OK\r\n")
1477
+ sock.write("Transfer-Encoding: chunked\r\n")
1478
+ sock.write("\r\n")
1479
+ sock.write("1a\r\n")
1480
+ sock.write("abcdefghijklmnopqrstuvwxyz\r\n")
1481
+ sock.write("10\r\n")
1482
+ sock.write("1234567890abcdef\r\n")
1483
+ sock.write("0\r\n")
1484
+ sock.write("\r\n")
1485
+ else
1486
+ sock.write("HTTP/1.1 200 OK\r\n")
1487
+ sock.write("Content-Length: 5\r\n")
1488
+ sock.write("\r\n")
1489
+ sock.write("12345")
1490
+ end
1491
+ end
1492
+ sock.close
1493
+ }
1494
+ end
1495
+
1496
+ def test_keepalive
1497
+ server = TCPServer.open('localhost', 0)
1498
+ server_thread = Thread.new {
1499
+ Thread.abort_on_exception = true
1500
+ sock = server.accept
1501
+ create_keepalive_thread(10, sock)
1502
+ }
1503
+ url = "http://localhost:#{server.addr[1]}/"
1504
+ begin
1505
+ # content-length
1506
+ 5.times do
1507
+ assert_equal('12345', @client.get(url).body)
1508
+ end
1509
+ # chunked
1510
+ 5.times do
1511
+ assert_equal('abcdefghijklmnopqrstuvwxyz1234567890abcdef', @client.get(url + 'chunked').body)
1512
+ end
1513
+ ensure
1514
+ server.close
1515
+ server_thread.join
1516
+ end
1517
+ end
1518
+
1519
+ def test_socket_local
1520
+ @client.socket_local.host = '127.0.0.1'
1521
+ assert_equal('hello', @client.get_content(serverurl + 'hello'))
1522
+ @client.reset_all
1523
+ @client.socket_local.port = serverport
1524
+ begin
1525
+ @client.get_content(serverurl + 'hello')
1526
+ rescue Errno::EADDRINUSE, SocketError
1527
+ assert(true)
1528
+ end
1529
+ end
1530
+
1531
+ def test_body_param_order
1532
+ ary = ('b'..'d').map { |k| ['key2', k] } << ['key1', 'a'] << ['key3', 'z']
1533
+ assert_equal("key2=b&key2=c&key2=d&key1=a&key3=z", HTTP::Message.escape_query(ary))
1534
+ end
1535
+
1536
+ if RUBY_VERSION > "1.9"
1537
+ def test_charset
1538
+ body = @client.get(serverurl + 'charset').body
1539
+ assert_equal(Encoding::EUC_JP, body.encoding)
1540
+ assert_equal('あいうえお'.encode(Encoding::EUC_JP), body)
1541
+ end
1542
+ end
1543
+
1544
+ if RUBY_VERSION >= "1.9.3"
1545
+ def test_continue
1546
+ @client.debug_dev = str = ''
1547
+ res = @client.get(serverurl + 'continue', :header => {:Expect => '100-continue'})
1548
+ assert_equal(200, res.status)
1549
+ assert_equal('done!', res.body)
1550
+ assert_match(/Expect: 100-continue/, str)
1551
+ end
1552
+ end
1553
+
1554
+ def test_ipv6literaladdress_in_uri
1555
+ server = TCPServer.open('::1', 0) rescue return # Skip if IPv6 is unavailable.
1556
+ server_thread = Thread.new {
1557
+ Thread.abort_on_exception = true
1558
+ sock = server.accept
1559
+ while line = sock.gets
1560
+ break if line.chomp.empty?
1561
+ end
1562
+ sock.write("HTTP/1.1 200 OK\r\n")
1563
+ sock.write("Content-Length: 5\r\n")
1564
+ sock.write("\r\n")
1565
+ sock.write("12345")
1566
+ sock.close
1567
+ }
1568
+ uri = "http://[::1]:#{server.addr[1]}/"
1569
+ begin
1570
+ assert_equal('12345', @client.get(uri).body)
1571
+ ensure
1572
+ server.close
1573
+ server_thread.kill
1574
+ server_thread.join
1575
+ end
1576
+ end
1577
+
1578
+ private
1579
+
1580
+ def check_query_get(query)
1581
+ WEBrick::HTTPUtils.parse_query(
1582
+ @client.get(serverurl + 'servlet', query).header["x-query"][0]
1583
+ )
1584
+ end
1585
+
1586
+ def check_query_post(query)
1587
+ WEBrick::HTTPUtils.parse_query(
1588
+ @client.post(serverurl + 'servlet', query).header["x-query"][0]
1589
+ )
1590
+ end
1591
+
1592
+ def setup_server
1593
+ @server = WEBrick::HTTPServer.new(
1594
+ :BindAddress => "localhost",
1595
+ :Logger => @logger,
1596
+ :Port => 0,
1597
+ :AccessLog => [],
1598
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__))
1599
+ )
1600
+ @serverport = @server.config[:Port]
1601
+ [
1602
+ :hello, :sleep, :servlet_redirect, :redirect1, :redirect2, :redirect3,
1603
+ :redirect_self, :relative_redirect, :redirect_see_other, :chunked,
1604
+ :largebody, :status, :compressed, :charset, :continue
1605
+ ].each do |sym|
1606
+ @server.mount(
1607
+ "/#{sym}",
1608
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
1609
+ )
1610
+ end
1611
+ @server.mount('/servlet', TestServlet.new(@server))
1612
+ @server_thread = start_server_thread(@server)
1613
+ end
1614
+
1615
+ def escape_noproxy
1616
+ backup = HTTPClient::NO_PROXY_HOSTS.dup
1617
+ HTTPClient::NO_PROXY_HOSTS.clear
1618
+ yield
1619
+ ensure
1620
+ HTTPClient::NO_PROXY_HOSTS.replace(backup)
1621
+ end
1622
+
1623
+ def do_hello(req, res)
1624
+ res['content-type'] = 'text/html'
1625
+ res.body = "hello"
1626
+ end
1627
+
1628
+ def do_sleep(req, res)
1629
+ sec = req.query['sec'].to_i
1630
+ sleep sec
1631
+ res['content-type'] = 'text/html'
1632
+ res.body = "hello"
1633
+ end
1634
+
1635
+ def do_servlet_redirect(req, res)
1636
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet")
1637
+ end
1638
+
1639
+ def do_redirect1(req, res)
1640
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello")
1641
+ end
1642
+
1643
+ def do_redirect2(req, res)
1644
+ res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3")
1645
+ end
1646
+
1647
+ def do_redirect3(req, res)
1648
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello")
1649
+ end
1650
+
1651
+ def do_redirect_self(req, res)
1652
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self")
1653
+ end
1654
+
1655
+ def do_relative_redirect(req, res)
1656
+ res.set_redirect(WEBrick::HTTPStatus::Found, "hello")
1657
+ end
1658
+
1659
+ def do_redirect_see_other(req, res)
1660
+ if req.request_method == 'POST'
1661
+ res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other") # self
1662
+ else
1663
+ res.body = 'hello'
1664
+ end
1665
+ end
1666
+
1667
+ def do_chunked(req, res)
1668
+ res.chunked = true
1669
+ res['content-type'] = 'text/plain; charset=UTF-8'
1670
+ piper, pipew = IO.pipe
1671
+ res.body = piper
1672
+ pipew << req.query['msg']
1673
+ pipew.close
1674
+ end
1675
+
1676
+ def do_largebody(req, res)
1677
+ res['content-type'] = 'text/html'
1678
+ res.body = "a" * 1000 * 1000
1679
+ end
1680
+
1681
+ def do_compressed(req, res)
1682
+ res['content-type'] = 'application/octet-stream'
1683
+ if req.query['enc'] == 'gzip'
1684
+ res['content-encoding'] = 'gzip'
1685
+ res.body = GZIP_CONTENT
1686
+ elsif req.query['enc'] == 'deflate'
1687
+ res['content-encoding'] = 'deflate'
1688
+ res.body = DEFLATE_CONTENT
1689
+ end
1690
+ end
1691
+
1692
+ def do_charset(req, res)
1693
+ if RUBY_VERSION > "1.9"
1694
+ res.body = 'あいうえお'.encode("euc-jp")
1695
+ res['Content-Type'] = 'text/plain; charset=euc-jp'
1696
+ else
1697
+ res.body = 'this endpoint is for 1.9 or later'
1698
+ end
1699
+ end
1700
+
1701
+ def do_status(req, res)
1702
+ res.status = req.query['status'].to_i
1703
+ end
1704
+
1705
+ def do_continue(req, res)
1706
+ req.continue
1707
+ res.body = 'done!'
1708
+ end
1709
+
1710
+ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
1711
+ def get_instance(*arg)
1712
+ self
1713
+ end
1714
+
1715
+ def do_HEAD(req, res)
1716
+ res["x-head"] = 'head' # use this for test purpose only.
1717
+ res["x-query"] = query_response(req)
1718
+ end
1719
+
1720
+ def do_GET(req, res)
1721
+ res.body = 'get'
1722
+ res["x-query"] = query_response(req)
1723
+ end
1724
+
1725
+ def do_POST(req, res)
1726
+ res["content-type"] = "text/plain" # iso-8859-1, not US-ASCII
1727
+ res.body = 'post,' + req.body.to_s
1728
+ res["x-query"] = body_response(req)
1729
+ end
1730
+
1731
+ def do_PUT(req, res)
1732
+ res["x-query"] = body_response(req)
1733
+ param = WEBrick::HTTPUtils.parse_query(req.body) || {}
1734
+ res["x-size"] = (param['txt'] || '').size
1735
+ res.body = param['txt'] || 'put'
1736
+ end
1737
+
1738
+ def do_DELETE(req, res)
1739
+ res.body = 'delete'
1740
+ end
1741
+
1742
+ def do_OPTIONS(req, res)
1743
+ # check RFC for legal response.
1744
+ res.body = 'options'
1745
+ end
1746
+
1747
+ def do_PROPFIND(req, res)
1748
+ res.body = 'propfind'
1749
+ end
1750
+
1751
+ def do_PROPPATCH(req, res)
1752
+ res.body = 'proppatch'
1753
+ res["x-query"] = body_response(req)
1754
+ end
1755
+
1756
+ def do_TRACE(req, res)
1757
+ # client SHOULD reflect the message received back to the client as the
1758
+ # entity-body of a 200 (OK) response. [RFC2616]
1759
+ res.body = 'trace'
1760
+ res["x-query"] = query_response(req)
1761
+ end
1762
+
1763
+ private
1764
+
1765
+ def query_response(req)
1766
+ query_escape(WEBrick::HTTPUtils.parse_query(req.query_string))
1767
+ end
1768
+
1769
+ def body_response(req)
1770
+ query_escape(WEBrick::HTTPUtils.parse_query(req.body))
1771
+ end
1772
+
1773
+ def query_escape(query)
1774
+ escaped = []
1775
+ query.sort_by { |k, v| k }.collect do |k, v|
1776
+ v.to_ary.each do |ve|
1777
+ escaped << CGI.escape(k) + '=' + CGI.escape(ve)
1778
+ end
1779
+ end
1780
+ escaped.join('&')
1781
+ end
1782
+ end
1783
+ end