glebtv-httpclient 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +108 -0
  3. data/bin/httpclient +65 -0
  4. data/lib/glebtv-httpclient.rb +1 -0
  5. data/lib/hexdump.rb +50 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/http-access2.rb +55 -0
  9. data/lib/httpclient/auth.rb +899 -0
  10. data/lib/httpclient/cacert.p7s +1912 -0
  11. data/lib/httpclient/connection.rb +88 -0
  12. data/lib/httpclient/cookie.rb +438 -0
  13. data/lib/httpclient/http.rb +1050 -0
  14. data/lib/httpclient/include_client.rb +83 -0
  15. data/lib/httpclient/session.rb +1031 -0
  16. data/lib/httpclient/ssl_config.rb +403 -0
  17. data/lib/httpclient/timeout.rb +140 -0
  18. data/lib/httpclient/util.rb +186 -0
  19. data/lib/httpclient/version.rb +3 -0
  20. data/lib/httpclient.rb +1157 -0
  21. data/lib/oauthclient.rb +110 -0
  22. data/sample/async.rb +8 -0
  23. data/sample/auth.rb +11 -0
  24. data/sample/cookie.rb +18 -0
  25. data/sample/dav.rb +103 -0
  26. data/sample/howto.rb +49 -0
  27. data/sample/oauth_buzz.rb +57 -0
  28. data/sample/oauth_friendfeed.rb +59 -0
  29. data/sample/oauth_twitter.rb +61 -0
  30. data/sample/ssl/0cert.pem +22 -0
  31. data/sample/ssl/0key.pem +30 -0
  32. data/sample/ssl/1000cert.pem +19 -0
  33. data/sample/ssl/1000key.pem +18 -0
  34. data/sample/ssl/htdocs/index.html +10 -0
  35. data/sample/ssl/ssl_client.rb +22 -0
  36. data/sample/ssl/webrick_httpsd.rb +29 -0
  37. data/sample/stream.rb +21 -0
  38. data/sample/thread.rb +27 -0
  39. data/sample/wcat.rb +21 -0
  40. data/test/ca-chain.cert +44 -0
  41. data/test/ca.cert +23 -0
  42. data/test/client.cert +19 -0
  43. data/test/client.key +15 -0
  44. data/test/helper.rb +129 -0
  45. data/test/htdigest +1 -0
  46. data/test/htpasswd +2 -0
  47. data/test/runner.rb +2 -0
  48. data/test/server.cert +19 -0
  49. data/test/server.key +15 -0
  50. data/test/sslsvr.rb +65 -0
  51. data/test/subca.cert +21 -0
  52. data/test/test_auth.rb +321 -0
  53. data/test/test_cookie.rb +412 -0
  54. data/test/test_hexdump.rb +14 -0
  55. data/test/test_http-access2.rb +507 -0
  56. data/test/test_httpclient.rb +1801 -0
  57. data/test/test_include_client.rb +52 -0
  58. data/test/test_ssl.rb +235 -0
  59. metadata +102 -0
