mechanize 0.6.11 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mechanize might be problematic. Click here for more details.

Files changed (91) hide show
  1. data/CHANGELOG.txt +8 -0
  2. data/Manifest.txt +31 -22
  3. data/lib/mechanize.rb +2 -652
  4. data/lib/www/mechanize.rb +635 -0
  5. data/lib/www/mechanize/content_type_error.rb +16 -0
  6. data/lib/www/mechanize/cookie.rb +64 -0
  7. data/lib/{mechanize/cookie.rb → www/mechanize/cookie_jar.rb} +0 -60
  8. data/lib/www/mechanize/file.rb +73 -0
  9. data/lib/www/mechanize/file_saver.rb +39 -0
  10. data/lib/{mechanize → www/mechanize}/form.rb +119 -137
  11. data/lib/www/mechanize/form/button.rb +8 -0
  12. data/lib/www/mechanize/form/check_box.rb +13 -0
  13. data/lib/www/mechanize/form/field.rb +28 -0
  14. data/lib/www/mechanize/form/file_upload.rb +24 -0
  15. data/lib/www/mechanize/form/image_button.rb +23 -0
  16. data/lib/www/mechanize/form/multi_select_list.rb +69 -0
  17. data/lib/www/mechanize/form/option.rb +51 -0
  18. data/lib/www/mechanize/form/radio_button.rb +38 -0
  19. data/lib/www/mechanize/form/select_list.rb +41 -0
  20. data/lib/www/mechanize/headers.rb +12 -0
  21. data/lib/{mechanize → www/mechanize}/history.rb +0 -0
  22. data/lib/{mechanize → www/mechanize}/inspect.rb +21 -28
  23. data/lib/{mechanize → www/mechanize}/list.rb +0 -0
  24. data/lib/{mechanize → www/mechanize}/monkey_patch.rb +19 -0
  25. data/lib/www/mechanize/page.rb +121 -0
  26. data/lib/www/mechanize/page/base.rb +10 -0
  27. data/lib/www/mechanize/page/frame.rb +22 -0
  28. data/lib/www/mechanize/page/link.rb +50 -0
  29. data/lib/www/mechanize/page/meta.rb +10 -0
  30. data/lib/www/mechanize/pluggable_parsers.rb +93 -0
  31. data/lib/{mechanize/errors.rb → www/mechanize/response_code_error.rb} +1 -13
  32. data/test/{test_includes.rb → helper.rb} +4 -18
  33. data/test/{test_servlets.rb → servlets.rb} +0 -0
  34. data/test/tc_authenticate.rb +1 -8
  35. data/test/tc_bad_links.rb +3 -10
  36. data/test/tc_blank_form.rb +1 -8
  37. data/test/tc_checkboxes.rb +1 -8
  38. data/test/tc_cookie_class.rb +1 -6
  39. data/test/tc_cookie_jar.rb +1 -7
  40. data/test/tc_cookies.rb +10 -17
  41. data/test/tc_encoded_links.rb +5 -12
  42. data/test/tc_errors.rb +4 -11
  43. data/test/tc_follow_meta.rb +1 -8
  44. data/test/tc_form_action.rb +6 -14
  45. data/test/tc_form_as_hash.rb +1 -9
  46. data/test/tc_form_button.rb +5 -8
  47. data/test/tc_form_no_inputname.rb +1 -8
  48. data/test/tc_forms.rb +16 -24
  49. data/test/tc_frames.rb +3 -10
  50. data/test/tc_gzipping.rb +2 -9
  51. data/test/tc_history.rb +5 -12
  52. data/test/tc_html_unscape_forms.rb +8 -15
  53. data/test/tc_if_modified_since.rb +1 -6
  54. data/test/tc_keep_alive.rb +1 -8
  55. data/test/tc_links.rb +12 -19
  56. data/test/tc_mech.rb +26 -34
  57. data/test/{test_mechanize_file.rb → tc_mechanize_file.rb} +1 -6
  58. data/test/tc_multi_select.rb +10 -17
  59. data/test/tc_no_attributes.rb +1 -8
  60. data/test/tc_page.rb +3 -10
  61. data/test/tc_pluggable_parser.rb +8 -15
  62. data/test/tc_post_form.rb +3 -10
  63. data/test/tc_pretty_print.rb +3 -10
  64. data/test/tc_radiobutton.rb +2 -9
  65. data/test/tc_referer.rb +13 -20
  66. data/test/tc_relative_links.rb +1 -8
  67. data/test/tc_response_code.rb +14 -21
  68. data/test/tc_save_file.rb +1 -9
  69. data/test/tc_select.rb +3 -10
  70. data/test/tc_select_all.rb +2 -10
  71. data/test/tc_select_none.rb +2 -10
  72. data/test/tc_select_noopts.rb +2 -9
  73. data/test/tc_set_fields.rb +2 -9
  74. data/test/tc_ssl_server.rb +5 -12
  75. data/test/tc_subclass.rb +2 -9
  76. data/test/tc_textarea.rb +2 -9
  77. data/test/tc_upload.rb +2 -9
  78. data/test/test_all.rb +4 -43
  79. metadata +96 -80
  80. data/lib/mechanize/form_elements.rb +0 -254
  81. data/lib/mechanize/net-overrides/net/http.rb +0 -2107
  82. data/lib/mechanize/net-overrides/net/https.rb +0 -172
  83. data/lib/mechanize/net-overrides/net/protocol.rb +0 -380
  84. data/lib/mechanize/page.rb +0 -138
  85. data/lib/mechanize/page_elements.rb +0 -77
  86. data/lib/mechanize/parsers/rexml_page.rb +0 -35
  87. data/lib/mechanize/pluggable_parsers.rb +0 -204
  88. data/lib/mechanize/rexml.rb +0 -236
  89. data/setup.rb +0 -1585
  90. data/test/tc_proxy.rb +0 -25
  91. data/test/tc_watches.rb +0 -32
