glebtv-httpclient 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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