data/test/test_auth.rb ADDED
@@ -0,0 +1,321 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'digest/md5'
3
+
4
+ class TestAuth < Test::Unit::TestCase
5
+ include Helper
6
+
7
+ def setup
8
+ super
9
+ setup_server
10
+ end
11
+
12
+ def teardown
13
+ super
14
+ end
15
+
16
+ def setup_server
17
+ @server = WEBrick::HTTPServer.new(
18
+ :BindAddress => "localhost",
19
+ :Logger => @logger,
20
+ :Port => 0,
21
+ :AccessLog => [],
22
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__))
23
+ )
24
+ @serverport = @server.config[:Port]
25
+ @server.mount(
26
+ '/basic_auth',
27
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_basic_auth).to_proc)
28
+ )
29
+ @server.mount(
30
+ '/digest_auth',
31
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_digest_auth).to_proc)
32
+ )
33
+ @server.mount(
34
+ '/digest_sess_auth',
35
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_digest_sess_auth).to_proc)
36
+ )
37
+ htpasswd = File.join(File.dirname(__FILE__), 'htpasswd')
38
+ htpasswd_userdb = WEBrick::HTTPAuth::Htpasswd.new(htpasswd)
39
+ htdigest = File.join(File.dirname(__FILE__), 'htdigest')
40
+ htdigest_userdb = WEBrick::HTTPAuth::Htdigest.new(htdigest)
41
+ @basic_auth = WEBrick::HTTPAuth::BasicAuth.new(
42
+ :Logger => @logger,
43
+ :Realm => 'auth',
44
+ :UserDB => htpasswd_userdb
45
+ )
46
+ @digest_auth = WEBrick::HTTPAuth::DigestAuth.new(
47
+ :Logger => @logger,
48
+ :Algorithm => 'MD5',
49
+ :Realm => 'auth',
50
+ :UserDB => htdigest_userdb
51
+ )
52
+ @digest_sess_auth = WEBrick::HTTPAuth::DigestAuth.new(
53
+ :Logger => @logger,
54
+ :Algorithm => 'MD5-sess',
55
+ :Realm => 'auth',
56
+ :UserDB => htdigest_userdb
57
+ )
58
+ @server_thread = start_server_thread(@server)
59
+
60
+ @proxy_digest_auth = WEBrick::HTTPAuth::ProxyDigestAuth.new(
61
+ :Logger => @proxylogger,
62
+ :Algorithm => 'MD5',
63
+ :Realm => 'auth',
64
+ :UserDB => htdigest_userdb
65
+ )
66
+
67
+ @proxyserver = WEBrick::HTTPProxyServer.new(
68
+ :ProxyAuthProc => @proxy_digest_auth.method(:authenticate).to_proc,
69
+ :BindAddress => "localhost",
70
+ :Logger => @proxylogger,
71
+ :Port => 0,
72
+ :AccessLog => []
73
+ )
74
+ @proxyport = @proxyserver.config[:Port]
75
+ @proxyserver_thread = start_server_thread(@proxyserver)
76
+ end
77
+
78
+ def do_basic_auth(req, res)
79
+ @basic_auth.authenticate(req, res)
80
+ res['content-type'] = 'text/plain'
81
+ res.body = 'basic_auth OK'
82
+ end
83
+
84
+ def do_digest_auth(req, res)
85
+ @digest_auth.authenticate(req, res)
86
+ res['content-type'] = 'text/plain'
87
+ res['x-query'] = req.body
88
+ res.body = 'digest_auth OK' + req.query_string.to_s
89
+ end
90
+
91
+ def do_digest_sess_auth(req, res)
92
+ @digest_sess_auth.authenticate(req, res)
93
+ res['content-type'] = 'text/plain'
94
+ res['x-query'] = req.body
95
+ res.body = 'digest_sess_auth OK' + req.query_string.to_s
96
+ end
97
+
98
+ def test_basic_auth
99
+ c = HTTPClient.new
100
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
101
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
102
+ end
103
+
104
+ def test_basic_auth_compat
105
+ c = HTTPClient.new
106
+ c.set_basic_auth("http://localhost:#{serverport}/", 'admin', 'admin')
107
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
108
+ end
109
+
110
+ def test_BASIC_auth
111
+ c = HTTPClient.new
112
+ webrick_backup = @basic_auth.instance_eval { @auth_scheme }
113
+ #httpaccess2_backup = c.www_auth.basic_auth.instance_eval { @scheme }
114
+ begin
115
+ @basic_auth.instance_eval { @auth_scheme = "BASIC" }
116
+ c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
117
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
118
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
119
+ ensure
120
+ @basic_auth.instance_eval { @auth_scheme = webrick_backup }
121
+ #c.www_auth.basic_auth.instance_eval { @scheme = httpaccess2_backup }
122
+ end
123
+ end
124
+
125
+ def test_basic_auth_reuses_credentials
126
+ c = HTTPClient.new
127
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
128
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth/"))
129
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
130
+ c.debug_dev = str = ''
131
+ c.get_content("http://localhost:#{serverport}/basic_auth/sub/dir/")
132
+ assert_match /Authorization: Basic YWRtaW46YWRtaW4=/, str
133
+ end
134
+
135
+ def test_digest_auth
136
+ c = HTTPClient.new
137
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
138
+ assert_equal('digest_auth OK', c.get_content("http://localhost:#{serverport}/digest_auth"))
139
+ end
140
+
141
+ def test_digest_auth_reuses_credentials
142
+ c = HTTPClient.new
143
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
144
+ assert_equal('digest_auth OK', c.get_content("http://localhost:#{serverport}/digest_auth/"))
145
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
146
+ c.debug_dev = str = ''
147
+ c.get_content("http://localhost:#{serverport}/digest_auth/sub/dir/")
148
+ assert_match /Authorization: Digest/, str
149
+ end
150
+
151
+ def test_digest_auth_with_block
152
+ c = HTTPClient.new
153
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
154
+ called = false
155
+ c.get_content("http://localhost:#{serverport}/digest_auth") do |str|
156
+ assert_equal('digest_auth OK', str)
157
+ called = true
158
+ end
159
+ assert(called)
160
+ #
161
+ called = false
162
+ c.get("http://localhost:#{serverport}/digest_auth") do |str|
163
+ assert_equal('digest_auth OK', str)
164
+ called = true
165
+ end
166
+ assert(called)
167
+ end
168
+
169
+ def test_digest_auth_with_post_io
170
+ c = HTTPClient.new
171
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
172
+ post_body = StringIO.new("1234567890")
173
+ assert_equal('1234567890', c.post("http://localhost:#{serverport}/digest_auth", post_body).header['x-query'][0])
174
+ #
175
+ post_body = StringIO.new("1234567890")
176
+ post_body.read(5)
177
+ assert_equal('67890', c.post("http://localhost:#{serverport}/digest_auth", post_body).header['x-query'][0])
178
+ end
179
+
180
+ def test_digest_auth_with_querystring
181
+ c = HTTPClient.new
182
+ c.debug_dev = STDERR if $DEBUG
183
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
184
+ assert_equal('digest_auth OKbar=baz', c.get_content("http://localhost:#{serverport}/digest_auth/foo?bar=baz"))
185
+ end
186
+
187
+ def test_perfer_digest
188
+ c = HTTPClient.new
189
+ c.set_auth('http://example.com/', 'admin', 'admin')
190
+ c.test_loopback_http_response << "HTTP/1.0 401 Unauthorized\nWWW-Authenticate: Basic realm=\"foo\"\nWWW-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
191
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
192
+ c.debug_dev = str = ''
193
+ c.get_content('http://example.com/')
194
+ assert_match(/^Authorization: Digest/, str)
195
+ end
196
+
197
+ def test_digest_sess_auth
198
+ c = HTTPClient.new
199
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
200
+ assert_equal('digest_sess_auth OK', c.get_content("http://localhost:#{serverport}/digest_sess_auth"))
201
+ end
202
+
203
+ def test_proxy_auth
204
+ c = HTTPClient.new
205
+ c.set_proxy_auth('admin', 'admin')
206
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Basic realm=\"foo\"\nContent-Length: 2\n\nNG"
207
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
208
+ c.debug_dev = str = ''
209
+ c.get_content('http://example.com/')
210
+ assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
211
+ end
212
+
213
+ def test_proxy_auth_reuses_credentials
214
+ c = HTTPClient.new
215
+ c.set_proxy_auth('admin', 'admin')
216
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Basic realm=\"foo\"\nContent-Length: 2\n\nNG"
217
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
218
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
219
+ c.get_content('http://www1.example.com/')
220
+ c.debug_dev = str = ''
221
+ c.get_content('http://www2.example.com/')
222
+ assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
223
+ end
224
+
225
+ def test_digest_proxy_auth_loop
226
+ c = HTTPClient.new
227
+ c.set_proxy_auth('admin', 'admin')
228
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
229
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
230
+ md5 = Digest::MD5.new
231
+ ha1 = md5.hexdigest("admin:foo:admin")
232
+ ha2 = md5.hexdigest("GET:/")
233
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
234
+ c.debug_dev = str = ''
235
+ c.get_content('http://example.com/')
236
+ assert_match(/Proxy-Authorization: Digest/, str)
237
+ assert_match(%r"response=\"#{response}\"", str)
238
+ end
239
+
240
+ def test_digest_proxy_auth
241
+ c=HTTPClient.new("http://localhost:#{proxyport}/")
242
+ c.set_proxy_auth('admin', 'admin')
243
+ c.set_auth("http://127.0.0.1:#{serverport}/", 'admin', 'admin')
244
+ assert_equal('basic_auth OK', c.get_content("http://127.0.0.1:#{serverport}/basic_auth"))
245
+ end
246
+
247
+ def test_digest_proxy_invalid_auth
248
+ c=HTTPClient.new("http://localhost:#{proxyport}/")
249
+ c.set_proxy_auth('admin', 'wrong')
250
+ c.set_auth("http://127.0.0.1:#{serverport}/", 'admin', 'admin')
251
+ assert_raises(HTTPClient::BadResponseError) do
252
+ c.get_content("http://127.0.0.1:#{serverport}/basic_auth")
253
+ end
254
+ end
255
+
256
+ def test_prefer_digest_to_basic_proxy_auth
257
+ c = HTTPClient.new
258
+ c.set_proxy_auth('admin', 'admin')
259
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nProxy-Authenticate: Basic realm=\"bar\"\nContent-Length: 2\n\nNG"
260
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
261
+ md5 = Digest::MD5.new
262
+ ha1 = md5.hexdigest("admin:foo:admin")
263
+ ha2 = md5.hexdigest("GET:/")
264
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
265
+ c.debug_dev = str = ''
266
+ c.get_content('http://example.com/')
267
+ assert_match(/Proxy-Authorization: Digest/, str)
268
+ assert_match(%r"response=\"#{response}\"", str)
269
+ end
270
+
271
+ def test_digest_proxy_auth_reuses_credentials
272
+ c = HTTPClient.new
273
+ c.set_proxy_auth('admin', 'admin')
274
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
275
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
276
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
277
+ md5 = Digest::MD5.new
278
+ ha1 = md5.hexdigest("admin:foo:admin")
279
+ ha2 = md5.hexdigest("GET:/")
280
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
281
+ c.get_content('http://www1.example.com/')
282
+ c.debug_dev = str = ''
283
+ c.get_content('http://www2.example.com/')
284
+ assert_match(/Proxy-Authorization: Digest/, str)
285
+ assert_match(%r"response=\"#{response}\"", str)
286
+ end
287
+
288
+ def test_oauth
289
+ c = HTTPClient.new
290
+ config = HTTPClient::OAuth::Config.new(
291
+ :realm => 'http://photos.example.net/',
292
+ :consumer_key => 'dpf43f3p2l4k3l03',
293
+ :consumer_secret => 'kd94hf93k423kf44',
294
+ :token => 'nnch734d00sl2jdk',
295
+ :secret => 'pfkkdhi9sl3r4s00',
296
+ :version => '1.0',
297
+ :signature_method => 'HMAC-SHA1'
298
+ )
299
+ config.debug_timestamp = '1191242096'
300
+ config.debug_nonce = 'kllo9940pd9333jh'
301
+ c.www_auth.oauth.set_config('http://photos.example.net/', config)
302
+ c.www_auth.oauth.challenge('http://photos.example.net/')
303
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
304
+ c.debug_dev = str = ''
305
+ c.get_content('http://photos.example.net/photos', [[:file, 'vacation.jpg'], [:size, 'original']])
306
+ assert(str.index(%q(GET /photos?file=vacation.jpg&size=original)))
307
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
308
+ #
309
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
310
+ c.debug_dev = str = ''
311
+ c.get_content('http://photos.example.net/photos?file=vacation.jpg&size=original')
312
+ assert(str.index(%q(GET /photos?file=vacation.jpg&size=original)))
313
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
314
+ #
315
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
316
+ c.debug_dev = str = ''
317
+ c.post_content('http://photos.example.net/photos', [[:file, 'vacation.jpg'], [:size, 'original']])
318
+ assert(str.index(%q(POST /photos)))
319
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="wPkvxykrw%2BBTdCcGqKr%2B3I%2BPsiM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
320
+ end
321
+ end