@@ -1,2107 +0,0 @@
1
- # :enddoc:
2
- # = net/http.rb
3
- #
4
- # Copyright (C) 1999-2005 Yukihiro Matsumoto
5
- # Copyright (C) 1999-2005 Minero Aoki
6
- # Copyright (C) 2001 GOTOU Yuuzou
7
- #
8
- # Written and maintained by Minero Aoki <aamine@loveruby.net>.
9
- # HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
10
- #
11
- # This file is derived from "http-access.rb".
12
- #
13
- # Documented by Minero Aoki; converted to RDoc by William Webber.
14
- #
15
- # This program is free software. You can re-distribute and/or
16
- # modify this program under the same terms of ruby itself ---
17
- # Ruby Distribution License or GNU General Public License.
18
- #
19
- # See Net:::HTTP for an overview and examples.
20
- #
21
- # NOTE: You can find Japanese version of this document here:
22
- # http://www.ruby-lang.org/ja/man/?cmd=view;name=net%2Fhttp.rb
23
- #
24
- #--
25
- # $Id: http.rb,v 1.123 2005/01/01 08:59:47 aamine Exp $
26
- #++
27
-
28
- require 'net/protocol'
29
- require 'uri'
30
-
31
- module Net # :nodoc:
32
-
33
- # :stopdoc:
34
- class HTTPBadResponse < StandardError; end
35
- class HTTPHeaderSyntaxError < StandardError; end
36
- # :startdoc:
37
-
38
- # == What Is This Library?
39
- #
40
- # This library provides your program functions to access WWW
41
- # documents via HTTP, Hyper Text Transfer Protocol version 1.1.
42
- # For details of HTTP, refer [RFC2616]
43
- # (http://www.ietf.org/rfc/rfc2616.txt).
44
- #
45
- # == Examples
46
- #
47
- # === Getting Document From WWW Server
48
- #
49
- # (formal version)
50
- #
51
- # require 'net/http'
52
- # Net::HTTP.start('www.example.com', 80) {|http|
53
- # response = http.get('/index.html')
54
- # puts response.body
55
- # }
56
- #
57
- # (shorter version)
58
- #
59
- # require 'net/http'
60
- # Net::HTTP.get_print 'www.example.com', '/index.html'
61
- #
62
- # or
63
- #
64
- # require 'net/http'
65
- # require 'uri'
66
- # Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
67
- #
68
- # === Posting Form Data
69
- #
70
- # require 'net/http'
71
- # Net::HTTP.start('some.www.server', 80) {|http|
72
- # response = http.post('/cgi-bin/search.rb', 'query=ruby')
73
- # }
74
- #
75
- # === Accessing via Proxy
76
- #
77
- # Net::HTTP.Proxy creates http proxy class. It has same
78
- # methods of Net::HTTP but its instances always connect to
79
- # proxy, instead of given host.
80
- #
81
- # require 'net/http'
82
- #
83
- # proxy_addr = 'your.proxy.host'
84
- # proxy_port = 8080
85
- # :
86
- # Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
87
- # # always connect to your.proxy.addr:8080
88
- # :
89
- # }
90
- #
91
- # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
92
- # there's no need to change code if there's proxy or not.
93
- #
94
- # There are two additional parameters in Net::HTTP.Proxy which allow to
95
- # specify proxy user name and password:
96
- #
97
- # Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
98
- #
99
- # You may use them to work with authorization-enabled proxies:
100
- #
101
- # require 'net/http'
102
- # require 'uri'
103
- #
104
- # proxy_host = 'your.proxy.host'
105
- # proxy_port = 8080
106
- # uri = URI.parse(ENV['http_proxy'])
107
- # proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
108
- # Net::HTTP::Proxy(proxy_host, proxy_port,
109
- # proxy_user, proxy_pass).start('www.example.com') {|http|
110
- # # always connect to your.proxy.addr:8080 using specified username and password
111
- # :
112
- # }
113
- #
114
- # Note that net/http never rely on HTTP_PROXY environment variable.
115
- # If you want to use proxy, set it explicitly.
116
- #
117
- # === Following Redirection
118
- #
119
- # require 'net/http'
120
- # require 'uri'
121
- #
122
- # def fetch( uri_str, limit = 10 )
123
- # # You should choose better exception.
124
- # raise ArgumentError, 'HTTP redirect too deep' if limit == 0
125
- #
126
- # response = Net::HTTP.get_response(URI.parse(uri_str))
127
- # case response
128
- # when Net::HTTPSuccess then response
129
- # when Net::HTTPRedirection then fetch(response['location'], limit - 1)
130
- # else
131
- # response.error!
132
- # end
133
- # end
134
- #
135
- # print fetch('http://www.ruby-lang.org')
136
- #
137
- # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
138
- # All HTTPResponse objects belong to its own response class which
139
- # indicate HTTP result status. For details of response classes,
140
- # see section "HTTP Response Classes".
141
- #
142
- # === Basic Authentication
143
- #
144
- # require 'net/http'
145
- #
146
- # Net::HTTP.start('www.example.com') {|http|
147
- # req = Net::HTTP::Get.new('/secret-page.html')
148
- # req.basic_auth 'account', 'password'
149
- # response = http.request(req)
150
- # print response.body
151
- # }
152
- #
153
- # === HTTP Response Classes
154
- #
155
- # TODO: write me.
156
- #
157
- # == Switching Net::HTTP versions
158
- #
159
- # You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
160
- # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
161
- # allows you to use 1.2 features again.
162
- #
163
- # # example
164
- # Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
165
- #
166
- # Net::HTTP.version_1_1
167
- # Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
168
- #
169
- # Net::HTTP.version_1_2
170
- # Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
171
- #
172
- # This function is NOT thread-safe.
173
- #
174
- class HTTP < Protocol
175
-
176
- # :stopdoc:
177
- Revision = %q$Revision: 1.123 $.split[1]
178
- HTTPVersion = '1.1'
179
- @newimpl = true # for backward compatability
180
- # :startdoc:
181
-
182
- # Turns on net/http 1.2 (ruby 1.8) features.
183
- # Defaults to ON in ruby 1.8.
184
- #
185
- # I strongly recommend to call this method always.
186
- #
187
- # require 'net/http'
188
- # Net::HTTP.version_1_2
189
- #
190
- def HTTP.version_1_2
191
- @newimpl = true
192
- end
193
-
194
- # Turns on net/http 1.1 (ruby 1.6) features.
195
- # Defaults to OFF in ruby 1.8.
196
- def HTTP.version_1_1
197
- @newimpl = false
198
- end
199
-
200
- # true if net/http is in version 1.2 mode.
201
- # Defaults to true.
202
- def HTTP.version_1_2?
203
- @newimpl
204
- end
205
-
206
- # true if net/http is in version 1.1 compatible mode.
207
- # Defaults to true.
208
- def HTTP.version_1_1?
209
- not @newimpl
210
- end
211
-
212
- class << HTTP
213
- alias is_version_1_1? version_1_1? #:nodoc:
214
- alias is_version_1_2? version_1_2? #:nodoc:
215
- end
216
-
217
- #
218
- # short cut methods
219
- #
220
-
221
- #
222
- # Get body from target and output it to +$stdout+. The
223
- # target can either be specified as (+uri+), or as
224
- # (+host+, +path+, +port+ = 80); so:
225
- #
226
- # Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
227
- #
228
- # or:
229
- #
230
- # Net::HTTP.get_print('www.example.com', '/index.html')
231
- #
232
- def HTTP.get_print(arg1, arg2 = nil, port = nil)
233
- if arg2
234
- addr, path = arg1, arg2
235
- else
236
- uri = arg1
237
- addr = uri.host
238
- path = uri.request_uri
239
- port = uri.port
240
- end
241
- new(addr, port || HTTP.default_port).start {|http|
242
- http.get path, nil, $stdout
243
- }
244
- nil
245
- end
246
-
247
- # Send a GET request to the target and return the response
248
- # as a string. The target can either be specified as
249
- # (+uri+), or as (+host+, +path+, +port+ = 80); so:
250
- #
251
- # print Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
252
- #
253
- # or:
254
- #
255
- # print Net::HTTP.get('www.example.com', '/index.html')
256
- #
257
- def HTTP.get(arg1, arg2 = nil, arg3 = nil)
258
- get_response(arg1,arg2,arg3).body
259
- end
260
-
261
- # Send a GET request to the target and return the response
262
- # as a Net::HTTPResponse object. The target can either be specified as
263
- # (+uri+), or as (+host+, +path+, +port+ = 80); so:
264
- #
265
- # res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html'))
266
- # print res.body
267
- #
268
- # or:
269
- #
270
- # res = Net::HTTP.get_response('www.example.com', '/index.html')
271
- # print res.body
272
- #
273
- def HTTP.get_response(arg1, arg2 = nil, arg3 = nil)
274
- if arg2
275
- get_by_path(arg1, arg2, arg3)
276
- else
277
- get_by_uri(arg1)
278
- end
279
- end
280
-
281
- def HTTP.get_by_path(addr, path, port = nil) #:nodoc:
282
- new(addr, port || HTTP.default_port).start {|http|
283
- return http.request(Get.new(path))
284
- }
285
- end
286
- private_class_method :get_by_path
287
-
288
- def HTTP.get_by_uri(uri) #:nodoc:
289
- # Should we allow this?
290
- # uri = URI.parse(uri) unless uri.respond_to?(:host)
291
- new(uri.host, uri.port).start {|http|
292
- return http.request(Get.new(uri.request_uri))
293
- }
294
- end
295
- private_class_method :get_by_uri
296
-
297
- #
298
- # HTTP session management
299
- #
300
-
301
- # The default port to use for HTTP requests; defaults to 80.
302
- def HTTP.default_port
303
- http_default_port()
304
- end
305
-
306
- # The default port to use for HTTP requests; defaults to 80.
307
- def HTTP.http_default_port
308
- 80
309
- end
310
-
311
- # The default port to use for HTTPS requests; defaults to 443.
312
- def HTTP.https_default_port
313
- 443
314
- end
315
-
316
- def HTTP.socket_type #:nodoc: obsolete
317
- InternetMessageIO
318
- end
319
-
320
- # creates a new Net::HTTP object and opens its TCP connection and
321
- # HTTP session. If the optional block is given, the newly
322
- # created Net::HTTP object is passed to it and closed when the
323
- # block finishes. In this case, the return value of this method
324
- # is the return value of the block. If no block is given, the
325
- # return value of this method is the newly created Net::HTTP object
326
- # itself, and the caller is responsible for closing it upon completion.
327
- def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+
328
- new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
329
- end
330
-
331
- class << HTTP
332
- alias newobj new
333
- end
334
-
335
- # Creates a new Net::HTTP object.
336
- # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support.
337
- # This method does not open the TCP connection.
338
- def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil)
339
- h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port)
340
- h.instance_eval {
341
- @newimpl = ::Net::HTTP.version_1_2?
342
- }
343
- h
344
- end
345
-
346
- # Creates a new Net::HTTP object for the specified +address+.
347
- # This method does not open the TCP connection.
348
- def initialize(address, port = nil)
349
- @address = address
350
- @port = (port || HTTP.default_port)
351
- @curr_http_version = HTTPVersion
352
- @seems_1_0_server = false
353
- @close_on_empty_response = false
354
- @socket = nil
355
- @started = false
356
- @open_timeout = 30
357
- @read_timeout = 60
358
- @debug_output = nil
359
- @use_ssl = false
360
- @ssl_context = nil
361
- end
362
-
363
- def inspect
364
- "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
365
- end
366
-
367
- # *WARNING* This method causes serious security hole.
368
- # Never use this method in production code.
369
- #
370
- # Set an output stream for debugging.
371
- #
372
- # http = Net::HTTP.new
373
- # http.set_debug_output $stderr
374
- # http.start { .... }
375
- #
376
- def set_debug_output(output)
377
- warn 'Net::HTTP#set_debug_output called after HTTP started' if started?
378
- @debug_output = output
379
- end
380
-
381
- # The host name to connect to.
382
- attr_reader :address
383
-
384
- # The port number to connect to.
385
- attr_reader :port
386
-
387
- # Seconds to wait until connection is opened.
388
- # If the HTTP object cannot open a connection in this many seconds,
389
- # it raises a TimeoutError exception.
390
- attr_accessor :open_timeout
391
-
392
- # Seconds to wait until reading one block (by one read(2) call).
393
- # If the HTTP object cannot open a connection in this many seconds,
394
- # it raises a TimeoutError exception.
395
- attr_reader :read_timeout
396
-
397
- # Setter for the read_timeout attribute.
398
- def read_timeout=(sec)
399
- @socket.read_timeout = sec if @socket
400
- @read_timeout = sec
401
- end
402
-
403
- # returns true if the HTTP session is started.
404
- def started?
405
- @started
406
- end
407
-
408
- alias active? started? #:nodoc: obsolete
409
-
410
- attr_accessor :close_on_empty_response
411
-
412
- # returns true if use SSL/TLS with HTTP.
413
- def use_ssl?
414
- false # redefined in net/https
415
- end
416
-
417
- # Opens TCP connection and HTTP session.
418
- #
419
- # When this method is called with block, gives a HTTP object
420
- # to the block and closes the TCP connection / HTTP session
421
- # after the block executed.
422
- #
423
- # When called with a block, returns the return value of the
424
- # block; otherwise, returns self.
425
- #
426
- def start # :yield: http
427
- raise IOError, 'HTTP session already opened' if @started
428
- if block_given?
429
- begin
430
- do_start
431
- return yield(self)
432
- ensure
433
- do_finish
434
- end
435
- end
436
- do_start
437
- self
438
- end
439
-
440
- def do_start
441
- connect
442
- @started = true
443
- end
444
- private :do_start
445
-
446
- def connect
447
- D "opening connection to #{conn_address()}..."
448
- s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
449
- D "opened"
450
- if use_ssl?
451
- unless @ssl_context.verify_mode
452
- warn "warning: peer certificate won't be verified in this SSL session"
453
- @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
454
- end
455
- s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
456
- s.sync_close = true
457
- end
458
- @socket = BufferedIO.new(s)
459
- @socket.read_timeout = @read_timeout
460
- @socket.debug_output = @debug_output
461
- if use_ssl?
462
- if proxy?
463
- @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
464
- @address, @port, HTTPVersion)
465
- @socket.writeline ''
466
- HTTPResponse.read_new(@socket).value
467
- end
468
- s.connect
469
- end
470
- on_connect
471
- end
472
- private :connect
473
-
474
- def on_connect
475
- end
476
- private :on_connect
477
-
478
- # Finishes HTTP session and closes TCP connection.
479
- # Raises IOError if not started.
480
- def finish
481
- raise IOError, 'HTTP session not yet started' unless started?
482
- do_finish
483
- end
484
-
485
- def do_finish
486
- @started = false
487
- @socket.close if @socket and not @socket.closed?
488
- @socket = nil
489
- end
490
- private :do_finish
491
-
492
- #
493
- # proxy
494
- #
495
-
496
- public
497
-
498
- # no proxy
499
- @is_proxy_class = false
500
- @proxy_addr = nil
501
- @proxy_port = nil
502
- @proxy_user = nil
503
- @proxy_pass = nil
504
-
505
- # Creates an HTTP proxy class.
506
- # Arguments are address/port of proxy host and username/password
507
- # if authorization on proxy server is required.
508
- # You can replace the HTTP class with created proxy class.
509
- #
510
- # If ADDRESS is nil, this method returns self (Net::HTTP).
511
- #
512
- # # Example
513
- # proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
514
- # :
515
- # proxy_class.start('www.ruby-lang.org') {|http|
516
- # # connecting proxy.foo.org:8080
517
- # :
518
- # }
519
- #
520
- def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil)
521
- return self unless p_addr
522
- delta = ProxyDelta
523
- proxyclass = Class.new(self)
524
- proxyclass.module_eval {
525
- include delta
526
- # with proxy
527
- @is_proxy_class = true
528
- @proxy_address = p_addr
529
- @proxy_port = p_port || default_port()
530
- @proxy_user = p_user
531
- @proxy_pass = p_pass
532
- }
533
- proxyclass
534
- end
535
-
536
- class << HTTP
537
- # returns true if self is a class which was created by HTTP::Proxy.
538
- def proxy_class?
539
- @is_proxy_class
540
- end
541
-
542
- attr_reader :proxy_address
543
- attr_reader :proxy_port
544
- attr_reader :proxy_user
545
- attr_reader :proxy_pass
546
- end
547
-
548
- # True if self is a HTTP proxy class.
549
- def proxy?
550
- self.class.proxy_class?
551
- end
552
-
553
- # Address of proxy host. If self does not use a proxy, nil.
554
- def proxy_address
555
- self.class.proxy_address
556
- end
557
-
558
- # Port number of proxy host. If self does not use a proxy, nil.
559
- def proxy_port
560
- self.class.proxy_port
561
- end
562
-
563
- # User name for accessing proxy. If self does not use a proxy, nil.
564
- def proxy_user
565
- self.class.proxy_user
566
- end
567
-
568
- # User password for accessing proxy. If self does not use a proxy, nil.
569
- def proxy_pass
570
- self.class.proxy_pass
571
- end
572
-
573
- alias proxyaddr proxy_address #:nodoc: obsolete
574
- alias proxyport proxy_port #:nodoc: obsolete
575
-
576
- private
577
-
578
- # without proxy
579
-
580
- def conn_address
581
- address()
582
- end
583
-
584
- def conn_port
585
- port()
586
- end
587
-
588
- def edit_path(path)
589
- path
590
- end
591
-
592
- module ProxyDelta #:nodoc: internal use only
593
- private
594
-
595
- def conn_address
596
- proxy_address()
597
- end
598
-
599
- def conn_port
600
- proxy_port()
601
- end
602
-
603
- def edit_path(path)
604
- if use_ssl?
605
- "https://#{addr_port()}#{path}"
606
- else
607
- "http://#{addr_port()}#{path}"
608
- end
609
- end
610
- end
611
-
612
- #
613
- # HTTP operations
614
- #
615
-
616
- public
617
-
618
- # Gets data from +path+ on the connected-to host.
619
- # +header+ must be a Hash like { 'Accept' => '*/*', ... }.
620
- #
621
- # In version 1.1 (ruby 1.6), this method returns a pair of objects,
622
- # a Net::HTTPResponse object and the entity body string.
623
- # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse
624
- # object.
625
- #
626
- # If called with a block, yields each fragment of the
627
- # entity body in turn as a string as it is read from
628
- # the socket. Note that in this case, the returned response
629
- # object will *not* contain a (meaningful) body.
630
- #
631
- # +dest+ argument is obsolete.
632
- # It still works but you must not use it.
633
- #
634
- # In version 1.1, this method might raise an exception for
635
- # 3xx (redirect). In this case you can get a HTTPResponse object
636
- # by "anException.response".
637
- #
638
- # In version 1.2, this method never raises exception.
639
- #
640
- # # version 1.1 (bundled with Ruby 1.6)
641
- # response, body = http.get('/index.html')
642
- #
643
- # # version 1.2 (bundled with Ruby 1.8 or later)
644
- # response = http.get('/index.html')
645
- #
646
- # # using block
647
- # File.open('result.txt', 'w') {|f|
648
- # http.get('/~foo/') do |str|
649
- # f.write str
650
- # end
651
- # }
652
- #
653
- def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
654
- res = nil
655
- request(Get.new(path, initheader)) {|r|
656
- r.read_body dest, &block
657
- res = r
658
- }
659
- unless @newimpl
660
- res.value
661
- return res, res.body
662
- end
663
-
664
- res
665
- end
666
-
667
- # Gets only the header from +path+ on the connected-to host.
668
- # +header+ is a Hash like { 'Accept' => '*/*', ... }.
669
- #
670
- # This method returns a Net::HTTPResponse object.
671
- #
672
- # In version 1.1, this method might raise an exception for
673
- # 3xx (redirect). On the case you can get a HTTPResponse object
674
- # by "anException.response".
675
- # In version 1.2, this method never raises an exception.
676
- #
677
- # response = nil
678
- # Net::HTTP.start('some.www.server', 80) {|http|
679
- # response = http.head('/index.html')
680
- # }
681
- # p response['content-type']
682
- #
683
- def head(path, initheader = nil)
684
- res = request(Head.new(path, initheader))
685
- res.value unless @newimpl
686
- res
687
- end
688
-
689
- # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
690
- # like { 'Accept' => '*/*', ... }.
691
- #
692
- # In version 1.1 (ruby 1.6), this method returns a pair of objects, a
693
- # Net::HTTPResponse object and an entity body string.
694
- # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object.
695
- #
696
- # If called with a block, yields each fragment of the
697
- # entity body in turn as a string as it are read from
698
- # the socket. Note that in this case, the returned response
699
- # object will *not* contain a (meaningful) body.
700
- #
701
- # +dest+ is an alternative method of collecting the body. It
702
- # must be an object responding to the "<<" operator (such as
703
- # a String or an Array). Each fragment of the entity body
704
- # will be "<<"-ed in turn onto +dest+ if provided, and it will
705
- # also become the body of the returned response object.
706
- #
707
- # You must *not* provide both +dest+ and a block; doing so
708
- # will result in an ArgumentError.
709
- #
710
- # In version 1.1, this method might raise an exception for
711
- # 3xx (redirect). In this case you can get an HTTPResponse object
712
- # by "anException.response".
713
- # In version 1.2, this method never raises exception.
714
- #
715
- # # version 1.1
716
- # response, body = http.post('/cgi-bin/search.rb', 'query=foo')
717
- #
718
- # # version 1.2
719
- # response = http.post('/cgi-bin/search.rb', 'query=foo')
720
- #
721
- # # using block
722
- # File.open('result.txt', 'w') {|f|
723
- # http.post('/cgi-bin/search.rb', 'query=foo') do |str|
724
- # f.write str
725
- # end
726
- # }
727
- #
728
- def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
729
- res = nil
730
- request(Post.new(path, initheader), data) {|r|
731
- r.read_body dest, &block
732
- res = r
733
- }
734
- unless @newimpl
735
- res.value
736
- return res, res.body
737
- end
738
-
739
- res
740
- end
741
-
742
- def put(path, data, initheader = nil) #:nodoc:
743
- res = request(Put.new(path, initheader), data)
744
- res.value unless @newimpl
745
- res
746
- end
747
-
748
- # Sends a PROPPATCH request to the +path+ and gets a response,
749
- # as an HTTPResponse object.
750
- def proppatch(path, body, initheader = nil)
751
- request(Proppatch.new(path, initheader), body)
752
- end
753
-
754
- # Sends a LOCK request to the +path+ and gets a response,
755
- # as an HTTPResponse object.
756
- def lock(path, body, initheader = nil)
757
- request(Lock.new(path, initheader), body)
758
- end
759
-
760
- # Sends a UNLOCK request to the +path+ and gets a response,
761
- # as an HTTPResponse object.
762
- def unlock(path, body, initheader = nil)
763
- request(Unlock.new(path, initheader), body)
764
- end
765
-
766
- # Sends a OPTIONS request to the +path+ and gets a response,
767
- # as an HTTPResponse object.
768
- def options(path, initheader = nil)
769
- request(Options.new(path, initheader))
770
- end
771
-
772
- # Sends a PROPFIND request to the +path+ and gets a response,
773
- # as an HTTPResponse object.
774
- def propfind(path, body = nil, initheader = {'Depth' => '0'})
775
- request(Propfind.new(path, initheader), body)
776
- end
777
-
778
- # Sends a DELETE request to the +path+ and gets a response,
779
- # as an HTTPResponse object.
780
- def delete(path, initheader = {'Depth' => 'Infinity'})
781
- request(Delete.new(path, initheader))
782
- end
783
-
784
- # Sends a MOVE request to the +path+ and gets a response,
785
- # as an HTTPResponse object.
786
- def move(path, initheader = nil)
787
- request(Move.new(path, initheader))
788
- end
789
-
790
- # Sends a COPY request to the +path+ and gets a response,
791
- # as an HTTPResponse object.
792
- def copy(path, initheader = nil)
793
- request(Copy.new(path, initheader))
794
- end
795
-
796
- # Sends a MKCOL request to the +path+ and gets a response,
797
- # as an HTTPResponse object.
798
- def mkcol(path, body = nil, initheader = nil)
799
- request(Mkcol.new(path, initheader), body)
800
- end
801
-
802
- # Sends a TRACE request to the +path+ and gets a response,
803
- # as an HTTPResponse object.
804
- def trace(path, initheader = nil)
805
- request(Trace.new(path, initheader))
806
- end
807
-
808
- # Sends a GET request to the +path+ and gets a response,
809
- # as an HTTPResponse object.
810
- #
811
- # When called with a block, yields an HTTPResponse object.
812
- # The body of this response will not have been read yet;
813
- # the caller can process it using HTTPResponse#read_body,
814
- # if desired.
815
- #
816
- # Returns the response.
817
- #
818
- # This method never raises Net::* exceptions.
819
- #
820
- # response = http.request_get('/index.html')
821
- # # The entity body is already read here.
822
- # p response['content-type']
823
- # puts response.body
824
- #
825
- # # using block
826
- # http.request_get('/index.html') {|response|
827
- # p response['content-type']
828
- # response.read_body do |str| # read body now
829
- # print str
830
- # end
831
- # }
832
- #
833
- def request_get(path, initheader = nil, &block) # :yield: +response+
834
- request(Get.new(path, initheader), &block)
835
- end
836
-
837
- # Sends a HEAD request to the +path+ and gets a response,
838
- # as an HTTPResponse object.
839
- #
840
- # Returns the response.
841
- #
842
- # This method never raises Net::* exceptions.
843
- #
844
- # response = http.request_head('/index.html')
845
- # p response['content-type']
846
- #
847
- def request_head(path, initheader = nil, &block)
848
- request(Head.new(path, initheader), &block)
849
- end
850
-
851
- # Sends a POST request to the +path+ and gets a response,
852
- # as an HTTPResponse object.
853
- #
854
- # When called with a block, yields an HTTPResponse object.
855
- # The body of this response will not have been read yet;
856
- # the caller can process it using HTTPResponse#read_body,
857
- # if desired.
858
- #
859
- # Returns the response.
860
- #
861
- # This method never raises Net::* exceptions.
862
- #
863
- # # example
864
- # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
865
- # p response.status
866
- # puts response.body # body is already read
867
- #
868
- # # using block
869
- # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
870
- # p response.status
871
- # p response['content-type']
872
- # response.read_body do |str| # read body now
873
- # print str
874
- # end
875
- # }
876
- #
877
- def request_post(path, data, initheader = nil, &block) # :yield: +response+
878
- request Post.new(path, initheader), data, &block
879
- end
880
-
881
- def request_put(path, data, initheader = nil, &block) #:nodoc:
882
- request Put.new(path, initheader), data, &block
883
- end
884
-
885
- alias get2 request_get #:nodoc: obsolete
886
- alias head2 request_head #:nodoc: obsolete
887
- alias post2 request_post #:nodoc: obsolete
888
- alias put2 request_put #:nodoc: obsolete
889
-
890
-
891
- # Sends an HTTP request to the HTTP server.
892
- # This method also sends DATA string if DATA is given.
893
- #
894
- # Returns a HTTPResponse object.
895
- #
896
- # This method never raises Net::* exceptions.
897
- #
898
- # response = http.send_request('GET', '/index.html')
899
- # puts response.body
900
- #
901
- def send_request(name, path, data = nil, header = nil)
902
- r = HTTPGenericRequest.new(name,(data ? true : false),true,path,header)
903
- request r, data
904
- end
905
-
906
- # Sends an HTTPRequest object REQUEST to the HTTP server.
907
- # This method also sends DATA string if REQUEST is a post/put request.
908
- # Giving DATA for get/head request causes ArgumentError.
909
- #
910
- # When called with a block, yields an HTTPResponse object.
911
- # The body of this response will not have been read yet;
912
- # the caller can process it using HTTPResponse#read_body,
913
- # if desired.
914
- #
915
- # Returns a HTTPResponse object.
916
- #
917
- # This method never raises Net::* exceptions.
918
- #
919
- def request(req, body = nil, &block) # :yield: +response+
920
- unless started?
921
- start {
922
- req['connection'] ||= 'close'
923
- return request(req, body, &block)
924
- }
925
- end
926
- if proxy_user()
927
- req.proxy_basic_auth proxy_user(), proxy_pass()
928
- end
929
-
930
- req.set_body_internal body
931
- begin_transport req
932
- req.exec @socket, @curr_http_version, edit_path(req.path)
933
- begin
934
- res = HTTPResponse.read_new(@socket)
935
- end while res.kind_of?(HTTPContinue)
936
- res.reading_body(@socket, req.response_body_permitted?) {
937
- yield res if block_given?
938
- }
939
- end_transport req, res
940
-
941
- res
942
- end
943
-
944
- private
945
-
946
- def begin_transport(req)
947
- if @socket.closed?
948
- connect
949
- end
950
- if @seems_1_0_server
951
- req['connection'] ||= 'close'
952
- end
953
- if not req.response_body_permitted? and @close_on_empty_response
954
- req['connection'] ||= 'close'
955
- end
956
- req['host'] ||= addr_port()
957
- end
958
-
959
- def end_transport(req, res)
960
- @curr_http_version = res.http_version
961
- if not res.body and @close_on_empty_response
962
- D 'Conn close'
963
- @socket.close
964
- elsif keep_alive?(req, res)
965
- D 'Conn keep-alive'
966
- if @socket.closed?
967
- D 'Conn (but seems 1.0 server)'
968
- @seems_1_0_server = true
969
- end
970
- else
971
- D 'Conn close'
972
- @socket.close
973
- end
974
- end
975
-
976
- def keep_alive?(req, res)
977
- return false if /close/i =~ req['connection'].to_s
978
- return false if @seems_1_0_server
979
- return true if /keep-alive/i =~ res['connection'].to_s
980
- return false if /close/i =~ res['connection'].to_s
981
- return true if /keep-alive/i =~ res['proxy-connection'].to_s
982
- return false if /close/i =~ res['proxy-connection'].to_s
983
- (@curr_http_version == '1.1')
984
- end
985
-
986
- #
987
- # utils
988
- #
989
-
990
- private
991
-
992
- def addr_port
993
- if use_ssl?
994
- address() + (port == HTTP.https_default_port ? '' : ":#{port()}")
995
- else
996
- address() + (port == HTTP.http_default_port ? '' : ":#{port()}")
997
- end
998
- end
999
-
1000
- def D(msg)
1001
- return unless @debug_output
1002
- @debug_output << msg
1003
- @debug_output << "\n"
1004
- end
1005
-
1006
- end
1007
-
1008
- HTTPSession = HTTP
1009
-
1010
-
1011
- #
1012
- # Header module.
1013
- #
1014
- # Provides access to @header in the mixed-into class as a hash-like
1015
- # object, except with case-insensitive keys. Also provides
1016
- # methods for accessing commonly-used header values in a more
1017
- # convenient format.
1018
- #
1019
- module HTTPHeader
1020
-
1021
- def initialize_http_header(initheader)
1022
- @header = {}
1023
- return unless initheader
1024
- initheader.each do |key, value|
1025
- warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
1026
- @header[key.downcase] = [value.strip]
1027
- end
1028
- end
1029
-
1030
- def size #:nodoc: obsolete
1031
- @header.size
1032
- end
1033
-
1034
- alias length size #:nodoc: obsolete
1035
-
1036
- # Returns the header field corresponding to the case-insensitive key.
1037
- # For example, a key of "Content-Type" might return "text/html"
1038
- def [](key)
1039
- a = @header[key.downcase] or return nil
1040
- a.join(', ')
1041
- end
1042
-
1043
- # Sets the header field corresponding to the case-insensitive key.
1044
- def []=(key, val)
1045
- unless val
1046
- @header.delete key.downcase
1047
- return val
1048
- end
1049
- @header[key.downcase] = Array(val).map {|s| s.to_str }
1050
- end
1051
-
1052
- # Adds header name and field instead of replace.
1053
- #
1054
- # request.add_header 'X-My-Header', 'a'
1055
- # p request['X-My-Header'] #=> "a"
1056
- # request.add_header 'X-My-Header', 'b'
1057
- # p request['X-My-Header'] #=> "a, b"
1058
- # request.add_header 'X-My-Header', 'c'
1059
- # p request['X-My-Header'] #=> "a, b, c"
1060
- # p request.get_fields('X-My-Header') #=> ["a", "b", "c"]
1061
- #
1062
- def add_field(key, val)
1063
- if @header.key?(key.downcase)
1064
- @header[key.downcase].concat Array(val)
1065
- else
1066
- @header[key.downcase] = Array(val).dup
1067
- end
1068
- end
1069
-
1070
- # Returns the header field by Array, corresponding to the
1071
- # case-insensitive key. This method allows you to get duplicated
1072
- # fields without any processing.
1073
- #
1074
- # p response.get_fields('Set-Cookie')
1075
- # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
1076
- # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
1077
- # p response['Set-Cookie']
1078
- # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
1079
- #
1080
- def get_fields(key)
1081
- return nil unless @header[key.downcase]
1082
- @header[key.downcase].dup
1083
- end
1084
-
1085
- # Returns the header field corresponding to the case-insensitive key.
1086
- # Returns the default value +args+, or the result of the block, or nil,
1087
- # if there's no header field named key. See Hash#fetch
1088
- def fetch(key, *args, &block) #:yield: +key+
1089
- a = @header.fetch(key.downcase, *args, &block)
1090
- a.join(', ')
1091
- end
1092
-
1093
- # Iterates for each header names and values.
1094
- def each_header #:yield: +key+, +value+
1095
- @header.each do |k,va|
1096
- yield k, va.join(', ')
1097
- end
1098
- end
1099
-
1100
- alias each each_header
1101
-
1102
- # Iterates for each header names.
1103
- def each_name(&block) #:yield: +key+
1104
- @header.each_key(&block)
1105
- end
1106
-
1107
- alias each_key each_name
1108
-
1109
- # Iterates for each capitalized header names.
1110
- def each_capitalized_name(&block) #:yield: +key+
1111
- @header.each_key do |k|
1112
- yield capitalize(k)
1113
- end
1114
- end
1115
-
1116
- # Iterates for each header values.
1117
- def each_value #:yield: +value+
1118
- @header.each_value do |va|
1119
- yield va.join(', ')
1120
- end
1121
- end
1122
-
1123
- # Removes a header field.
1124
- def delete(key)
1125
- @header.delete(key.downcase)
1126
- end
1127
-
1128
- # true if +key+ header exists.
1129
- def key?(key)
1130
- @header.key?(key.downcase)
1131
- end
1132
-
1133
- # Returns a Hash consist of header names and values.
1134
- def to_hash
1135
- @header.dup
1136
- end
1137
-
1138
- # As for #each_header, except the keys are provided in capitalized form.
1139
- def each_capitalized
1140
- @header.each do |k,v|
1141
- yield capitalize(k), v.join(', ')
1142
- end
1143
- end
1144
-
1145
- alias canonical_each each_capitalized
1146
-
1147
- def capitalize(name)
1148
- name.split(/-/).map {|s| s.capitalize }.join('-')
1149
- end
1150
- private :capitalize
1151
-
1152
- # Returns an Array of Range objects which represents Range: header field,
1153
- # or +nil+ if there is no such header.
1154
- def range
1155
- return nil unless @header['range']
1156
- self['Range'].split(/,/).map {|spec|
1157
- m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
1158
- raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
1159
- d1 = m[1].to_i
1160
- d2 = m[2].to_i
1161
- if m[1] and m[2] then d1..d2
1162
- elsif m[1] then d1..-1
1163
- elsif m[2] then -d2..-1
1164
- else
1165
- raise HTTPHeaderSyntaxError, 'range is not specified'
1166
- end
1167
- }
1168
- end
1169
-
1170
- # Set Range: header from Range (arg r) or beginning index and
1171
- # length from it (arg idx&len).
1172
- #
1173
- # req.range = (0..1023)
1174
- # req.set_range 0, 1023
1175
- #
1176
- def set_range(r, e = nil)
1177
- unless r
1178
- @header.delete 'range'
1179
- return r
1180
- end
1181
- r = (r...r+e) if e
1182
- case r
1183
- when Numeric
1184
- n = r.to_i
1185
- rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
1186
- when Range
1187
- first = r.first
1188
- last = r.last
1189
- last -= 1 if r.exclude_end?
1190
- if last == -1
1191
- rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
1192
- else
1193
- raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
1194
- raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
1195
- raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
1196
- rangestr = "#{first}-#{last}"
1197
- end
1198
- else
1199
- raise TypeError, 'Range/Integer is required'
1200
- end
1201
- @header['range'] = ["bytes=#{rangestr}"]
1202
- r
1203
- end
1204
-
1205
- alias range= set_range
1206
-
1207
- # Returns an Integer object which represents the Content-Length: header field
1208
- # or +nil+ if that field is not provided.
1209
- def content_length
1210
- return nil unless key?('Content-Length')
1211
- len = self['Content-Length'].slice(/\d+/) or
1212
- raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
1213
- len.to_i
1214
- end
1215
-
1216
- def content_length=(len)
1217
- unless len
1218
- @header.delete 'content-length'
1219
- return nil
1220
- end
1221
- @header['content-length'] = [len.to_i.to_s]
1222
- end
1223
-
1224
- # Returns "true" if the "transfer-encoding" header is present and
1225
- # set to "chunked". This is an HTTP/1.1 feature, allowing the
1226
- # the content to be sent in "chunks" without at the outset
1227
- # stating the entire content length.
1228
- def chunked?
1229
- return false unless @header['transfer-encoding']
1230
- field = self['Transfer-Encoding']
1231
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
1232
- end
1233
-
1234
- # Returns a Range object which represents Content-Range: header field.
1235
- # This indicates, for a partial entity body, where this fragment
1236
- # fits inside the full entity body, as range of byte offsets.
1237
- def content_range
1238
- return nil unless @header['content-range']
1239
- m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
1240
- raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
1241
- m[1].to_i .. m[2].to_i + 1
1242
- end
1243
-
1244
- # The length of the range represented in Content-Range: header.
1245
- def range_length
1246
- r = content_range() or return nil
1247
- r.end - r.begin
1248
- end
1249
-
1250
- def content_type
1251
- "#{main_type()}/#{sub_type()}"
1252
- end
1253
-
1254
- def main_type
1255
- return nil unless @header['content-type']
1256
- self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
1257
- end
1258
-
1259
- def sub_type
1260
- return nil unless @header['content-type']
1261
- self['Content-Type'].split(';').first.to_s.split('/')[1].to_s.strip
1262
- end
1263
-
1264
- def type_params
1265
- result = {}
1266
- self['Content-Type'].to_s.split(';')[1..-1].each do |param|
1267
- k, v = *param.split('=', 2)
1268
- result[k.strip] = v.strip
1269
- end
1270
- result
1271
- end
1272
-
1273
- def set_content_type(type, params = {})
1274
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
1275
- end
1276
-
1277
- alias content_type= set_content_type
1278
-
1279
- # Set the Authorization: header for "Basic" authorization.
1280
- def basic_auth(account, password)
1281
- @header['authorization'] = [basic_encode(account, password)]
1282
- end
1283
-
1284
- # Set Proxy-Authorization: header for "Basic" authorization.
1285
- def proxy_basic_auth(account, password)
1286
- @header['proxy-authorization'] = [basic_encode(account, password)]
1287
- end
1288
-
1289
- def basic_encode(account, password)
1290
- 'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n")
1291
- end
1292
- private :basic_encode
1293
-
1294
- end
1295
-
1296
-
1297
- #
1298
- # Parent of HTTPRequest class. Do not use this directly; use
1299
- # a subclass of HTTPRequest.
1300
- #
1301
- # Mixes in the HTTPHeader module.
1302
- #
1303
- class HTTPGenericRequest
1304
-
1305
- include HTTPHeader
1306
-
1307
- def initialize(m, reqbody, resbody, path, initheader = nil)
1308
- @method = m
1309
- @request_has_body = reqbody
1310
- @response_has_body = resbody
1311
- raise ArgumentError, "HTTP request path is empty" if path.empty?
1312
- @path = path
1313
- initialize_http_header initheader
1314
- self['Accept'] ||= '*/*'
1315
- @body = nil
1316
- @body_stream = nil
1317
- end
1318
-
1319
- attr_reader :method
1320
- attr_reader :path
1321
-
1322
- def inspect
1323
- "\#<#{self.class} #{@method}>"
1324
- end
1325
-
1326
- def request_body_permitted?
1327
- @request_has_body
1328
- end
1329
-
1330
- def response_body_permitted?
1331
- @response_has_body
1332
- end
1333
-
1334
- def body_exist?
1335
- warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE
1336
- response_body_permitted?
1337
- end
1338
-
1339
- attr_reader :body
1340
-
1341
- def body=(str)
1342
- @body = str
1343
- @body_stream = nil
1344
- str
1345
- end
1346
-
1347
- attr_reader :body_stream
1348
-
1349
- def body_stream=(input)
1350
- @body = nil
1351
- @body_stream = input
1352
- input
1353
- end
1354
-
1355
- def set_body_internal(str) #:nodoc: internal use only
1356
- raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
1357
- self.body = str if str
1358
- end
1359
-
1360
- #
1361
- # write
1362
- #
1363
-
1364
- def exec(sock, ver, path) #:nodoc: internal use only
1365
- if @body
1366
- send_request_with_body sock, ver, path, @body
1367
- elsif @body_stream
1368
- send_request_with_body_stream sock, ver, path, @body_stream
1369
- else
1370
- write_header sock, ver, path
1371
- end
1372
- end
1373
-
1374
- private
1375
-
1376
- def send_request_with_body(sock, ver, path, body)
1377
- self.content_length = body.length
1378
- delete 'Transfer-Encoding'
1379
- unless content_type()
1380
- warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
1381
- set_content_type 'application/x-www-form-urlencoded'
1382
- end
1383
- write_header sock, ver, path
1384
- sock.write body
1385
- end
1386
-
1387
- def send_request_with_body_stream(sock, ver, path, f)
1388
- raise ArgumentError, "Content-Length not given and Transfer-Encoding is not `chunked'" unless content_length() or chunked?
1389
- unless content_type()
1390
- warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
1391
- set_content_type 'application/x-www-form-urlencoded'
1392
- end
1393
- write_header sock, ver, path
1394
- if chunked?
1395
- while s = f.read(1024)
1396
- sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
1397
- end
1398
- sock.write "0\r\n\r\n"
1399
- else
1400
- while s = f.read(1024)
1401
- sock.write s
1402
- end
1403
- end
1404
- end
1405
-
1406
- def write_header(sock, ver, path)
1407
- buf = "#{@method} #{path} HTTP/#{ver}\r\n"
1408
- each_capitalized do |k,v|
1409
- buf << "#{k}: #{v}\r\n"
1410
- end
1411
- buf << "\r\n"
1412
- sock.write buf
1413
- end
1414
-
1415
- end
1416
-
1417
-
1418
- #
1419
- # HTTP request class. This class wraps request header and entity path.
1420
- # You *must* use its subclass, Net::HTTP::Get, Post, Head.
1421
- #
1422
- class HTTPRequest < HTTPGenericRequest
1423
-
1424
- # Creates HTTP request object.
1425
- def initialize(path, initheader = nil)
1426
- super self.class::METHOD,
1427
- self.class::REQUEST_HAS_BODY,
1428
- self.class::RESPONSE_HAS_BODY,
1429
- path, initheader
1430
- end
1431
- end
1432
-
1433
-
1434
- class HTTP
1435
- class Get < HTTPRequest
1436
- METHOD = 'GET'
1437
- REQUEST_HAS_BODY = false
1438
- RESPONSE_HAS_BODY = true
1439
- end
1440
-
1441
- class Head < HTTPRequest
1442
- METHOD = 'HEAD'
1443
- REQUEST_HAS_BODY = false
1444
- RESPONSE_HAS_BODY = false
1445
- end
1446
-
1447
- class Post < HTTPRequest
1448
- METHOD = 'POST'
1449
- REQUEST_HAS_BODY = true
1450
- RESPONSE_HAS_BODY = true
1451
- end
1452
-
1453
- class Put < HTTPRequest
1454
- METHOD = 'PUT'
1455
- REQUEST_HAS_BODY = true
1456
- RESPONSE_HAS_BODY = true
1457
- end
1458
-
1459
- class Proppatch < HTTPRequest
1460
- METHOD = 'PROPPATCH'
1461
- REQUEST_HAS_BODY = true
1462
- RESPONSE_HAS_BODY = true
1463
- end
1464
-
1465
- class Lock < HTTPRequest
1466
- METHOD = 'LOCK'
1467
- REQUEST_HAS_BODY = true
1468
- RESPONSE_HAS_BODY = true
1469
- end
1470
-
1471
- class Unlock < HTTPRequest
1472
- METHOD = 'UNLOCK'
1473
- REQUEST_HAS_BODY = true
1474
- RESPONSE_HAS_BODY = true
1475
- end
1476
-
1477
- class Options < HTTPRequest
1478
- METHOD = 'OPTIONS'
1479
- REQUEST_HAS_BODY = false
1480
- RESPONSE_HAS_BODY = false
1481
- end
1482
-
1483
- class Propfind < HTTPRequest
1484
- METHOD = 'PROPFIND'
1485
- REQUEST_HAS_BODY = true
1486
- RESPONSE_HAS_BODY = true
1487
- end
1488
-
1489
- class Delete < HTTPRequest
1490
- METHOD = 'DELETE'
1491
- REQUEST_HAS_BODY = false
1492
- RESPONSE_HAS_BODY = true
1493
- end
1494
-
1495
- class Move < HTTPRequest
1496
- METHOD = 'MOVE'
1497
- REQUEST_HAS_BODY = false
1498
- RESPONSE_HAS_BODY = true
1499
- end
1500
-
1501
- class Copy < HTTPRequest
1502
- METHOD = 'COPY'
1503
- REQUEST_HAS_BODY = false
1504
- RESPONSE_HAS_BODY = true
1505
- end
1506
-
1507
- class Mkcol < HTTPRequest
1508
- METHOD = 'MKCOL'
1509
- REQUEST_HAS_BODY = true
1510
- RESPONSE_HAS_BODY = true
1511
- end
1512
-
1513
- class Trace < HTTPRequest
1514
- METHOD = 'TRACE'
1515
- REQUEST_HAS_BODY = false
1516
- RESPONSE_HAS_BODY = true
1517
- end
1518
- end
1519
-
1520
-
1521
- ###
1522
- ### Response
1523
- ###
1524
-
1525
- # HTTP exception class.
1526
- # You must use its subclasses.
1527
- module HTTPExceptions
1528
- def initialize(msg, res) #:nodoc:
1529
- super msg
1530
- @response = res
1531
- end
1532
- attr_reader :response
1533
- alias data response #:nodoc: obsolete
1534
- end
1535
- class HTTPError < ProtocolError
1536
- include HTTPExceptions
1537
- end
1538
- class HTTPRetriableError < ProtoRetriableError
1539
- include HTTPExceptions
1540
- end
1541
- class HTTPServerException < ProtoServerError
1542
- # We cannot use the name "HTTPServerError", it is the name of the response.
1543
- include HTTPExceptions
1544
- end
1545
- class HTTPFatalError < ProtoFatalError
1546
- include HTTPExceptions
1547
- end
1548
-
1549
-
1550
- # HTTP response class. This class wraps response header and entity.
1551
- # Mixes in the HTTPHeader module, which provides access to response
1552
- # header values both via hash-like methods and individual readers.
1553
- # Note that each possible HTTP response code defines its own
1554
- # HTTPResponse subclass. These are listed below.
1555
- # All classes are
1556
- # defined under the Net module. Indentation indicates inheritance.
1557
- #
1558
- # xxx HTTPResponse
1559
- #
1560
- # 1xx HTTPInformation
1561
- # 100 HTTPContinue
1562
- # 101 HTTPSwitchProtocol
1563
- #
1564
- # 2xx HTTPSuccess
1565
- # 200 HTTPOK
1566
- # 201 HTTPCreated
1567
- # 202 HTTPAccepted
1568
- # 203 HTTPNonAuthoritativeInformation
1569
- # 204 HTTPNoContent
1570
- # 205 HTTPResetContent
1571
- # 206 HTTPPartialContent
1572
- #
1573
- # 3xx HTTPRedirection
1574
- # 300 HTTPMultipleChoice
1575
- # 301 HTTPMovedPermanently
1576
- # 302 HTTPFound
1577
- # 303 HTTPSeeOther
1578
- # 304 HTTPNotModified
1579
- # 305 HTTPUseProxy
1580
- # 307 HTTPTemporaryRedirect
1581
- #
1582
- # 4xx HTTPClientError
1583
- # 400 HTTPBadRequest
1584
- # 401 HTTPUnauthorized
1585
- # 402 HTTPPaymentRequired
1586
- # 403 HTTPForbidden
1587
- # 404 HTTPNotFound
1588
- # 405 HTTPMethodNotAllowed
1589
- # 406 HTTPNotAcceptable
1590
- # 407 HTTPProxyAuthenticationRequired
1591
- # 408 HTTPRequestTimeOut
1592
- # 409 HTTPConflict
1593
- # 410 HTTPGone
1594
- # 411 HTTPLengthRequired
1595
- # 412 HTTPPreconditionFailed
1596
- # 413 HTTPRequestEntityTooLarge
1597
- # 414 HTTPRequestURITooLong
1598
- # 415 HTTPUnsupportedMediaType
1599
- # 416 HTTPRequestedRangeNotSatisfiable
1600
- # 417 HTTPExpectationFailed
1601
- #
1602
- # 5xx HTTPServerError
1603
- # 500 HTTPInternalServerError
1604
- # 501 HTTPNotImplemented
1605
- # 502 HTTPBadGateway
1606
- # 503 HTTPServiceUnavailable
1607
- # 504 HTTPGatewayTimeOut
1608
- # 505 HTTPVersionNotSupported
1609
- #
1610
- # xxx HTTPUnknownResponse
1611
- #
1612
- class HTTPResponse
1613
- # true if the response has body.
1614
- def HTTPResponse.body_permitted?
1615
- self::HAS_BODY
1616
- end
1617
-
1618
- def HTTPResponse.exception_type # :nodoc: internal use only
1619
- self::EXCEPTION_TYPE
1620
- end
1621
- end # redefined after
1622
-
1623
- # :stopdoc:
1624
-
1625
- class HTTPUnknownResponse < HTTPResponse
1626
- HAS_BODY = true
1627
- EXCEPTION_TYPE = HTTPError
1628
- end
1629
- class HTTPInformation < HTTPResponse # 1xx
1630
- HAS_BODY = false
1631
- EXCEPTION_TYPE = HTTPError
1632
- end
1633
- class HTTPSuccess < HTTPResponse # 2xx
1634
- HAS_BODY = true
1635
- EXCEPTION_TYPE = HTTPError
1636
- end
1637
- class HTTPRedirection < HTTPResponse # 3xx
1638
- HAS_BODY = true
1639
- EXCEPTION_TYPE = HTTPRetriableError
1640
- end
1641
- class HTTPClientError < HTTPResponse # 4xx
1642
- HAS_BODY = true
1643
- EXCEPTION_TYPE = HTTPServerException # for backward compatibility
1644
- end
1645
- class HTTPServerError < HTTPResponse # 5xx
1646
- HAS_BODY = true
1647
- EXCEPTION_TYPE = HTTPFatalError # for backward compatibility
1648
- end
1649
-
1650
- class HTTPContinue < HTTPInformation # 100
1651
- HAS_BODY = false
1652
- end
1653
- class HTTPSwitchProtocol < HTTPInformation # 101
1654
- HAS_BODY = false
1655
- end
1656
-
1657
- class HTTPOK < HTTPSuccess # 200
1658
- HAS_BODY = true
1659
- end
1660
- class HTTPCreated < HTTPSuccess # 201
1661
- HAS_BODY = true
1662
- end
1663
- class HTTPAccepted < HTTPSuccess # 202
1664
- HAS_BODY = true
1665
- end
1666
- class HTTPNonAuthoritativeInformation < HTTPSuccess # 203
1667
- HAS_BODY = true
1668
- end
1669
- class HTTPNoContent < HTTPSuccess # 204
1670
- HAS_BODY = false
1671
- end
1672
- class HTTPResetContent < HTTPSuccess # 205
1673
- HAS_BODY = false
1674
- end
1675
- class HTTPPartialContent < HTTPSuccess # 206
1676
- HAS_BODY = true
1677
- end
1678
-
1679
- class HTTPMultipleChoice < HTTPRedirection # 300
1680
- HAS_BODY = true
1681
- end
1682
- class HTTPMovedPermanently < HTTPRedirection # 301
1683
- HAS_BODY = true
1684
- end
1685
- class HTTPFound < HTTPRedirection # 302
1686
- HAS_BODY = true
1687
- end
1688
- HTTPMovedTemporarily = HTTPFound
1689
- class HTTPSeeOther < HTTPRedirection # 303
1690
- HAS_BODY = true
1691
- end
1692
- class HTTPNotModified < HTTPRedirection # 304
1693
- HAS_BODY = false
1694
- end
1695
- class HTTPUseProxy < HTTPRedirection # 305
1696
- HAS_BODY = false
1697
- end
1698
- # 306 unused
1699
- class HTTPTemporaryRedirect < HTTPRedirection # 307
1700
- HAS_BODY = true
1701
- end
1702
-
1703
- class HTTPBadRequest < HTTPClientError # 400
1704
- HAS_BODY = true
1705
- end
1706
- class HTTPUnauthorized < HTTPClientError # 401
1707
- HAS_BODY = true
1708
- end
1709
- class HTTPPaymentRequired < HTTPClientError # 402
1710
- HAS_BODY = true
1711
- end
1712
- class HTTPForbidden < HTTPClientError # 403
1713
- HAS_BODY = true
1714
- end
1715
- class HTTPNotFound < HTTPClientError # 404
1716
- HAS_BODY = true
1717
- end
1718
- class HTTPMethodNotAllowed < HTTPClientError # 405
1719
- HAS_BODY = true
1720
- end
1721
- class HTTPNotAcceptable < HTTPClientError # 406
1722
- HAS_BODY = true
1723
- end
1724
- class HTTPProxyAuthenticationRequired < HTTPClientError # 407
1725
- HAS_BODY = true
1726
- end
1727
- class HTTPRequestTimeOut < HTTPClientError # 408
1728
- HAS_BODY = true
1729
- end
1730
- class HTTPConflict < HTTPClientError # 409
1731
- HAS_BODY = true
1732
- end
1733
- class HTTPGone < HTTPClientError # 410
1734
- HAS_BODY = true
1735
- end
1736
- class HTTPLengthRequired < HTTPClientError # 411
1737
- HAS_BODY = true
1738
- end
1739
- class HTTPPreconditionFailed < HTTPClientError # 412
1740
- HAS_BODY = true
1741
- end
1742
- class HTTPRequestEntityTooLarge < HTTPClientError # 413
1743
- HAS_BODY = true
1744
- end
1745
- class HTTPRequestURITooLong < HTTPClientError # 414
1746
- HAS_BODY = true
1747
- end
1748
- HTTPRequestURITooLarge = HTTPRequestURITooLong
1749
- class HTTPUnsupportedMediaType < HTTPClientError # 415
1750
- HAS_BODY = true
1751
- end
1752
- class HTTPRequestedRangeNotSatisfiable < HTTPClientError # 416
1753
- HAS_BODY = true
1754
- end
1755
- class HTTPExpectationFailed < HTTPClientError # 417
1756
- HAS_BODY = true
1757
- end
1758
-
1759
- class HTTPInternalServerError < HTTPServerError # 500
1760
- HAS_BODY = true
1761
- end
1762
- class HTTPNotImplemented < HTTPServerError # 501
1763
- HAS_BODY = true
1764
- end
1765
- class HTTPBadGateway < HTTPServerError # 502
1766
- HAS_BODY = true
1767
- end
1768
- class HTTPServiceUnavailable < HTTPServerError # 503
1769
- HAS_BODY = true
1770
- end
1771
- class HTTPGatewayTimeOut < HTTPServerError # 504
1772
- HAS_BODY = true
1773
- end
1774
- class HTTPVersionNotSupported < HTTPServerError # 505
1775
- HAS_BODY = true
1776
- end
1777
-
1778
- # :startdoc:
1779
-
1780
-
1781
- class HTTPResponse # redefine
1782
-
1783
- CODE_CLASS_TO_OBJ = {
1784
- '1' => HTTPInformation,
1785
- '2' => HTTPSuccess,
1786
- '3' => HTTPRedirection,
1787
- '4' => HTTPClientError,
1788
- '5' => HTTPServerError
1789
- }
1790
- CODE_TO_OBJ = {
1791
- '100' => HTTPContinue,
1792
- '101' => HTTPSwitchProtocol,
1793
-
1794
- '200' => HTTPOK,
1795
- '201' => HTTPCreated,
1796
- '202' => HTTPAccepted,
1797
- '203' => HTTPNonAuthoritativeInformation,
1798
- '204' => HTTPNoContent,
1799
- '205' => HTTPResetContent,
1800
- '206' => HTTPPartialContent,
1801
-
1802
- '300' => HTTPMultipleChoice,
1803
- '301' => HTTPMovedPermanently,
1804
- '302' => HTTPFound,
1805
- '303' => HTTPSeeOther,
1806
- '304' => HTTPNotModified,
1807
- '305' => HTTPUseProxy,
1808
- '307' => HTTPTemporaryRedirect,
1809
-
1810
- '400' => HTTPBadRequest,
1811
- '401' => HTTPUnauthorized,
1812
- '402' => HTTPPaymentRequired,
1813
- '403' => HTTPForbidden,
1814
- '404' => HTTPNotFound,
1815
- '405' => HTTPMethodNotAllowed,
1816
- '406' => HTTPNotAcceptable,
1817
- '407' => HTTPProxyAuthenticationRequired,
1818
- '408' => HTTPRequestTimeOut,
1819
- '409' => HTTPConflict,
1820
- '410' => HTTPGone,
1821
- '411' => HTTPLengthRequired,
1822
- '412' => HTTPPreconditionFailed,
1823
- '413' => HTTPRequestEntityTooLarge,
1824
- '414' => HTTPRequestURITooLong,
1825
- '415' => HTTPUnsupportedMediaType,
1826
- '416' => HTTPRequestedRangeNotSatisfiable,
1827
- '417' => HTTPExpectationFailed,
1828
-
1829
- '500' => HTTPInternalServerError,
1830
- '501' => HTTPNotImplemented,
1831
- '502' => HTTPBadGateway,
1832
- '503' => HTTPServiceUnavailable,
1833
- '504' => HTTPGatewayTimeOut,
1834
- '505' => HTTPVersionNotSupported
1835
- }
1836
-
1837
- class << HTTPResponse
1838
- def read_new(sock) #:nodoc: internal use only
1839
- httpv, code, msg = read_status_line(sock)
1840
- res = response_class(code).new(httpv, code, msg)
1841
- each_response_header(sock) do |k,v|
1842
- res.add_field k, v
1843
- end
1844
- res
1845
- end
1846
-
1847
- private
1848
-
1849
- def read_status_line(sock)
1850
- str = sock.readline
1851
- m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or
1852
- raise HTTPBadResponse, "wrong status line: #{str.dump}"
1853
- m.captures
1854
- end
1855
-
1856
- def response_class(code)
1857
- CODE_TO_OBJ[code] or
1858
- CODE_CLASS_TO_OBJ[code[0,1]] or
1859
- HTTPUnknownResponse
1860
- end
1861
-
1862
- def each_response_header(sock)
1863
- while true
1864
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
1865
- break if line.empty?
1866
- m = /\A([^:]+):\s*/.match(line) or
1867
- raise HTTPBadResponse, 'wrong header line format'
1868
- yield m[1], m.post_match
1869
- end
1870
- end
1871
- end
1872
-
1873
- # next is to fix bug in RDoc, where the private inside class << self
1874
- # spills out.
1875
- public
1876
-
1877
- include HTTPHeader
1878
-
1879
- def initialize(httpv, code, msg) #:nodoc: internal use only
1880
- @http_version = httpv
1881
- @code = code
1882
- @message = msg
1883
- initialize_http_header nil
1884
- @body = nil
1885
- @read = false
1886
- end
1887
-
1888
- # The HTTP version supported by the server.
1889
- attr_reader :http_version
1890
-
1891
- # HTTP result code string. For example, '302'. You can also
1892
- # determine the response type by which response subclass the
1893
- # response object is an instance of.
1894
- attr_reader :code
1895
-
1896
- # HTTP result message. For example, 'Not Found'.
1897
- attr_reader :message
1898
- alias msg message # :nodoc: obsolete
1899
-
1900
- def inspect
1901
- "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
1902
- end
1903
-
1904
- # For backward compatibility.
1905
- # To allow Net::HTTP 1.1 style assignment
1906
- # e.g.
1907
- # response, body = Net::HTTP.get(....)
1908
- #
1909
- def to_ary
1910
- warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE
1911
- res = self.dup
1912
- class << res
1913
- undef to_ary
1914
- end
1915
- [res, res.body]
1916
- end
1917
-
1918
- #
1919
- # response <-> exception relationship
1920
- #
1921
-
1922
- def code_type #:nodoc:
1923
- self.class
1924
- end
1925
-
1926
- def error! #:nodoc:
1927
- raise error_type().new(@code + ' ' + @message.dump, self)
1928
- end
1929
-
1930
- def error_type #:nodoc:
1931
- self.class::EXCEPTION_TYPE
1932
- end
1933
-
1934
- # Raises HTTP error if the response is not 2xx.
1935
- def value
1936
- error! unless self.kind_of?(HTTPSuccess)
1937
- end
1938
-
1939
- #
1940
- # header (for backward compatibility only; DO NOT USE)
1941
- #
1942
-
1943
- def response #:nodoc:
1944
- warn "#{caller(1)[0]}: warning: HTTPResponse#response is obsolete" if $VERBOSE
1945
- self
1946
- end
1947
-
1948
- def header #:nodoc:
1949
- warn "#{caller(1)[0]}: warning: HTTPResponse#header is obsolete" if $VERBOSE
1950
- self
1951
- end
1952
-
1953
- def read_header #:nodoc:
1954
- warn "#{caller(1)[0]}: warning: HTTPResponse#read_header is obsolete" if $VERBOSE
1955
- self
1956
- end
1957
-
1958
- #
1959
- # body
1960
- #
1961
-
1962
- def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only
1963
- @socket = sock
1964
- @body_exist = reqmethodallowbody && self.class.body_permitted?
1965
- begin
1966
- yield
1967
- self.body # ensure to read body
1968
- ensure
1969
- @socket = nil
1970
- end
1971
- end
1972
-
1973
- # Gets entity body. If the block given, yields it to +block+.
1974
- # The body is provided in fragments, as it is read in from the socket.
1975
- #
1976
- # Calling this method a second or subsequent time will return the
1977
- # already read string.
1978
- #
1979
- # http.request_get('/index.html') {|res|
1980
- # puts res.read_body
1981
- # }
1982
- #
1983
- # http.request_get('/index.html') {|res|
1984
- # p res.read_body.object_id # 538149362
1985
- # p res.read_body.object_id # 538149362
1986
- # }
1987
- #
1988
- # # using iterator
1989
- # http.request_get('/index.html') {|res|
1990
- # res.read_body do |segment|
1991
- # print segment
1992
- # end
1993
- # }
1994
- #
1995
- def read_body(dest = nil, &block)
1996
- if @read
1997
- raise IOError, "#{self.class}\#read_body called twice" if dest or block
1998
- return @body
1999
- end
2000
- to = procdest(dest, block)
2001
- stream_check
2002
- if @body_exist
2003
- read_body_0 to
2004
- @body = to
2005
- else
2006
- @body = nil
2007
- end
2008
- @read = true
2009
-
2010
- @body
2011
- end
2012
-
2013
- # Returns the entity body.
2014
- #
2015
- # Calling this method a second or subsequent time will return the
2016
- # already read string.
2017
- #
2018
- # http.request_get('/index.html') {|res|
2019
- # puts res.body
2020
- # }
2021
- #
2022
- # http.request_get('/index.html') {|res|
2023
- # p res.body.object_id # 538149362
2024
- # p res.body.object_id # 538149362
2025
- # }
2026
- #
2027
- def body
2028
- read_body()
2029
- end
2030
-
2031
- alias entity body #:nodoc: obsolete
2032
-
2033
- private
2034
-
2035
- def read_body_0(dest)
2036
- if chunked?
2037
- read_chunked dest
2038
- return
2039
- end
2040
- clen = content_length()
2041
- if clen
2042
- @socket.read clen, dest, true # ignore EOF
2043
- return
2044
- end
2045
- clen = range_length()
2046
- if clen
2047
- @socket.read clen, dest
2048
- return
2049
- end
2050
- @socket.read_all dest
2051
- end
2052
-
2053
- def read_chunked(dest)
2054
- len = nil
2055
- total = 0
2056
- while true
2057
- line = @socket.readline
2058
- hexlen = line.slice(/[0-9a-fA-F]+/) or
2059
- raise HTTPBadResponse, "wrong chunk size line: #{line}"
2060
- len = hexlen.hex
2061
- break if len == 0
2062
- @socket.read len, dest; total += len
2063
- @socket.read 2 # \r\n
2064
- end
2065
- until @socket.readline.empty?
2066
- # none
2067
- end
2068
- end
2069
-
2070
- def stream_check
2071
- raise IOError, 'attempt to read body out of block' if @socket.closed?
2072
- end
2073
-
2074
- def procdest(dest, block)
2075
- raise ArgumentError, 'both arg and block given for HTTP method' \
2076
- if dest and block
2077
- if block
2078
- ReadAdapter.new(block)
2079
- else
2080
- dest || ''
2081
- end
2082
- end
2083
-
2084
- end
2085
-
2086
-
2087
- # :enddoc:
2088
-
2089
- #--
2090
- # for backward compatibility
2091
- class HTTP
2092
- ProxyMod = ProxyDelta
2093
- end
2094
- module NetPrivate
2095
- HTTPRequest = ::Net::HTTPRequest
2096
- end
2097
-
2098
- HTTPInformationCode = HTTPInformation
2099
- HTTPSuccessCode = HTTPSuccess
2100
- HTTPRedirectionCode = HTTPRedirection
2101
- HTTPRetriableCode = HTTPRedirection
2102
- HTTPClientErrorCode = HTTPClientError
2103
- HTTPFatalErrorCode = HTTPClientError
2104
- HTTPServerErrorCode = HTTPServerError
2105
- HTTPResponceReceiver = HTTPResponse
2106
-
2107
- end # module Net