rubysl-net-http 1.0.1 → 2.0.4

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.
@@ -0,0 +1,268 @@
1
+ # :stopdoc:
2
+ class Net::HTTPUnknownResponse < Net::HTTPResponse
3
+ HAS_BODY = true
4
+ EXCEPTION_TYPE = Net::HTTPError
5
+ end
6
+ class Net::HTTPInformation < Net::HTTPResponse # 1xx
7
+ HAS_BODY = false
8
+ EXCEPTION_TYPE = Net::HTTPError
9
+ end
10
+ class Net::HTTPSuccess < Net::HTTPResponse # 2xx
11
+ HAS_BODY = true
12
+ EXCEPTION_TYPE = Net::HTTPError
13
+ end
14
+ class Net::HTTPRedirection < Net::HTTPResponse # 3xx
15
+ HAS_BODY = true
16
+ EXCEPTION_TYPE = Net::HTTPRetriableError
17
+ end
18
+ class Net::HTTPClientError < Net::HTTPResponse # 4xx
19
+ HAS_BODY = true
20
+ EXCEPTION_TYPE = Net::HTTPServerException # for backward compatibility
21
+ end
22
+ class Net::HTTPServerError < Net::HTTPResponse # 5xx
23
+ HAS_BODY = true
24
+ EXCEPTION_TYPE = Net::HTTPFatalError # for backward compatibility
25
+ end
26
+
27
+ class Net::HTTPContinue < Net::HTTPInformation # 100
28
+ HAS_BODY = false
29
+ end
30
+ class Net::HTTPSwitchProtocol < Net::HTTPInformation # 101
31
+ HAS_BODY = false
32
+ end
33
+ # 102 - RFC 2518; removed in RFC 4918
34
+
35
+ class Net::HTTPOK < Net::HTTPSuccess # 200
36
+ HAS_BODY = true
37
+ end
38
+ class Net::HTTPCreated < Net::HTTPSuccess # 201
39
+ HAS_BODY = true
40
+ end
41
+ class Net::HTTPAccepted < Net::HTTPSuccess # 202
42
+ HAS_BODY = true
43
+ end
44
+ class Net::HTTPNonAuthoritativeInformation < Net::HTTPSuccess # 203
45
+ HAS_BODY = true
46
+ end
47
+ class Net::HTTPNoContent < Net::HTTPSuccess # 204
48
+ HAS_BODY = false
49
+ end
50
+ class Net::HTTPResetContent < Net::HTTPSuccess # 205
51
+ HAS_BODY = false
52
+ end
53
+ class Net::HTTPPartialContent < Net::HTTPSuccess # 206
54
+ HAS_BODY = true
55
+ end
56
+ class Net::HTTPMultiStatus < Net::HTTPSuccess # 207 - RFC 4918
57
+ HAS_BODY = true
58
+ end
59
+ # 208 Already Reported - RFC 5842; experimental
60
+ # 226 IM Used - RFC 3229; no famous implementation known
61
+
62
+ class Net::HTTPMultipleChoices < Net::HTTPRedirection # 300
63
+ HAS_BODY = true
64
+ end
65
+ Net::HTTPMultipleChoice = Net::HTTPMultipleChoices
66
+ class Net::HTTPMovedPermanently < Net::HTTPRedirection # 301
67
+ HAS_BODY = true
68
+ end
69
+ class Net::HTTPFound < Net::HTTPRedirection # 302
70
+ HAS_BODY = true
71
+ end
72
+ Net::HTTPMovedTemporarily = Net::HTTPFound
73
+ class Net::HTTPSeeOther < Net::HTTPRedirection # 303
74
+ HAS_BODY = true
75
+ end
76
+ class Net::HTTPNotModified < Net::HTTPRedirection # 304
77
+ HAS_BODY = false
78
+ end
79
+ class Net::HTTPUseProxy < Net::HTTPRedirection # 305
80
+ HAS_BODY = false
81
+ end
82
+ # 306 Switch Proxy - no longer unused
83
+ class Net::HTTPTemporaryRedirect < Net::HTTPRedirection # 307
84
+ HAS_BODY = true
85
+ end
86
+ # 308 Permanent Redirect - in draft
87
+
88
+ class Net::HTTPBadRequest < Net::HTTPClientError # 400
89
+ HAS_BODY = true
90
+ end
91
+ class Net::HTTPUnauthorized < Net::HTTPClientError # 401
92
+ HAS_BODY = true
93
+ end
94
+ class Net::HTTPPaymentRequired < Net::HTTPClientError # 402
95
+ HAS_BODY = true
96
+ end
97
+ class Net::HTTPForbidden < Net::HTTPClientError # 403
98
+ HAS_BODY = true
99
+ end
100
+ class Net::HTTPNotFound < Net::HTTPClientError # 404
101
+ HAS_BODY = true
102
+ end
103
+ class Net::HTTPMethodNotAllowed < Net::HTTPClientError # 405
104
+ HAS_BODY = true
105
+ end
106
+ class Net::HTTPNotAcceptable < Net::HTTPClientError # 406
107
+ HAS_BODY = true
108
+ end
109
+ class Net::HTTPProxyAuthenticationRequired < Net::HTTPClientError # 407
110
+ HAS_BODY = true
111
+ end
112
+ class Net::HTTPRequestTimeOut < Net::HTTPClientError # 408
113
+ HAS_BODY = true
114
+ end
115
+ class Net::HTTPConflict < Net::HTTPClientError # 409
116
+ HAS_BODY = true
117
+ end
118
+ class Net::HTTPGone < Net::HTTPClientError # 410
119
+ HAS_BODY = true
120
+ end
121
+ class Net::HTTPLengthRequired < Net::HTTPClientError # 411
122
+ HAS_BODY = true
123
+ end
124
+ class Net::HTTPPreconditionFailed < Net::HTTPClientError # 412
125
+ HAS_BODY = true
126
+ end
127
+ class Net::HTTPRequestEntityTooLarge < Net::HTTPClientError # 413
128
+ HAS_BODY = true
129
+ end
130
+ class Net::HTTPRequestURITooLong < Net::HTTPClientError # 414
131
+ HAS_BODY = true
132
+ end
133
+ Net::HTTPRequestURITooLarge = Net::HTTPRequestURITooLong
134
+ class Net::HTTPUnsupportedMediaType < Net::HTTPClientError # 415
135
+ HAS_BODY = true
136
+ end
137
+ class Net::HTTPRequestedRangeNotSatisfiable < Net::HTTPClientError # 416
138
+ HAS_BODY = true
139
+ end
140
+ class Net::HTTPExpectationFailed < Net::HTTPClientError # 417
141
+ HAS_BODY = true
142
+ end
143
+ # 418 I'm a teapot - RFC 2324; a joke RFC
144
+ # 420 Enhance Your Calm - Twitter
145
+ class Net::HTTPUnprocessableEntity < Net::HTTPClientError # 422 - RFC 4918
146
+ HAS_BODY = true
147
+ end
148
+ class Net::HTTPLocked < Net::HTTPClientError # 423 - RFC 4918
149
+ HAS_BODY = true
150
+ end
151
+ class Net::HTTPFailedDependency < Net::HTTPClientError # 424 - RFC 4918
152
+ HAS_BODY = true
153
+ end
154
+ # 425 Unordered Collection - existed only in draft
155
+ class Net::HTTPUpgradeRequired < Net::HTTPClientError # 426 - RFC 2817
156
+ HAS_BODY = true
157
+ end
158
+ class Net::HTTPPreconditionRequired < Net::HTTPClientError # 428 - RFC 6585
159
+ HAS_BODY = true
160
+ end
161
+ class Net::HTTPTooManyRequests < Net::HTTPClientError # 429 - RFC 6585
162
+ HAS_BODY = true
163
+ end
164
+ class Net::HTTPRequestHeaderFieldsTooLarge < Net::HTTPClientError # 431 - RFC 6585
165
+ HAS_BODY = true
166
+ end
167
+ # 444 No Response - Nginx
168
+ # 449 Retry With - Microsoft
169
+ # 450 Blocked by Windows Parental Controls - Microsoft
170
+ # 499 Client Closed Request - Nginx
171
+
172
+ class Net::HTTPInternalServerError < Net::HTTPServerError # 500
173
+ HAS_BODY = true
174
+ end
175
+ class Net::HTTPNotImplemented < Net::HTTPServerError # 501
176
+ HAS_BODY = true
177
+ end
178
+ class Net::HTTPBadGateway < Net::HTTPServerError # 502
179
+ HAS_BODY = true
180
+ end
181
+ class Net::HTTPServiceUnavailable < Net::HTTPServerError # 503
182
+ HAS_BODY = true
183
+ end
184
+ class Net::HTTPGatewayTimeOut < Net::HTTPServerError # 504
185
+ HAS_BODY = true
186
+ end
187
+ class Net::HTTPVersionNotSupported < Net::HTTPServerError # 505
188
+ HAS_BODY = true
189
+ end
190
+ # 506 Variant Also Negotiates - RFC 2295; experimental
191
+ class Net::HTTPInsufficientStorage < Net::HTTPServerError # 507 - RFC 4918
192
+ HAS_BODY = true
193
+ end
194
+ # 508 Loop Detected - RFC 5842; experimental
195
+ # 509 Bandwidth Limit Exceeded - Apache bw/limited extension
196
+ # 510 Not Extended - RFC 2774; experimental
197
+ class Net::HTTPNetworkAuthenticationRequired < Net::HTTPServerError # 511 - RFC 6585
198
+ HAS_BODY = true
199
+ end
200
+
201
+ class Net::HTTPResponse
202
+ CODE_CLASS_TO_OBJ = {
203
+ '1' => Net::HTTPInformation,
204
+ '2' => Net::HTTPSuccess,
205
+ '3' => Net::HTTPRedirection,
206
+ '4' => Net::HTTPClientError,
207
+ '5' => Net::HTTPServerError
208
+ }
209
+ CODE_TO_OBJ = {
210
+ '100' => Net::HTTPContinue,
211
+ '101' => Net::HTTPSwitchProtocol,
212
+
213
+ '200' => Net::HTTPOK,
214
+ '201' => Net::HTTPCreated,
215
+ '202' => Net::HTTPAccepted,
216
+ '203' => Net::HTTPNonAuthoritativeInformation,
217
+ '204' => Net::HTTPNoContent,
218
+ '205' => Net::HTTPResetContent,
219
+ '206' => Net::HTTPPartialContent,
220
+ '207' => Net::HTTPMultiStatus,
221
+
222
+ '300' => Net::HTTPMultipleChoices,
223
+ '301' => Net::HTTPMovedPermanently,
224
+ '302' => Net::HTTPFound,
225
+ '303' => Net::HTTPSeeOther,
226
+ '304' => Net::HTTPNotModified,
227
+ '305' => Net::HTTPUseProxy,
228
+ '307' => Net::HTTPTemporaryRedirect,
229
+
230
+ '400' => Net::HTTPBadRequest,
231
+ '401' => Net::HTTPUnauthorized,
232
+ '402' => Net::HTTPPaymentRequired,
233
+ '403' => Net::HTTPForbidden,
234
+ '404' => Net::HTTPNotFound,
235
+ '405' => Net::HTTPMethodNotAllowed,
236
+ '406' => Net::HTTPNotAcceptable,
237
+ '407' => Net::HTTPProxyAuthenticationRequired,
238
+ '408' => Net::HTTPRequestTimeOut,
239
+ '409' => Net::HTTPConflict,
240
+ '410' => Net::HTTPGone,
241
+ '411' => Net::HTTPLengthRequired,
242
+ '412' => Net::HTTPPreconditionFailed,
243
+ '413' => Net::HTTPRequestEntityTooLarge,
244
+ '414' => Net::HTTPRequestURITooLong,
245
+ '415' => Net::HTTPUnsupportedMediaType,
246
+ '416' => Net::HTTPRequestedRangeNotSatisfiable,
247
+ '417' => Net::HTTPExpectationFailed,
248
+ '422' => Net::HTTPUnprocessableEntity,
249
+ '423' => Net::HTTPLocked,
250
+ '424' => Net::HTTPFailedDependency,
251
+ '426' => Net::HTTPUpgradeRequired,
252
+ '428' => Net::HTTPPreconditionRequired,
253
+ '429' => Net::HTTPTooManyRequests,
254
+ '431' => Net::HTTPRequestHeaderFieldsTooLarge,
255
+
256
+ '500' => Net::HTTPInternalServerError,
257
+ '501' => Net::HTTPNotImplemented,
258
+ '502' => Net::HTTPBadGateway,
259
+ '503' => Net::HTTPServiceUnavailable,
260
+ '504' => Net::HTTPGatewayTimeOut,
261
+ '505' => Net::HTTPVersionNotSupported,
262
+ '507' => Net::HTTPInsufficientStorage,
263
+ '511' => Net::HTTPNetworkAuthenticationRequired,
264
+ }
265
+ end
266
+
267
+ # :startdoc:
268
+
@@ -1,8 +1,8 @@
1
1
  #
2
2
  # = net/http.rb
3
3
  #
4
- # Copyright (c) 1999-2006 Yukihiro Matsumoto
5
- # Copyright (c) 1999-2006 Minero Aoki
4
+ # Copyright (c) 1999-2007 Yukihiro Matsumoto
5
+ # Copyright (c) 1999-2007 Minero Aoki
6
6
  # Copyright (c) 2001 GOTOU Yuuzou
7
7
  #
8
8
  # Written and maintained by Minero Aoki <aamine@loveruby.net>.
@@ -18,299 +18,397 @@
18
18
  #
19
19
  # See Net::HTTP for an overview and examples.
20
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$
26
- #++
27
21
 
28
22
  require 'net/protocol'
29
23
  require 'uri'
30
24
 
31
25
  module Net #:nodoc:
26
+ autoload :OpenSSL, 'openssl'
32
27
 
33
28
  # :stopdoc:
34
29
  class HTTPBadResponse < StandardError; end
35
30
  class HTTPHeaderSyntaxError < StandardError; end
36
31
  # :startdoc:
37
32
 
38
- # == What Is This Library?
33
+ # == An HTTP client API for Ruby.
39
34
  #
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).
35
+ # Net::HTTP provides a rich library which can be used to build HTTP
36
+ # user-agents. For more details about HTTP see
37
+ # [RFC2616](http://www.ietf.org/rfc/rfc2616.txt)
44
38
  #
45
- # == Examples
39
+ # Net::HTTP is designed to work closely with URI. URI::HTTP#host,
40
+ # URI::HTTP#port and URI::HTTP#request_uri are designed to work with
41
+ # Net::HTTP.
46
42
  #
47
- # === Getting Document From WWW Server
43
+ # If you are only performing a few GET requests you should try OpenURI.
48
44
  #
49
- # Example #1: Simple GET+print
45
+ # == Simple Examples
50
46
  #
51
- # require 'net/http'
52
- # Net::HTTP.get_print 'www.example.com', '/index.html'
47
+ # All examples assume you have loaded Net::HTTP with:
53
48
  #
54
- # Example #2: Simple GET+print by URL
49
+ # require 'net/http'
55
50
  #
56
- # require 'net/http'
57
- # require 'uri'
58
- # Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
51
+ # This will also require 'uri' so you don't need to require it separately.
59
52
  #
60
- # Example #3: More generic GET+print
53
+ # The Net::HTTP methods in the following section do not persist
54
+ # connections. They are not recommended if you are performing many HTTP
55
+ # requests.
61
56
  #
62
- # require 'net/http'
63
- # require 'uri'
57
+ # === GET
64
58
  #
65
- # url = URI.parse('http://www.example.com/index.html')
66
- # res = Net::HTTP.start(url.host, url.port) {|http|
67
- # http.get('/index.html')
68
- # }
69
- # puts res.body
59
+ # Net::HTTP.get('example.com', '/index.html') # => String
70
60
  #
71
- # Example #4: More generic GET+print
61
+ # === GET by URI
72
62
  #
73
- # require 'net/http'
63
+ # uri = URI('http://example.com/index.html?count=10')
64
+ # Net::HTTP.get(uri) # => String
74
65
  #
75
- # url = URI.parse('http://www.example.com/index.html')
76
- # req = Net::HTTP::Get.new(url.path)
77
- # res = Net::HTTP.start(url.host, url.port) {|http|
78
- # http.request(req)
79
- # }
80
- # puts res.body
66
+ # === GET with Dynamic Parameters
81
67
  #
82
- # === Posting Form Data
68
+ # uri = URI('http://example.com/index.html')
69
+ # params = { :limit => 10, :page => 3 }
70
+ # uri.query = URI.encode_www_form(params)
83
71
  #
84
- # require 'net/http'
85
- # require 'uri'
72
+ # res = Net::HTTP.get_response(uri)
73
+ # puts res.body if res.is_a?(Net::HTTPSuccess)
86
74
  #
87
- # #1: Simple POST
88
- # res = Net::HTTP.post_form(URI.parse('http://www.example.com/search.cgi'),
89
- # {'q'=>'ruby', 'max'=>'50'})
90
- # puts res.body
75
+ # === POST
91
76
  #
92
- # #2: POST with basic authentication
93
- # res = Net::HTTP.post_form(URI.parse('http://jack:pass@www.example.com/todo.cgi'),
94
- # {'from'=>'2005-01-01', 'to'=>'2005-03-31'})
95
- # puts res.body
77
+ # uri = URI('http://www.example.com/search.cgi')
78
+ # res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
79
+ # puts res.body
96
80
  #
97
- # #3: Detailed control
98
- # url = URI.parse('http://www.example.com/todo.cgi')
99
- # req = Net::HTTP::Post.new(url.path)
100
- # req.basic_auth 'jack', 'pass'
101
- # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';')
102
- # res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }
103
- # case res
104
- # when Net::HTTPSuccess, Net::HTTPRedirection
105
- # # OK
106
- # else
107
- # res.error!
108
- # end
81
+ # === POST with Multiple Values
82
+ #
83
+ # uri = URI('http://www.example.com/search.cgi')
84
+ # res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
85
+ # puts res.body
109
86
  #
110
- # === Accessing via Proxy
87
+ # == How to use Net::HTTP
111
88
  #
112
- # Net::HTTP.Proxy creates http proxy class. It has same
113
- # methods of Net::HTTP but its instances always connect to
114
- # proxy, instead of given host.
89
+ # The following example code can be used as the basis of a HTTP user-agent
90
+ # which can perform a variety of request types using persistent
91
+ # connections.
115
92
  #
116
- # require 'net/http'
93
+ # uri = URI('http://example.com/some_path?query=string')
117
94
  #
118
- # proxy_addr = 'your.proxy.host'
119
- # proxy_port = 8080
120
- # :
121
- # Net::HTTP::Proxy(proxy_addr, proxy_port).start('www.example.com') {|http|
122
- # # always connect to your.proxy.addr:8080
123
- # :
124
- # }
95
+ # Net::HTTP.start(uri.host, uri.port) do |http|
96
+ # request = Net::HTTP::Get.new uri
125
97
  #
126
- # Since Net::HTTP.Proxy returns Net::HTTP itself when proxy_addr is nil,
127
- # there's no need to change code if there's proxy or not.
98
+ # response = http.request request # Net::HTTPResponse object
99
+ # end
128
100
  #
129
- # There are two additional parameters in Net::HTTP.Proxy which allow to
130
- # specify proxy user name and password:
101
+ # Net::HTTP::start immediately creates a connection to an HTTP server which
102
+ # is kept open for the duration of the block. The connection will remain
103
+ # open for multiple requests in the block if the server indicates it
104
+ # supports persistent connections.
131
105
  #
132
- # Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user = nil, proxy_pass = nil)
106
+ # The request types Net::HTTP supports are listed below in the section "HTTP
107
+ # Request Classes".
133
108
  #
134
- # You may use them to work with authorization-enabled proxies:
109
+ # If you wish to re-use a connection across multiple HTTP requests without
110
+ # automatically closing it you can use ::new instead of ::start. #request
111
+ # will automatically open a connection to the server if one is not currently
112
+ # open. You can manually close the connection with #finish.
135
113
  #
136
- # require 'net/http'
137
- # require 'uri'
114
+ # For all the Net::HTTP request objects and shortcut request methods you may
115
+ # supply either a String for the request path or a URI from which Net::HTTP
116
+ # will extract the request path.
138
117
  #
139
- # proxy_host = 'your.proxy.host'
140
- # proxy_port = 8080
141
- # uri = URI.parse(ENV['http_proxy'])
142
- # proxy_user, proxy_pass = uri.userinfo.split(/:/) if uri.userinfo
143
- # Net::HTTP::Proxy(proxy_host, proxy_port,
144
- # proxy_user, proxy_pass).start('www.example.com') {|http|
145
- # # always connect to your.proxy.addr:8080 using specified username and password
146
- # :
147
- # }
118
+ # === Response Data
148
119
  #
149
- # Note that net/http never rely on HTTP_PROXY environment variable.
150
- # If you want to use proxy, set it explicitly.
120
+ # uri = URI('http://example.com/index.html')
121
+ # res = Net::HTTP.get_response(uri)
122
+ #
123
+ # # Headers
124
+ # res['Set-Cookie'] # => String
125
+ # res.get_fields('set-cookie') # => Array
126
+ # res.to_hash['set-cookie'] # => Array
127
+ # puts "Headers: #{res.to_hash.inspect}"
128
+ #
129
+ # # Status
130
+ # puts res.code # => '200'
131
+ # puts res.message # => 'OK'
132
+ # puts res.class.name # => 'HTTPOK'
133
+ #
134
+ # # Body
135
+ # puts res.body if res.response_body_permitted?
151
136
  #
152
137
  # === Following Redirection
153
138
  #
154
- # require 'net/http'
155
- # require 'uri'
139
+ # Each Net::HTTPResponse object belongs to a class for its response code.
156
140
  #
157
- # def fetch(uri_str, limit = 10)
158
- # # You should choose better exception.
159
- # raise ArgumentError, 'HTTP redirect too deep' if limit == 0
141
+ # For example, all 2XX responses are instances of a Net::HTTPSuccess
142
+ # subclass, a 3XX response is an instance of a Net::HTTPRedirection
143
+ # subclass and a 200 response is an instance of the Net::HTTPOK class. For
144
+ # details of response classes, see the section "HTTP Response Classes"
145
+ # below.
160
146
  #
161
- # response = Net::HTTP.get_response(URI.parse(uri_str))
162
- # case response
163
- # when Net::HTTPSuccess then response
164
- # when Net::HTTPRedirection then fetch(response['location'], limit - 1)
165
- # else
166
- # response.error!
167
- # end
147
+ # Using a case statement you can handle various types of responses properly:
148
+ #
149
+ # def fetch(uri_str, limit = 10)
150
+ # # You should choose a better exception.
151
+ # raise ArgumentError, 'too many HTTP redirects' if limit == 0
152
+ #
153
+ # response = Net::HTTP.get_response(URI(uri_str))
154
+ #
155
+ # case response
156
+ # when Net::HTTPSuccess then
157
+ # response
158
+ # when Net::HTTPRedirection then
159
+ # location = response['location']
160
+ # warn "redirected to #{location}"
161
+ # fetch(location, limit - 1)
162
+ # else
163
+ # response.value
168
164
  # end
165
+ # end
166
+ #
167
+ # print fetch('http://www.ruby-lang.org')
168
+ #
169
+ # === POST
170
+ #
171
+ # A POST can be made using the Net::HTTP::Post request class. This example
172
+ # creates a urlencoded POST body:
173
+ #
174
+ # uri = URI('http://www.example.com/todo.cgi')
175
+ # req = Net::HTTP::Post.new(uri)
176
+ # req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
169
177
  #
170
- # print fetch('http://www.ruby-lang.org')
178
+ # res = Net::HTTP.start(uri.hostname, uri.port) do |http|
179
+ # http.request(req)
180
+ # end
171
181
  #
172
- # Net::HTTPSuccess and Net::HTTPRedirection is a HTTPResponse class.
173
- # All HTTPResponse objects belong to its own response class which
174
- # indicate HTTP result status. For details of response classes,
175
- # see section "HTTP Response Classes".
182
+ # case res
183
+ # when Net::HTTPSuccess, Net::HTTPRedirection
184
+ # # OK
185
+ # else
186
+ # res.value
187
+ # end
188
+ #
189
+ # At this time Net::HTTP does not support multipart/form-data. To send
190
+ # multipart/form-data use Net::HTTPRequest#body= and
191
+ # Net::HTTPRequest#content_type=:
192
+ #
193
+ # req = Net::HTTP::Post.new(uri)
194
+ # req.body = multipart_data
195
+ # req.content_type = 'multipart/form-data'
196
+ #
197
+ # Other requests that can contain a body such as PUT can be created in the
198
+ # same way using the corresponding request class (Net::HTTP::Put).
199
+ #
200
+ # === Setting Headers
201
+ #
202
+ # The following example performs a conditional GET using the
203
+ # If-Modified-Since header. If the files has not been modified since the
204
+ # time in the header a Not Modified response will be returned. See RFC 2616
205
+ # section 9.3 for further details.
206
+ #
207
+ # uri = URI('http://example.com/cached_response')
208
+ # file = File.stat 'cached_response'
209
+ #
210
+ # req = Net::HTTP::Get.new(uri)
211
+ # req['If-Modified-Since'] = file.mtime.rfc2822
212
+ #
213
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
214
+ # http.request(req)
215
+ # }
216
+ #
217
+ # open 'cached_response', 'w' do |io|
218
+ # io.write res.body
219
+ # end if res.is_a?(Net::HTTPSuccess)
176
220
  #
177
221
  # === Basic Authentication
178
222
  #
179
- # require 'net/http'
180
- #
181
- # Net::HTTP.start('www.example.com') {|http|
182
- # req = Net::HTTP::Get.new('/secret-page.html')
183
- # req.basic_auth 'account', 'password'
184
- # response = http.request(req)
185
- # print response.body
186
- # }
187
- #
188
- # === HTTP Request Classes
189
- #
190
- # Here is HTTP request class hierarchy.
191
- #
192
- # Net::HTTPRequest
193
- # Net::HTTP::Get
194
- # Net::HTTP::Head
195
- # Net::HTTP::Post
196
- # Net::HTTP::Put
197
- # Net::HTTP::Proppatch
198
- # Net::HTTP::Lock
199
- # Net::HTTP::Unlock
200
- # Net::HTTP::Options
201
- # Net::HTTP::Propfind
202
- # Net::HTTP::Delete
203
- # Net::HTTP::Move
204
- # Net::HTTP::Copy
205
- # Net::HTTP::Mkcol
206
- # Net::HTTP::Trace
207
- #
208
- # === HTTP Response Classes
209
- #
210
- # Here is HTTP response class hierarchy.
211
- # All classes are defined in Net module.
212
- #
213
- # HTTPResponse
214
- # HTTPUnknownResponse
215
- # HTTPInformation # 1xx
216
- # HTTPContinue # 100
217
- # HTTPSwitchProtocl # 101
218
- # HTTPSuccess # 2xx
219
- # HTTPOK # 200
220
- # HTTPCreated # 201
221
- # HTTPAccepted # 202
222
- # HTTPNonAuthoritativeInformation # 203
223
- # HTTPNoContent # 204
224
- # HTTPResetContent # 205
225
- # HTTPPartialContent # 206
226
- # HTTPRedirection # 3xx
227
- # HTTPMultipleChoice # 300
228
- # HTTPMovedPermanently # 301
229
- # HTTPFound # 302
230
- # HTTPSeeOther # 303
231
- # HTTPNotModified # 304
232
- # HTTPUseProxy # 305
233
- # HTTPTemporaryRedirect # 307
234
- # HTTPClientError # 4xx
235
- # HTTPBadRequest # 400
236
- # HTTPUnauthorized # 401
237
- # HTTPPaymentRequired # 402
238
- # HTTPForbidden # 403
239
- # HTTPNotFound # 404
240
- # HTTPMethodNotAllowed # 405
241
- # HTTPNotAcceptable # 406
242
- # HTTPProxyAuthenticationRequired # 407
243
- # HTTPRequestTimeOut # 408
244
- # HTTPConflict # 409
245
- # HTTPGone # 410
246
- # HTTPLengthRequired # 411
247
- # HTTPPreconditionFailed # 412
248
- # HTTPRequestEntityTooLarge # 413
249
- # HTTPRequestURITooLong # 414
250
- # HTTPUnsupportedMediaType # 415
251
- # HTTPRequestedRangeNotSatisfiable # 416
252
- # HTTPExpectationFailed # 417
253
- # HTTPServerError # 5xx
254
- # HTTPInternalServerError # 500
255
- # HTTPNotImplemented # 501
256
- # HTTPBadGateway # 502
257
- # HTTPServiceUnavailable # 503
258
- # HTTPGatewayTimeOut # 504
259
- # HTTPVersionNotSupported # 505
260
- #
261
- # == Switching Net::HTTP versions
262
- #
263
- # You can use net/http.rb 1.1 features (bundled with Ruby 1.6)
264
- # by calling HTTP.version_1_1. Calling Net::HTTP.version_1_2
265
- # allows you to use 1.2 features again.
266
- #
267
- # # example
268
- # Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
269
- #
270
- # Net::HTTP.version_1_1
271
- # Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
272
- #
273
- # Net::HTTP.version_1_2
274
- # Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
275
- #
276
- # This function is NOT thread-safe.
223
+ # Basic authentication is performed according to
224
+ # [RFC2617](http://www.ietf.org/rfc/rfc2617.txt)
225
+ #
226
+ # uri = URI('http://example.com/index.html?key=value')
227
+ #
228
+ # req = Net::HTTP::Get.new(uri)
229
+ # req.basic_auth 'user', 'pass'
230
+ #
231
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
232
+ # http.request(req)
233
+ # }
234
+ # puts res.body
235
+ #
236
+ # === Streaming Response Bodies
237
+ #
238
+ # By default Net::HTTP reads an entire response into memory. If you are
239
+ # handling large files or wish to implement a progress bar you can instead
240
+ # stream the body directly to an IO.
241
+ #
242
+ # uri = URI('http://example.com/large_file')
243
+ #
244
+ # Net::HTTP.start(uri.host, uri.port) do |http|
245
+ # request = Net::HTTP::Get.new uri
246
+ #
247
+ # http.request request do |response|
248
+ # open 'large_file', 'w' do |io|
249
+ # response.read_body do |chunk|
250
+ # io.write chunk
251
+ # end
252
+ # end
253
+ # end
254
+ # end
255
+ #
256
+ # === HTTPS
257
+ #
258
+ # HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.
259
+ #
260
+ # uri = URI('https://secure.example.com/some_path?query=string')
261
+ #
262
+ # Net::HTTP.start(uri.host, uri.port,
263
+ # :use_ssl => uri.scheme == 'https') do |http|
264
+ # request = Net::HTTP::Get.new uri
265
+ #
266
+ # response = http.request request # Net::HTTPResponse object
267
+ # end
268
+ #
269
+ # In previous versions of Ruby you would need to require 'net/https' to use
270
+ # HTTPS. This is no longer true.
271
+ #
272
+ # === Proxies
273
+ #
274
+ # Net::HTTP will automatically create a proxy from the +http_proxy+
275
+ # environment variable if it is present. To disable use of +http_proxy+,
276
+ # pass +nil+ for the proxy address.
277
+ #
278
+ # You may also create a custom proxy:
279
+ #
280
+ # proxy_addr = 'your.proxy.host'
281
+ # proxy_port = 8080
282
+ #
283
+ # Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
284
+ # # always proxy via your.proxy.addr:8080
285
+ # }
286
+ #
287
+ # See Net::HTTP.new for further details and examples such as proxies that
288
+ # require a username and password.
289
+ #
290
+ # === Compression
291
+ #
292
+ # Net::HTTP automatically adds Accept-Encoding for compression of response
293
+ # bodies and automatically decompresses gzip and deflate responses unless a
294
+ # Range header was sent.
295
+ #
296
+ # Compression can be disabled through the Accept-Encoding: identity header.
297
+ #
298
+ # == HTTP Request Classes
299
+ #
300
+ # Here is the HTTP request class hierarchy.
301
+ #
302
+ # * Net::HTTPRequest
303
+ # * Net::HTTP::Get
304
+ # * Net::HTTP::Head
305
+ # * Net::HTTP::Post
306
+ # * Net::HTTP::Patch
307
+ # * Net::HTTP::Put
308
+ # * Net::HTTP::Proppatch
309
+ # * Net::HTTP::Lock
310
+ # * Net::HTTP::Unlock
311
+ # * Net::HTTP::Options
312
+ # * Net::HTTP::Propfind
313
+ # * Net::HTTP::Delete
314
+ # * Net::HTTP::Move
315
+ # * Net::HTTP::Copy
316
+ # * Net::HTTP::Mkcol
317
+ # * Net::HTTP::Trace
318
+ #
319
+ # == HTTP Response Classes
320
+ #
321
+ # Here is HTTP response class hierarchy. All classes are defined in Net
322
+ # module and are subclasses of Net::HTTPResponse.
323
+ #
324
+ # HTTPUnknownResponse:: For unhandled HTTP extensions
325
+ # HTTPInformation:: 1xx
326
+ # HTTPContinue:: 100
327
+ # HTTPSwitchProtocol:: 101
328
+ # HTTPSuccess:: 2xx
329
+ # HTTPOK:: 200
330
+ # HTTPCreated:: 201
331
+ # HTTPAccepted:: 202
332
+ # HTTPNonAuthoritativeInformation:: 203
333
+ # HTTPNoContent:: 204
334
+ # HTTPResetContent:: 205
335
+ # HTTPPartialContent:: 206
336
+ # HTTPMultiStatus:: 207
337
+ # HTTPRedirection:: 3xx
338
+ # HTTPMultipleChoices:: 300
339
+ # HTTPMovedPermanently:: 301
340
+ # HTTPFound:: 302
341
+ # HTTPSeeOther:: 303
342
+ # HTTPNotModified:: 304
343
+ # HTTPUseProxy:: 305
344
+ # HTTPTemporaryRedirect:: 307
345
+ # HTTPClientError:: 4xx
346
+ # HTTPBadRequest:: 400
347
+ # HTTPUnauthorized:: 401
348
+ # HTTPPaymentRequired:: 402
349
+ # HTTPForbidden:: 403
350
+ # HTTPNotFound:: 404
351
+ # HTTPMethodNotAllowed:: 405
352
+ # HTTPNotAcceptable:: 406
353
+ # HTTPProxyAuthenticationRequired:: 407
354
+ # HTTPRequestTimeOut:: 408
355
+ # HTTPConflict:: 409
356
+ # HTTPGone:: 410
357
+ # HTTPLengthRequired:: 411
358
+ # HTTPPreconditionFailed:: 412
359
+ # HTTPRequestEntityTooLarge:: 413
360
+ # HTTPRequestURITooLong:: 414
361
+ # HTTPUnsupportedMediaType:: 415
362
+ # HTTPRequestedRangeNotSatisfiable:: 416
363
+ # HTTPExpectationFailed:: 417
364
+ # HTTPUnprocessableEntity:: 422
365
+ # HTTPLocked:: 423
366
+ # HTTPFailedDependency:: 424
367
+ # HTTPUpgradeRequired:: 426
368
+ # HTTPPreconditionRequired:: 428
369
+ # HTTPTooManyRequests:: 429
370
+ # HTTPRequestHeaderFieldsTooLarge:: 431
371
+ # HTTPServerError:: 5xx
372
+ # HTTPInternalServerError:: 500
373
+ # HTTPNotImplemented:: 501
374
+ # HTTPBadGateway:: 502
375
+ # HTTPServiceUnavailable:: 503
376
+ # HTTPGatewayTimeOut:: 504
377
+ # HTTPVersionNotSupported:: 505
378
+ # HTTPInsufficientStorage:: 507
379
+ # HTTPNetworkAuthenticationRequired:: 511
380
+ #
381
+ # There is also the Net::HTTPBadResponse exception which is raised when
382
+ # there is a protocol error.
277
383
  #
278
384
  class HTTP < Protocol
279
385
 
280
386
  # :stopdoc:
281
- Revision = %q$Revision$.split[1]
387
+ Revision = %q$Revision: 42169 $.split[1]
282
388
  HTTPVersion = '1.1'
283
- @newimpl = true
389
+ begin
390
+ require 'zlib'
391
+ require 'stringio' #for our purposes (unpacking gzip) lump these together
392
+ HAVE_ZLIB=true
393
+ rescue LoadError
394
+ HAVE_ZLIB=false
395
+ end
284
396
  # :startdoc:
285
397
 
286
- # Turns on net/http 1.2 (ruby 1.8) features.
287
- # Defaults to ON in ruby 1.8.
288
- #
289
- # I strongly recommend to call this method always.
290
- #
291
- # require 'net/http'
292
- # Net::HTTP.version_1_2
293
- #
398
+ # Turns on net/http 1.2 (Ruby 1.8) features.
399
+ # Defaults to ON in Ruby 1.8 or later.
294
400
  def HTTP.version_1_2
295
- @newimpl = true
401
+ true
296
402
  end
297
403
 
298
- # Turns on net/http 1.1 (ruby 1.6) features.
299
- # Defaults to OFF in ruby 1.8.
300
- def HTTP.version_1_1
301
- @newimpl = false
302
- end
303
-
304
- # true if net/http is in version 1.2 mode.
404
+ # Returns true if net/http is in version 1.2 mode.
305
405
  # Defaults to true.
306
406
  def HTTP.version_1_2?
307
- @newimpl
407
+ true
308
408
  end
309
409
 
310
- # true if net/http is in version 1.1 compatible mode.
311
- # Defaults to true.
312
- def HTTP.version_1_1?
313
- not @newimpl
410
+ def HTTP.version_1_1? #:nodoc:
411
+ false
314
412
  end
315
413
 
316
414
  class << HTTP
@@ -323,11 +421,11 @@ module Net #:nodoc:
323
421
  #
324
422
 
325
423
  #
326
- # Get body from target and output it to +$stdout+. The
327
- # target can either be specified as (+uri+), or as
328
- # (+host+, +path+, +port+ = 80); so:
424
+ # Gets the body text from the target and outputs it to $stdout. The
425
+ # target can either be specified as
426
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
329
427
  #
330
- # Net::HTTP.get_print URI.parse('http://www.example.com/index.html')
428
+ # Net::HTTP.get_print URI('http://www.example.com/index.html')
331
429
  #
332
430
  # or:
333
431
  #
@@ -342,11 +440,11 @@ module Net #:nodoc:
342
440
  nil
343
441
  end
344
442
 
345
- # Send a GET request to the target and return the response
443
+ # Sends a GET request to the target and returns the HTTP response
346
444
  # as a string. The target can either be specified as
347
445
  # (+uri+), or as (+host+, +path+, +port+ = 80); so:
348
446
  #
349
- # print Net::HTTP.get(URI.parse('http://www.example.com/index.html'))
447
+ # print Net::HTTP.get(URI('http://www.example.com/index.html'))
350
448
  #
351
449
  # or:
352
450
  #
@@ -356,11 +454,11 @@ module Net #:nodoc:
356
454
  get_response(uri_or_host, path, port).body
357
455
  end
358
456
 
359
- # Send a GET request to the target and return the response
457
+ # Sends a GET request to the target and returns the HTTP response
360
458
  # as a Net::HTTPResponse object. The target can either be specified as
361
459
  # (+uri+), or as (+host+, +path+, +port+ = 80); so:
362
460
  #
363
- # res = Net::HTTP.get_response(URI.parse('http://www.example.com/index.html'))
461
+ # res = Net::HTTP.get_response(URI('http://www.example.com/index.html'))
364
462
  # print res.body
365
463
  #
366
464
  # or:
@@ -376,32 +474,37 @@ module Net #:nodoc:
376
474
  }
377
475
  else
378
476
  uri = uri_or_host
379
- new(uri.host, uri.port).start {|http|
380
- return http.request_get(uri.request_uri, &block)
477
+ start(uri.hostname, uri.port,
478
+ :use_ssl => uri.scheme == 'https') {|http|
479
+ return http.request_get(uri, &block)
381
480
  }
382
481
  end
383
482
  end
384
483
 
385
- # Posts HTML form data to the +URL+.
386
- # Form data must be represented as a Hash of String to String, e.g:
484
+ # Posts HTML form data to the specified URI object.
485
+ # The form data must be provided as a Hash mapping from String to String.
486
+ # Example:
387
487
  #
388
488
  # { "cmd" => "search", "q" => "ruby", "max" => "50" }
389
489
  #
390
- # This method also does Basic Authentication iff +URL+.user exists.
490
+ # This method also does Basic Authentication iff +url+.user exists.
491
+ # But userinfo for authentication is deprecated (RFC3986).
492
+ # So this feature will be removed.
391
493
  #
392
494
  # Example:
393
495
  #
394
496
  # require 'net/http'
395
497
  # require 'uri'
396
498
  #
397
- # HTTP.post_form URI.parse('http://www.example.com/search.cgi'),
398
- # { "q" => "ruby", "max" => "50" }
499
+ # Net::HTTP.post_form URI('http://www.example.com/search.cgi'),
500
+ # { "q" => "ruby", "max" => "50" }
399
501
  #
400
502
  def HTTP.post_form(url, params)
401
- req = Post.new(url.path)
503
+ req = Post.new(url)
402
504
  req.form_data = params
403
505
  req.basic_auth url.user, url.password if url.user
404
- new(url.host, url.port).start {|http|
506
+ start(url.hostname, url.port,
507
+ :use_ssl => url.scheme == 'https' ) {|http|
405
508
  http.request(req)
406
509
  }
407
510
  end
@@ -429,59 +532,146 @@ module Net #:nodoc:
429
532
  BufferedIO
430
533
  end
431
534
 
432
- # creates a new Net::HTTP object and opens its TCP connection and
433
- # HTTP session. If the optional block is given, the newly
535
+ # :call-seq:
536
+ # HTTP.start(address, port, p_addr, p_port, p_user, p_pass, &block)
537
+ # HTTP.start(address, port=nil, p_addr=nil, p_port=nil, p_user=nil, p_pass=nil, opt, &block)
538
+ #
539
+ # Creates a new Net::HTTP object, then additionally opens the TCP
540
+ # connection and HTTP session.
541
+ #
542
+ # Arguments are the following:
543
+ # _address_ :: hostname or IP address of the server
544
+ # _port_ :: port of the server
545
+ # _p_addr_ :: address of proxy
546
+ # _p_port_ :: port of proxy
547
+ # _p_user_ :: user of proxy
548
+ # _p_pass_ :: pass of proxy
549
+ # _opt_ :: optional hash
550
+ #
551
+ # _opt_ sets following values by its accessor.
552
+ # The keys are ca_file, ca_path, cert, cert_store, ciphers,
553
+ # close_on_empty_response, key, open_timeout, read_timeout, ssl_timeout,
554
+ # ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
555
+ # If you set :use_ssl as true, you can use https and default value of
556
+ # verify_mode is set as OpenSSL::SSL::VERIFY_PEER.
557
+ #
558
+ # If the optional block is given, the newly
434
559
  # created Net::HTTP object is passed to it and closed when the
435
560
  # block finishes. In this case, the return value of this method
436
561
  # is the return value of the block. If no block is given, the
437
562
  # return value of this method is the newly created Net::HTTP object
438
- # itself, and the caller is responsible for closing it upon completion.
439
- def HTTP.start(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil, &block) # :yield: +http+
440
- new(address, port, p_addr, p_port, p_user, p_pass).start(&block)
563
+ # itself, and the caller is responsible for closing it upon completion
564
+ # using the finish() method.
565
+ def HTTP.start(address, *arg, &block) # :yield: +http+
566
+ arg.pop if opt = Hash.try_convert(arg[-1])
567
+ port, p_addr, p_port, p_user, p_pass = *arg
568
+ port = https_default_port if !port && opt && opt[:use_ssl]
569
+ http = new(address, port, p_addr, p_port, p_user, p_pass)
570
+
571
+ if opt
572
+ if opt[:use_ssl]
573
+ opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
574
+ end
575
+ http.methods.grep(/\A(\w+)=\z/) do |meth|
576
+ key = $1.to_sym
577
+ opt.key?(key) or next
578
+ http.__send__(meth, opt[key])
579
+ end
580
+ end
581
+
582
+ http.start(&block)
441
583
  end
442
584
 
443
585
  class << HTTP
444
- alias newobj new
445
- end
586
+ alias newobj new # :nodoc:
587
+ end
588
+
589
+ # Creates a new Net::HTTP object without opening a TCP connection or
590
+ # HTTP session.
591
+ #
592
+ # The +address+ should be a DNS hostname or IP address, the +port+ is the
593
+ # port the server operates on. If no +port+ is given the default port for
594
+ # HTTP or HTTPS is used.
595
+ #
596
+ # If none of the +p_+ arguments are given, the proxy host and port are
597
+ # taken from the +http_proxy+ environment variable (or its uppercase
598
+ # equivalent) if present. If the proxy requires authentication you must
599
+ # supply it by hand. See URI::Generic#find_proxy for details of proxy
600
+ # detection from the environment. To disable proxy detection set +p_addr+
601
+ # to nil.
602
+ #
603
+ # If you are connecting to a custom proxy, +p_addr+ the DNS name or IP
604
+ # address of the proxy host, +p_port+ the port to use to access the proxy,
605
+ # and +p_user+ and +p_pass+ the username and password if authorization is
606
+ # required to use the proxy.
607
+ #
608
+ def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)
609
+ http = super address, port
610
+
611
+ if proxy_class? then # from Net::HTTP::Proxy()
612
+ http.proxy_from_env = @proxy_from_env
613
+ http.proxy_address = @proxy_address
614
+ http.proxy_port = @proxy_port
615
+ http.proxy_user = @proxy_user
616
+ http.proxy_pass = @proxy_pass
617
+ elsif p_addr == :ENV then
618
+ http.proxy_from_env = true
619
+ else
620
+ http.proxy_address = p_addr
621
+ http.proxy_port = p_port || default_port
622
+ http.proxy_user = p_user
623
+ http.proxy_pass = p_pass
624
+ end
446
625
 
447
- # Creates a new Net::HTTP object.
448
- # If +proxy_addr+ is given, creates an Net::HTTP object with proxy support.
449
- # This method does not open the TCP connection.
450
- def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil)
451
- h = Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port)
452
- h.instance_eval {
453
- @newimpl = ::Net::HTTP.version_1_2?
454
- }
455
- h
626
+ http
456
627
  end
457
628
 
458
- # Creates a new Net::HTTP object for the specified +address+.
459
- # This method does not open the TCP connection.
629
+ # Creates a new Net::HTTP object for the specified server address,
630
+ # without opening the TCP connection or initializing the HTTP session.
631
+ # The +address+ should be a DNS hostname or IP address.
460
632
  def initialize(address, port = nil)
461
633
  @address = address
462
634
  @port = (port || HTTP.default_port)
635
+ @local_host = nil
636
+ @local_port = nil
463
637
  @curr_http_version = HTTPVersion
464
- @seems_1_0_server = false
638
+ @keep_alive_timeout = 2
639
+ @last_communicated = nil
465
640
  @close_on_empty_response = false
466
641
  @socket = nil
467
642
  @started = false
468
643
  @open_timeout = nil
469
644
  @read_timeout = 60
645
+ @continue_timeout = nil
470
646
  @debug_output = nil
647
+
648
+ @proxy_from_env = false
649
+ @proxy_uri = nil
650
+ @proxy_address = nil
651
+ @proxy_port = nil
652
+ @proxy_user = nil
653
+ @proxy_pass = nil
654
+
471
655
  @use_ssl = false
472
656
  @ssl_context = nil
657
+ @ssl_session = nil
658
+ @enable_post_connection_check = true
659
+ @sspi_enabled = false
660
+ SSL_IVNAMES.each do |ivname|
661
+ instance_variable_set ivname, nil
662
+ end
473
663
  end
474
664
 
475
665
  def inspect
476
666
  "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
477
667
  end
478
668
 
479
- # *WARNING* This method causes serious security hole.
669
+ # *WARNING* This method opens a serious security hole.
480
670
  # Never use this method in production code.
481
671
  #
482
- # Set an output stream for debugging.
672
+ # Sets an output stream for debugging.
483
673
  #
484
- # http = Net::HTTP.new
674
+ # http = Net::HTTP.new(hostname)
485
675
  # http.set_debug_output $stderr
486
676
  # http.start { .... }
487
677
  #
@@ -490,20 +680,34 @@ module Net #:nodoc:
490
680
  @debug_output = output
491
681
  end
492
682
 
493
- # The host name to connect to.
683
+ # The DNS host name or IP address to connect to.
494
684
  attr_reader :address
495
685
 
496
686
  # The port number to connect to.
497
687
  attr_reader :port
498
688
 
499
- # Seconds to wait until connection is opened.
500
- # If the HTTP object cannot open a connection in this many seconds,
501
- # it raises a TimeoutError exception.
689
+ # The local host used to estabilish the connection.
690
+ attr_accessor :local_host
691
+
692
+ # The local port used to estabilish the connection.
693
+ attr_accessor :local_port
694
+
695
+ attr_writer :proxy_from_env
696
+ attr_writer :proxy_address
697
+ attr_writer :proxy_port
698
+ attr_writer :proxy_user
699
+ attr_writer :proxy_pass
700
+
701
+ # Number of seconds to wait for the connection to open. Any number
702
+ # may be used, including Floats for fractional seconds. If the HTTP
703
+ # object cannot open a connection in this many seconds, it raises a
704
+ # Net::OpenTimeout exception. The default value is +nil+.
502
705
  attr_accessor :open_timeout
503
706
 
504
- # Seconds to wait until reading one block (by one read(2) call).
505
- # If the HTTP object cannot open a connection in this many seconds,
506
- # it raises a TimeoutError exception.
707
+ # Number of seconds to wait for one block to be read (via one read(2)
708
+ # call). Any number may be used, including Floats for fractional
709
+ # seconds. If the HTTP object cannot read data in this many seconds,
710
+ # it raises a Net::ReadTimeout exception. The default value is 60 seconds.
507
711
  attr_reader :read_timeout
508
712
 
509
713
  # Setter for the read_timeout attribute.
@@ -512,7 +716,24 @@ module Net #:nodoc:
512
716
  @read_timeout = sec
513
717
  end
514
718
 
515
- # returns true if the HTTP session is started.
719
+ # Seconds to wait for 100 Continue response. If the HTTP object does not
720
+ # receive a response in this many seconds it sends the request body. The
721
+ # default value is +nil+.
722
+ attr_reader :continue_timeout
723
+
724
+ # Setter for the continue_timeout attribute.
725
+ def continue_timeout=(sec)
726
+ @socket.continue_timeout = sec if @socket
727
+ @continue_timeout = sec
728
+ end
729
+
730
+ # Seconds to reuse the connection of the previous request.
731
+ # If the idle time is less than this Keep-Alive Timeout,
732
+ # Net::HTTP reuses the TCP/IP socket used by the previous communication.
733
+ # The default value is 2 seconds.
734
+ attr_accessor :keep_alive_timeout
735
+
736
+ # Returns true if the HTTP session has been started.
516
737
  def started?
517
738
  @started
518
739
  end
@@ -521,19 +742,107 @@ module Net #:nodoc:
521
742
 
522
743
  attr_accessor :close_on_empty_response
523
744
 
524
- # returns true if use SSL/TLS with HTTP.
745
+ # Returns true if SSL/TLS is being used with HTTP.
525
746
  def use_ssl?
526
- false # redefined in net/https
747
+ @use_ssl
748
+ end
749
+
750
+ # Turn on/off SSL.
751
+ # This flag must be set before starting session.
752
+ # If you change use_ssl value after session started,
753
+ # a Net::HTTP object raises IOError.
754
+ def use_ssl=(flag)
755
+ flag = flag ? true : false
756
+ if started? and @use_ssl != flag
757
+ raise IOError, "use_ssl value changed, but session already started"
758
+ end
759
+ @use_ssl = flag
760
+ end
761
+
762
+ SSL_IVNAMES = [
763
+ :@ca_file,
764
+ :@ca_path,
765
+ :@cert,
766
+ :@cert_store,
767
+ :@ciphers,
768
+ :@key,
769
+ :@ssl_timeout,
770
+ :@ssl_version,
771
+ :@verify_callback,
772
+ :@verify_depth,
773
+ :@verify_mode,
774
+ ]
775
+ SSL_ATTRIBUTES = [
776
+ :ca_file,
777
+ :ca_path,
778
+ :cert,
779
+ :cert_store,
780
+ :ciphers,
781
+ :key,
782
+ :ssl_timeout,
783
+ :ssl_version,
784
+ :verify_callback,
785
+ :verify_depth,
786
+ :verify_mode,
787
+ ]
788
+
789
+ # Sets path of a CA certification file in PEM format.
790
+ #
791
+ # The file can contain several CA certificates.
792
+ attr_accessor :ca_file
793
+
794
+ # Sets path of a CA certification directory containing certifications in
795
+ # PEM format.
796
+ attr_accessor :ca_path
797
+
798
+ # Sets an OpenSSL::X509::Certificate object as client certificate.
799
+ # (This method is appeared in Michal Rokos's OpenSSL extension).
800
+ attr_accessor :cert
801
+
802
+ # Sets the X509::Store to verify peer certificate.
803
+ attr_accessor :cert_store
804
+
805
+ # Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers=
806
+ attr_accessor :ciphers
807
+
808
+ # Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
809
+ # (This method is appeared in Michal Rokos's OpenSSL extension.)
810
+ attr_accessor :key
811
+
812
+ # Sets the SSL timeout seconds.
813
+ attr_accessor :ssl_timeout
814
+
815
+ # Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version=
816
+ attr_accessor :ssl_version
817
+
818
+ # Sets the verify callback for the server certification verification.
819
+ attr_accessor :verify_callback
820
+
821
+ # Sets the maximum depth for the certificate chain verification.
822
+ attr_accessor :verify_depth
823
+
824
+ # Sets the flags for server the certification verification at beginning of
825
+ # SSL/TLS session.
826
+ #
827
+ # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
828
+ attr_accessor :verify_mode
829
+
830
+ # Returns the X.509 certificates the server presented.
831
+ def peer_cert
832
+ if not use_ssl? or not @socket
833
+ return nil
834
+ end
835
+ @socket.io.peer_cert
527
836
  end
528
837
 
529
- # Opens TCP connection and HTTP session.
838
+ # Opens a TCP connection and HTTP session.
530
839
  #
531
- # When this method is called with block, gives a HTTP object
532
- # to the block and closes the TCP connection / HTTP session
533
- # after the block executed.
840
+ # When this method is called with a block, it passes the Net::HTTP
841
+ # object to the block, and closes the TCP connection and HTTP session
842
+ # after the block has been executed.
534
843
  #
535
- # When called with a block, returns the return value of the
536
- # block; otherwise, returns self.
844
+ # When called with a block, it returns the return value of the
845
+ # block; otherwise, it returns self.
537
846
  #
538
847
  def start # :yield: http
539
848
  raise IOError, 'HTTP session already opened' if @started
@@ -556,36 +865,66 @@ module Net #:nodoc:
556
865
  private :do_start
557
866
 
558
867
  def connect
559
- D "opening connection to #{conn_address()}..."
560
- s = timeout(@open_timeout) { TCPSocket.open(conn_address(), conn_port()) }
868
+ if proxy? then
869
+ conn_address = proxy_address
870
+ conn_port = proxy_port
871
+ else
872
+ conn_address = address
873
+ conn_port = port
874
+ end
875
+
876
+ D "opening connection to #{conn_address}:#{conn_port}..."
877
+ s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
878
+ TCPSocket.open(conn_address, conn_port, @local_host, @local_port)
879
+ }
880
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
561
881
  D "opened"
562
882
  if use_ssl?
563
- unless @ssl_context.verify_mode
564
- warn "warning: peer certificate won't be verified in this SSL session"
565
- @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
883
+ ssl_parameters = Hash.new
884
+ iv_list = instance_variables
885
+ SSL_IVNAMES.each_with_index do |ivname, i|
886
+ if iv_list.include?(ivname) and
887
+ value = instance_variable_get(ivname)
888
+ ssl_parameters[SSL_ATTRIBUTES[i]] = value if value
889
+ end
566
890
  end
891
+ @ssl_context = OpenSSL::SSL::SSLContext.new
892
+ @ssl_context.set_params(ssl_parameters)
893
+ D "starting SSL for #{conn_address}:#{conn_port}..."
567
894
  s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
568
895
  s.sync_close = true
896
+ D "SSL established"
569
897
  end
570
898
  @socket = BufferedIO.new(s)
571
899
  @socket.read_timeout = @read_timeout
900
+ @socket.continue_timeout = @continue_timeout
572
901
  @socket.debug_output = @debug_output
573
902
  if use_ssl?
574
- if proxy?
575
- @socket.writeline sprintf('CONNECT %s:%s HTTP/%s',
576
- @address, @port, HTTPVersion)
577
- @socket.writeline "Host: #{@address}:#{@port}"
578
- if proxy_user
579
- credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
580
- credential.delete!("\r\n")
581
- @socket.writeline "Proxy-Authorization: Basic #{credential}"
903
+ begin
904
+ if proxy?
905
+ buf = "CONNECT #{@address}:#{@port} HTTP/#{HTTPVersion}\r\n"
906
+ buf << "Host: #{@address}:#{@port}\r\n"
907
+ if proxy_user
908
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
909
+ credential.delete!("\r\n")
910
+ buf << "Proxy-Authorization: Basic #{credential}\r\n"
911
+ end
912
+ buf << "\r\n"
913
+ @socket.write(buf)
914
+ HTTPResponse.read_new(@socket).value
582
915
  end
583
- @socket.writeline ''
584
- HTTPResponse.read_new(@socket).value
585
- end
586
- s.connect
587
- if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
588
- s.post_connection_check(@address)
916
+ s.session = @ssl_session if @ssl_session
917
+ # Server Name Indication (SNI) RFC 3546
918
+ s.hostname = @address if s.respond_to? :hostname=
919
+ Timeout.timeout(@open_timeout, Net::OpenTimeout) { s.connect }
920
+ if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
921
+ s.post_connection_check(@address)
922
+ end
923
+ @ssl_session = s.session
924
+ rescue => exception
925
+ D "Conn close because of connect error #{exception}"
926
+ @socket.close if @socket and not @socket.closed?
927
+ raise exception
589
928
  end
590
929
  end
591
930
  on_connect
@@ -596,8 +935,8 @@ module Net #:nodoc:
596
935
  end
597
936
  private :on_connect
598
937
 
599
- # Finishes HTTP session and closes TCP connection.
600
- # Raises IOError if not started.
938
+ # Finishes the HTTP session and closes the TCP connection.
939
+ # Raises IOError if the session has not been started.
601
940
  def finish
602
941
  raise IOError, 'HTTP session not yet started' unless started?
603
942
  do_finish
@@ -618,77 +957,103 @@ module Net #:nodoc:
618
957
 
619
958
  # no proxy
620
959
  @is_proxy_class = false
960
+ @proxy_from_env = false
621
961
  @proxy_addr = nil
622
962
  @proxy_port = nil
623
963
  @proxy_user = nil
624
964
  @proxy_pass = nil
625
965
 
626
- # Creates an HTTP proxy class.
627
- # Arguments are address/port of proxy host and username/password
628
- # if authorization on proxy server is required.
629
- # You can replace the HTTP class with created proxy class.
966
+ # Creates an HTTP proxy class which behaves like Net::HTTP, but
967
+ # performs all access via the specified proxy.
630
968
  #
631
- # If ADDRESS is nil, this method returns self (Net::HTTP).
632
- #
633
- # # Example
634
- # proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080)
635
- # :
636
- # proxy_class.start('www.ruby-lang.org') {|http|
637
- # # connecting proxy.foo.org:8080
638
- # :
639
- # }
640
- #
641
- def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil)
969
+ # This class is obsolete. You may pass these same parameters directly to
970
+ # Net::HTTP.new. See Net::HTTP.new for details of the arguments.
971
+ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)
642
972
  return self unless p_addr
643
- delta = ProxyDelta
644
- proxyclass = Class.new(self)
645
- proxyclass.module_eval {
646
- include delta
647
- # with proxy
973
+
974
+ Class.new(self) {
648
975
  @is_proxy_class = true
649
- @proxy_address = p_addr
650
- @proxy_port = p_port || default_port()
651
- @proxy_user = p_user
652
- @proxy_pass = p_pass
976
+
977
+ if p_addr == :ENV then
978
+ @proxy_from_env = true
979
+ @proxy_address = nil
980
+ @proxy_port = nil
981
+ else
982
+ @proxy_from_env = false
983
+ @proxy_address = p_addr
984
+ @proxy_port = p_port || default_port
985
+ end
986
+
987
+ @proxy_user = p_user
988
+ @proxy_pass = p_pass
653
989
  }
654
- proxyclass
655
990
  end
656
991
 
657
992
  class << HTTP
658
993
  # returns true if self is a class which was created by HTTP::Proxy.
659
994
  def proxy_class?
660
- @is_proxy_class
995
+ defined?(@is_proxy_class) ? @is_proxy_class : false
661
996
  end
662
997
 
998
+ # Address of proxy host. If Net::HTTP does not use a proxy, nil.
663
999
  attr_reader :proxy_address
1000
+
1001
+ # Port number of proxy host. If Net::HTTP does not use a proxy, nil.
664
1002
  attr_reader :proxy_port
1003
+
1004
+ # User name for accessing proxy. If Net::HTTP does not use a proxy, nil.
665
1005
  attr_reader :proxy_user
1006
+
1007
+ # User password for accessing proxy. If Net::HTTP does not use a proxy,
1008
+ # nil.
666
1009
  attr_reader :proxy_pass
667
1010
  end
668
1011
 
669
- # True if self is a HTTP proxy class.
1012
+ # True if requests for this connection will be proxied
670
1013
  def proxy?
671
- self.class.proxy_class?
1014
+ !!if @proxy_from_env then
1015
+ proxy_uri
1016
+ else
1017
+ @proxy_address
1018
+ end
1019
+ end
1020
+
1021
+ # True if the proxy for this connection is determined from the environment
1022
+ def proxy_from_env?
1023
+ @proxy_from_env
1024
+ end
1025
+
1026
+ # The proxy URI determined from the environment for this connection.
1027
+ def proxy_uri # :nodoc:
1028
+ @proxy_uri ||= URI("http://#{address}:#{port}").find_proxy
672
1029
  end
673
1030
 
674
- # Address of proxy host. If self does not use a proxy, nil.
1031
+ # The address of the proxy server, if one is configured.
675
1032
  def proxy_address
676
- self.class.proxy_address
1033
+ if @proxy_from_env then
1034
+ proxy_uri && proxy_uri.hostname
1035
+ else
1036
+ @proxy_address
1037
+ end
677
1038
  end
678
1039
 
679
- # Port number of proxy host. If self does not use a proxy, nil.
1040
+ # The port of the proxy server, if one is configured.
680
1041
  def proxy_port
681
- self.class.proxy_port
1042
+ if @proxy_from_env then
1043
+ proxy_uri && proxy_uri.port
1044
+ else
1045
+ @proxy_port
1046
+ end
682
1047
  end
683
1048
 
684
- # User name for accessing proxy. If self does not use a proxy, nil.
1049
+ # The proxy username, if one is configured
685
1050
  def proxy_user
686
- self.class.proxy_user
1051
+ @proxy_user
687
1052
  end
688
1053
 
689
- # User password for accessing proxy. If self does not use a proxy, nil.
1054
+ # The proxy password, if one is configured
690
1055
  def proxy_pass
691
- self.class.proxy_pass
1056
+ @proxy_pass
692
1057
  end
693
1058
 
694
1059
  alias proxyaddr proxy_address #:nodoc: obsolete
@@ -696,33 +1061,21 @@ module Net #:nodoc:
696
1061
 
697
1062
  private
698
1063
 
699
- # without proxy
1064
+ # without proxy, obsolete
700
1065
 
701
- def conn_address
1066
+ def conn_address # :nodoc:
702
1067
  address()
703
1068
  end
704
1069
 
705
- def conn_port
1070
+ def conn_port # :nodoc:
706
1071
  port()
707
1072
  end
708
1073
 
709
1074
  def edit_path(path)
710
- path
711
- end
712
-
713
- module ProxyDelta #:nodoc: internal use only
714
- private
715
-
716
- def conn_address
717
- proxy_address()
718
- end
719
-
720
- def conn_port
721
- proxy_port()
722
- end
723
-
724
- def edit_path(path)
725
- use_ssl? ? path : "http://#{addr_port()}#{path}"
1075
+ if proxy? and not use_ssl? then
1076
+ "http://#{addr_port}#{path}"
1077
+ else
1078
+ path
726
1079
  end
727
1080
  end
728
1081
 
@@ -732,13 +1085,23 @@ module Net #:nodoc:
732
1085
 
733
1086
  public
734
1087
 
735
- # Gets data from +path+ on the connected-to host.
736
- # +header+ must be a Hash like { 'Accept' => '*/*', ... }.
1088
+ # Retrieves data from +path+ on the connected-to host which may be an
1089
+ # absolute path String or a URI to extract the path from.
1090
+ #
1091
+ # +initheader+ must be a Hash like { 'Accept' => '*/*', ... },
1092
+ # and it defaults to an empty hash.
1093
+ # If +initheader+ doesn't have the key 'accept-encoding', then
1094
+ # a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used,
1095
+ # so that gzip compression is used in preference to deflate
1096
+ # compression, which is used in preference to no compression.
1097
+ # Ruby doesn't have libraries to support the compress (Lempel-Ziv)
1098
+ # compression, so that is not supported. The intent of this is
1099
+ # to reduce bandwidth by default. If this routine sets up
1100
+ # compression, then it does the decompression also, removing
1101
+ # the header as well to prevent confusion. Otherwise
1102
+ # it leaves the body as it found it.
737
1103
  #
738
- # In version 1.1 (ruby 1.6), this method returns a pair of objects,
739
- # a Net::HTTPResponse object and the entity body string.
740
- # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse
741
- # object.
1104
+ # This method returns a Net::HTTPResponse object.
742
1105
  #
743
1106
  # If called with a block, yields each fragment of the
744
1107
  # entity body in turn as a string as it is read from
@@ -748,16 +1111,8 @@ module Net #:nodoc:
748
1111
  # +dest+ argument is obsolete.
749
1112
  # It still works but you must not use it.
750
1113
  #
751
- # In version 1.1, this method might raise an exception for
752
- # 3xx (redirect). In this case you can get a HTTPResponse object
753
- # by "anException.response".
754
- #
755
- # In version 1.2, this method never raises exception.
756
- #
757
- # # version 1.1 (bundled with Ruby 1.6)
758
- # response, body = http.get('/index.html')
1114
+ # This method never raises an exception.
759
1115
  #
760
- # # version 1.2 (bundled with Ruby 1.8 or later)
761
1116
  # response = http.get('/index.html')
762
1117
  #
763
1118
  # # using block
@@ -767,17 +1122,12 @@ module Net #:nodoc:
767
1122
  # end
768
1123
  # }
769
1124
  #
770
- def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
1125
+ def get(path, initheader = {}, dest = nil, &block) # :yield: +body_segment+
771
1126
  res = nil
772
1127
  request(Get.new(path, initheader)) {|r|
773
1128
  r.read_body dest, &block
774
1129
  res = r
775
1130
  }
776
- unless @newimpl
777
- res.value
778
- return res, res.body
779
- end
780
-
781
1131
  res
782
1132
  end
783
1133
 
@@ -786,10 +1136,7 @@ module Net #:nodoc:
786
1136
  #
787
1137
  # This method returns a Net::HTTPResponse object.
788
1138
  #
789
- # In version 1.1, this method might raise an exception for
790
- # 3xx (redirect). On the case you can get a HTTPResponse object
791
- # by "anException.response".
792
- # In version 1.2, this method never raises an exception.
1139
+ # This method never raises an exception.
793
1140
  #
794
1141
  # response = nil
795
1142
  # Net::HTTP.start('some.www.server', 80) {|http|
@@ -798,35 +1145,24 @@ module Net #:nodoc:
798
1145
  # p response['content-type']
799
1146
  #
800
1147
  def head(path, initheader = nil)
801
- res = request(Head.new(path, initheader))
802
- res.value unless @newimpl
803
- res
1148
+ request(Head.new(path, initheader))
804
1149
  end
805
1150
 
806
1151
  # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
807
1152
  # like { 'Accept' => '*/*', ... }.
808
1153
  #
809
- # In version 1.1 (ruby 1.6), this method returns a pair of objects, a
810
- # Net::HTTPResponse object and an entity body string.
811
- # In version 1.2 (ruby 1.8), this method returns a Net::HTTPResponse object.
1154
+ # This method returns a Net::HTTPResponse object.
812
1155
  #
813
1156
  # If called with a block, yields each fragment of the
814
- # entity body in turn as a string as it are read from
1157
+ # entity body in turn as a string as it is read from
815
1158
  # the socket. Note that in this case, the returned response
816
1159
  # object will *not* contain a (meaningful) body.
817
1160
  #
818
1161
  # +dest+ argument is obsolete.
819
1162
  # It still works but you must not use it.
820
1163
  #
821
- # In version 1.1, this method might raise an exception for
822
- # 3xx (redirect). In this case you can get an HTTPResponse object
823
- # by "anException.response".
824
- # In version 1.2, this method never raises exception.
825
- #
826
- # # version 1.1
827
- # response, body = http.post('/cgi-bin/search.rb', 'query=foo')
1164
+ # This method never raises exception.
828
1165
  #
829
- # # version 1.2
830
1166
  # response = http.post('/cgi-bin/search.rb', 'query=foo')
831
1167
  #
832
1168
  # # using block
@@ -841,22 +1177,17 @@ module Net #:nodoc:
841
1177
  # "application/x-www-form-urlencoded" by default.
842
1178
  #
843
1179
  def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
844
- res = nil
845
- request(Post.new(path, initheader), data) {|r|
846
- r.read_body dest, &block
847
- res = r
848
- }
849
- unless @newimpl
850
- res.value
851
- return res, res.body
852
- end
853
- res
1180
+ send_entity(path, data, initheader, dest, Post, &block)
1181
+ end
1182
+
1183
+ # Sends a PATCH request to the +path+ and gets a response,
1184
+ # as an HTTPResponse object.
1185
+ def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
1186
+ send_entity(path, data, initheader, dest, Patch, &block)
854
1187
  end
855
1188
 
856
1189
  def put(path, data, initheader = nil) #:nodoc:
857
- res = request(Put.new(path, initheader), data)
858
- res.value unless @newimpl
859
- res
1190
+ request(Put.new(path, initheader), data)
860
1191
  end
861
1192
 
862
1193
  # Sends a PROPPATCH request to the +path+ and gets a response,
@@ -919,12 +1250,12 @@ module Net #:nodoc:
919
1250
  request(Trace.new(path, initheader))
920
1251
  end
921
1252
 
922
- # Sends a GET request to the +path+ and gets a response,
923
- # as an HTTPResponse object.
1253
+ # Sends a GET request to the +path+.
1254
+ # Returns the response as a Net::HTTPResponse object.
924
1255
  #
925
- # When called with a block, yields an HTTPResponse object.
926
- # The body of this response will not have been read yet;
927
- # the caller can process it using HTTPResponse#read_body,
1256
+ # When called with a block, passes an HTTPResponse object to the block.
1257
+ # The body of the response will not have been read yet;
1258
+ # the block can process it using HTTPResponse#read_body,
928
1259
  # if desired.
929
1260
  #
930
1261
  # Returns the response.
@@ -932,11 +1263,11 @@ module Net #:nodoc:
932
1263
  # This method never raises Net::* exceptions.
933
1264
  #
934
1265
  # response = http.request_get('/index.html')
935
- # # The entity body is already read here.
1266
+ # # The entity body is already read in this case.
936
1267
  # p response['content-type']
937
1268
  # puts response.body
938
1269
  #
939
- # # using block
1270
+ # # Using a block
940
1271
  # http.request_get('/index.html') {|response|
941
1272
  # p response['content-type']
942
1273
  # response.read_body do |str| # read body now
@@ -948,8 +1279,8 @@ module Net #:nodoc:
948
1279
  request(Get.new(path, initheader), &block)
949
1280
  end
950
1281
 
951
- # Sends a HEAD request to the +path+ and gets a response,
952
- # as an HTTPResponse object.
1282
+ # Sends a HEAD request to the +path+ and returns the response
1283
+ # as a Net::HTTPResponse object.
953
1284
  #
954
1285
  # Returns the response.
955
1286
  #
@@ -962,13 +1293,13 @@ module Net #:nodoc:
962
1293
  request(Head.new(path, initheader), &block)
963
1294
  end
964
1295
 
965
- # Sends a POST request to the +path+ and gets a response,
966
- # as an HTTPResponse object.
1296
+ # Sends a POST request to the +path+.
967
1297
  #
968
- # When called with a block, yields an HTTPResponse object.
969
- # The body of this response will not have been read yet;
970
- # the caller can process it using HTTPResponse#read_body,
971
- # if desired.
1298
+ # Returns the response as a Net::HTTPResponse object.
1299
+ #
1300
+ # When called with a block, the block is passed an HTTPResponse
1301
+ # object. The body of that response will not have been read yet;
1302
+ # the block can process it using HTTPResponse#read_body, if desired.
972
1303
  #
973
1304
  # Returns the response.
974
1305
  #
@@ -977,7 +1308,7 @@ module Net #:nodoc:
977
1308
  # # example
978
1309
  # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
979
1310
  # p response.status
980
- # puts response.body # body is already read
1311
+ # puts response.body # body is already read in this case
981
1312
  #
982
1313
  # # using block
983
1314
  # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
@@ -1003,9 +1334,9 @@ module Net #:nodoc:
1003
1334
 
1004
1335
 
1005
1336
  # Sends an HTTP request to the HTTP server.
1006
- # This method also sends DATA string if DATA is given.
1337
+ # Also sends a DATA string if +data+ is given.
1007
1338
  #
1008
- # Returns a HTTPResponse object.
1339
+ # Returns a Net::HTTPResponse object.
1009
1340
  #
1010
1341
  # This method never raises Net::* exceptions.
1011
1342
  #
@@ -1017,16 +1348,18 @@ module Net #:nodoc:
1017
1348
  request r, data
1018
1349
  end
1019
1350
 
1020
- # Sends an HTTPRequest object REQUEST to the HTTP server.
1021
- # This method also sends DATA string if REQUEST is a post/put request.
1022
- # Giving DATA for get/head request causes ArgumentError.
1351
+ # Sends an HTTPRequest object +req+ to the HTTP server.
1023
1352
  #
1024
- # When called with a block, yields an HTTPResponse object.
1025
- # The body of this response will not have been read yet;
1026
- # the caller can process it using HTTPResponse#read_body,
1027
- # if desired.
1353
+ # If +req+ is a Net::HTTP::Post or Net::HTTP::Put request containing
1354
+ # data, the data is also sent. Providing data for a Net::HTTP::Head or
1355
+ # Net::HTTP::Get request results in an ArgumentError.
1356
+ #
1357
+ # Returns an HTTPResponse object.
1028
1358
  #
1029
- # Returns a HTTPResponse object.
1359
+ # When called with a block, passes an HTTPResponse object to the block.
1360
+ # The body of the response will not have been read yet;
1361
+ # the block can process it using HTTPResponse#read_body,
1362
+ # if desired.
1030
1363
  #
1031
1364
  # This method never raises Net::* exceptions.
1032
1365
  #
@@ -1038,57 +1371,107 @@ module Net #:nodoc:
1038
1371
  }
1039
1372
  end
1040
1373
  if proxy_user()
1041
- unless use_ssl?
1042
- req.proxy_basic_auth proxy_user(), proxy_pass()
1043
- end
1374
+ req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
1044
1375
  end
1045
-
1046
1376
  req.set_body_internal body
1377
+ res = transport_request(req, &block)
1378
+ if sspi_auth?(res)
1379
+ sspi_auth(req)
1380
+ res = transport_request(req, &block)
1381
+ end
1382
+ res
1383
+ end
1384
+
1385
+ private
1386
+
1387
+ # Executes a request which uses a representation
1388
+ # and returns its body.
1389
+ def send_entity(path, data, initheader, dest, type, &block)
1390
+ res = nil
1391
+ request(type.new(path, initheader), data) {|r|
1392
+ r.read_body dest, &block
1393
+ res = r
1394
+ }
1395
+ res
1396
+ end
1397
+
1398
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
1399
+
1400
+ def transport_request(req)
1401
+ count = 0
1047
1402
  begin
1048
1403
  begin_transport req
1049
- req.exec @socket, @curr_http_version, edit_path(req.path)
1050
- begin
1051
- res = HTTPResponse.read_new(@socket)
1052
- end while res.kind_of?(HTTPContinue)
1053
- res.reading_body(@socket, req.response_body_permitted?) {
1054
- yield res if block_given?
1404
+ res = catch(:response) {
1405
+ req.exec @socket, @curr_http_version, edit_path(req.path)
1406
+ begin
1407
+ res = HTTPResponse.read_new(@socket)
1408
+ res.decode_content = req.decode_content
1409
+ end while res.kind_of?(HTTPContinue)
1410
+
1411
+ res.uri = req.uri
1412
+
1413
+ res.reading_body(@socket, req.response_body_permitted?) {
1414
+ yield res if block_given?
1415
+ }
1416
+ res
1055
1417
  }
1056
- end_transport req, res
1057
- rescue => exception
1418
+ rescue Net::OpenTimeout
1419
+ raise
1420
+ rescue Net::ReadTimeout, IOError, EOFError,
1421
+ Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE,
1422
+ # avoid a dependency on OpenSSL
1423
+ defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
1424
+ Timeout::Error => exception
1425
+ if count == 0 && IDEMPOTENT_METHODS_.include?(req.method)
1426
+ count += 1
1427
+ @socket.close if @socket and not @socket.closed?
1428
+ D "Conn close because of error #{exception}, and retry"
1429
+ retry
1430
+ end
1058
1431
  D "Conn close because of error #{exception}"
1059
1432
  @socket.close if @socket and not @socket.closed?
1060
- raise exception
1433
+ raise
1061
1434
  end
1062
1435
 
1436
+ end_transport req, res
1063
1437
  res
1438
+ rescue => exception
1439
+ D "Conn close because of error #{exception}"
1440
+ @socket.close if @socket and not @socket.closed?
1441
+ raise exception
1064
1442
  end
1065
1443
 
1066
- private
1067
-
1068
1444
  def begin_transport(req)
1069
1445
  if @socket.closed?
1070
1446
  connect
1447
+ elsif @last_communicated && @last_communicated + @keep_alive_timeout < Time.now
1448
+ D 'Conn close because of keep_alive_timeout'
1449
+ @socket.close
1450
+ connect
1071
1451
  end
1072
- if @seems_1_0_server
1073
- req['connection'] ||= 'close'
1074
- end
1452
+
1075
1453
  if not req.response_body_permitted? and @close_on_empty_response
1076
1454
  req['connection'] ||= 'close'
1077
1455
  end
1456
+
1457
+ host = req['host'] || address
1458
+ host = $1 if host =~ /(.*):\d+$/
1459
+ req.update_uri host, port, use_ssl?
1460
+
1078
1461
  req['host'] ||= addr_port()
1079
1462
  end
1080
1463
 
1081
1464
  def end_transport(req, res)
1082
1465
  @curr_http_version = res.http_version
1083
- if not res.body and @close_on_empty_response
1466
+ @last_communicated = nil
1467
+ if @socket.closed?
1468
+ D 'Conn socket closed'
1469
+ elsif not res.body and @close_on_empty_response
1084
1470
  D 'Conn close'
1085
1471
  @socket.close
1086
1472
  elsif keep_alive?(req, res)
1087
1473
  D 'Conn keep-alive'
1088
- if @socket.closed?
1089
- D 'Conn (but seems 1.0 server)'
1090
- @seems_1_0_server = true
1091
- end
1474
+ @last_communicated = Time.now
1092
1475
  else
1093
1476
  D 'Conn close'
1094
1477
  @socket.close
@@ -1096,13 +1479,40 @@ module Net #:nodoc:
1096
1479
  end
1097
1480
 
1098
1481
  def keep_alive?(req, res)
1099
- return false if /close/i =~ req['connection'].to_s
1100
- return false if @seems_1_0_server
1101
- return true if /keep-alive/i =~ res['connection'].to_s
1102
- return false if /close/i =~ res['connection'].to_s
1103
- return true if /keep-alive/i =~ res['proxy-connection'].to_s
1104
- return false if /close/i =~ res['proxy-connection'].to_s
1105
- (@curr_http_version == '1.1')
1482
+ return false if req.connection_close?
1483
+ if @curr_http_version <= '1.0'
1484
+ res.connection_keep_alive?
1485
+ else # HTTP/1.1 or later
1486
+ not res.connection_close?
1487
+ end
1488
+ end
1489
+
1490
+ def sspi_auth?(res)
1491
+ return false unless @sspi_enabled
1492
+ if res.kind_of?(HTTPProxyAuthenticationRequired) and
1493
+ proxy? and res["Proxy-Authenticate"].include?("Negotiate")
1494
+ begin
1495
+ require 'win32/sspi'
1496
+ true
1497
+ rescue LoadError
1498
+ false
1499
+ end
1500
+ else
1501
+ false
1502
+ end
1503
+ end
1504
+
1505
+ def sspi_auth(req)
1506
+ n = Win32::SSPI::NegotiateAuth.new
1507
+ req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
1508
+ # Some versions of ISA will close the connection if this isn't present.
1509
+ req["Connection"] = "Keep-Alive"
1510
+ req["Proxy-Connection"] = "Keep-Alive"
1511
+ res = transport_request(req)
1512
+ authphrase = res["Proxy-Authenticate"] or return res
1513
+ req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
1514
+ rescue => err
1515
+ raise HTTPAuthenticationError.new('HTTP authentication failed', err)
1106
1516
  end
1107
1517
 
1108
1518
  #
@@ -1124,1167 +1534,22 @@ module Net #:nodoc:
1124
1534
  @debug_output << msg
1125
1535
  @debug_output << "\n"
1126
1536
  end
1127
-
1128
1537
  end
1129
1538
 
1130
- HTTPSession = HTTP
1131
-
1132
-
1133
- #
1134
- # Header module.
1135
- #
1136
- # Provides access to @header in the mixed-into class as a hash-like
1137
- # object, except with case-insensitive keys. Also provides
1138
- # methods for accessing commonly-used header values in a more
1139
- # convenient format.
1140
- #
1141
- module HTTPHeader
1142
-
1143
- def initialize_http_header(initheader)
1144
- @header = {}
1145
- return unless initheader
1146
- initheader.each do |key, value|
1147
- warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
1148
- @header[key.downcase] = [value.strip]
1149
- end
1150
- end
1151
-
1152
- def size #:nodoc: obsolete
1153
- @header.size
1154
- end
1155
-
1156
- alias length size #:nodoc: obsolete
1157
-
1158
- # Returns the header field corresponding to the case-insensitive key.
1159
- # For example, a key of "Content-Type" might return "text/html"
1160
- def [](key)
1161
- a = @header[key.downcase] or return nil
1162
- a.join(', ')
1163
- end
1164
-
1165
- # Sets the header field corresponding to the case-insensitive key.
1166
- def []=(key, val)
1167
- unless val
1168
- @header.delete key.downcase
1169
- return val
1170
- end
1171
- @header[key.downcase] = [val]
1172
- end
1173
-
1174
- # [Ruby 1.8.3]
1175
- # Adds header field instead of replace.
1176
- # Second argument +val+ must be a String.
1177
- # See also #[]=, #[] and #get_fields.
1178
- #
1179
- # request.add_field 'X-My-Header', 'a'
1180
- # p request['X-My-Header'] #=> "a"
1181
- # p request.get_fields('X-My-Header') #=> ["a"]
1182
- # request.add_field 'X-My-Header', 'b'
1183
- # p request['X-My-Header'] #=> "a, b"
1184
- # p request.get_fields('X-My-Header') #=> ["a", "b"]
1185
- # request.add_field 'X-My-Header', 'c'
1186
- # p request['X-My-Header'] #=> "a, b, c"
1187
- # p request.get_fields('X-My-Header') #=> ["a", "b", "c"]
1188
- #
1189
- def add_field(key, val)
1190
- if @header.key?(key.downcase)
1191
- @header[key.downcase].push val
1192
- else
1193
- @header[key.downcase] = [val]
1194
- end
1195
- end
1196
-
1197
- # [Ruby 1.8.3]
1198
- # Returns an array of header field strings corresponding to the
1199
- # case-insensitive +key+. This method allows you to get duplicated
1200
- # header fields without any processing. See also #[].
1201
- #
1202
- # p response.get_fields('Set-Cookie')
1203
- # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
1204
- # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
1205
- # p response['Set-Cookie']
1206
- # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
1207
- #
1208
- def get_fields(key)
1209
- return nil unless @header[key.downcase]
1210
- @header[key.downcase].dup
1211
- end
1212
-
1213
- # Returns the header field corresponding to the case-insensitive key.
1214
- # Returns the default value +args+, or the result of the block, or nil,
1215
- # if there's no header field named key. See Hash#fetch
1216
- def fetch(key, *args, &block) #:yield: +key+
1217
- a = @header.fetch(key.downcase, *args, &block)
1218
- a.join(', ')
1219
- end
1220
-
1221
- # Iterates for each header names and values.
1222
- def each_header #:yield: +key+, +value+
1223
- return to_enum(__method__) unless block_given?
1224
- @header.each do |k,va|
1225
- yield k, va.join(', ')
1226
- end
1227
- end
1228
-
1229
- alias each each_header
1230
-
1231
- # Iterates for each header names.
1232
- def each_name(&block) #:yield: +key+
1233
- return to_enum(__method__) unless block_given?
1234
- @header.each_key(&block)
1235
- end
1236
-
1237
- alias each_key each_name
1238
-
1239
- # Iterates for each capitalized header names.
1240
- def each_capitalized_name(&block) #:yield: +key+
1241
- return to_enum(__method__) unless block_given?
1242
- @header.each_key do |k|
1243
- yield capitalize(k)
1244
- end
1245
- end
1246
-
1247
- # Iterates for each header values.
1248
- def each_value #:yield: +value+
1249
- return to_enum(__method__) unless block_given?
1250
- @header.each_value do |va|
1251
- yield va.join(', ')
1252
- end
1253
- end
1254
-
1255
- # Removes a header field.
1256
- def delete(key)
1257
- @header.delete(key.downcase)
1258
- end
1259
-
1260
- # true if +key+ header exists.
1261
- def key?(key)
1262
- @header.key?(key.downcase)
1263
- end
1264
-
1265
- # Returns a Hash consist of header names and values.
1266
- def to_hash
1267
- @header.dup
1268
- end
1269
-
1270
- # As for #each_header, except the keys are provided in capitalized form.
1271
- def each_capitalized
1272
- return to_enum(__method__) unless block_given?
1273
- @header.each do |k,v|
1274
- yield capitalize(k), v.join(', ')
1275
- end
1276
- end
1277
-
1278
- alias canonical_each each_capitalized
1539
+ end
1279
1540
 
1280
- def capitalize(name)
1281
- name.split(/-/).map {|s| s.capitalize }.join('-')
1282
- end
1283
- private :capitalize
1284
-
1285
- # Returns an Array of Range objects which represents Range: header field,
1286
- # or +nil+ if there is no such header.
1287
- def range
1288
- return nil unless @header['range']
1289
- self['Range'].split(/,/).map {|spec|
1290
- m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
1291
- raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
1292
- d1 = m[1].to_i
1293
- d2 = m[2].to_i
1294
- if m[1] and m[2] then d1..d2
1295
- elsif m[1] then d1..-1
1296
- elsif m[2] then -d2..-1
1297
- else
1298
- raise HTTPHeaderSyntaxError, 'range is not specified'
1299
- end
1300
- }
1301
- end
1302
-
1303
- # Set Range: header from Range (arg r) or beginning index and
1304
- # length from it (arg idx&len).
1305
- #
1306
- # req.range = (0..1023)
1307
- # req.set_range 0, 1023
1308
- #
1309
- def set_range(r, e = nil)
1310
- unless r
1311
- @header.delete 'range'
1312
- return r
1313
- end
1314
- r = (r...r+e) if e
1315
- case r
1316
- when Numeric
1317
- n = r.to_i
1318
- rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
1319
- when Range
1320
- first = r.first
1321
- last = r.last
1322
- last -= 1 if r.exclude_end?
1323
- if last == -1
1324
- rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
1325
- else
1326
- raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
1327
- raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
1328
- raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
1329
- rangestr = "#{first}-#{last}"
1330
- end
1331
- else
1332
- raise TypeError, 'Range/Integer is required'
1333
- end
1334
- @header['range'] = ["bytes=#{rangestr}"]
1335
- r
1336
- end
1337
-
1338
- alias range= set_range
1541
+ require 'net/http/exceptions'
1339
1542
 
1340
- # Returns an Integer object which represents the Content-Length: header field
1341
- # or +nil+ if that field is not provided.
1342
- def content_length
1343
- return nil unless key?('Content-Length')
1344
- len = self['Content-Length'].slice(/\d+/) or
1345
- raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
1346
- len.to_i
1347
- end
1348
-
1349
- def content_length=(len)
1350
- unless len
1351
- @header.delete 'content-length'
1352
- return nil
1353
- end
1354
- @header['content-length'] = [len.to_i.to_s]
1355
- end
1356
-
1357
- # Returns "true" if the "transfer-encoding" header is present and
1358
- # set to "chunked". This is an HTTP/1.1 feature, allowing the
1359
- # the content to be sent in "chunks" without at the outset
1360
- # stating the entire content length.
1361
- def chunked?
1362
- return false unless @header['transfer-encoding']
1363
- field = self['Transfer-Encoding']
1364
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
1365
- end
1366
-
1367
- # Returns a Range object which represents Content-Range: header field.
1368
- # This indicates, for a partial entity body, where this fragment
1369
- # fits inside the full entity body, as range of byte offsets.
1370
- def content_range
1371
- return nil unless @header['content-range']
1372
- m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
1373
- raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
1374
- m[1].to_i .. m[2].to_i
1375
- end
1376
-
1377
- # The length of the range represented in Content-Range: header.
1378
- def range_length
1379
- r = content_range() or return nil
1380
- r.end - r.begin + 1
1381
- end
1382
-
1383
- # Returns a content type string such as "text/html".
1384
- # This method returns nil if Content-Type: header field does not exist.
1385
- def content_type
1386
- return nil unless main_type()
1387
- if sub_type()
1388
- then "#{main_type()}/#{sub_type()}"
1389
- else main_type()
1390
- end
1391
- end
1392
-
1393
- # Returns a content type string such as "text".
1394
- # This method returns nil if Content-Type: header field does not exist.
1395
- def main_type
1396
- return nil unless @header['content-type']
1397
- self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
1398
- end
1399
-
1400
- # Returns a content type string such as "html".
1401
- # This method returns nil if Content-Type: header field does not exist
1402
- # or sub-type is not given (e.g. "Content-Type: text").
1403
- def sub_type
1404
- return nil unless @header['content-type']
1405
- main, sub = *self['Content-Type'].split(';').first.to_s.split('/')
1406
- return nil unless sub
1407
- sub.strip
1408
- end
1409
-
1410
- # Returns content type parameters as a Hash as like
1411
- # {"charset" => "iso-2022-jp"}.
1412
- def type_params
1413
- result = {}
1414
- list = self['Content-Type'].to_s.split(';')
1415
- list.shift
1416
- list.each do |param|
1417
- k, v = *param.split('=', 2)
1418
- result[k.strip] = v.strip
1419
- end
1420
- result
1421
- end
1422
-
1423
- # Set Content-Type: header field by +type+ and +params+.
1424
- # +type+ must be a String, +params+ must be a Hash.
1425
- def set_content_type(type, params = {})
1426
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
1427
- end
1428
-
1429
- alias content_type= set_content_type
1543
+ require 'net/http/header'
1430
1544
 
1431
- # Set header fields and a body from HTML form data.
1432
- # +params+ should be a Hash containing HTML form data.
1433
- # Optional argument +sep+ means data record separator.
1434
- #
1435
- # This method also set Content-Type: header field to
1436
- # application/x-www-form-urlencoded.
1437
- def set_form_data(params, sep = '&')
1438
- self.body = params.map {|k,v| "#{urlencode(k.to_s)}=#{urlencode(v.to_s)}" }.join(sep)
1439
- self.content_type = 'application/x-www-form-urlencoded'
1440
- end
1545
+ require 'net/http/generic_request'
1546
+ require 'net/http/request'
1547
+ require 'net/http/requests'
1441
1548
 
1442
- alias form_data= set_form_data
1443
-
1444
- def urlencode(str)
1445
- str.gsub(/[^a-zA-Z0-9_\.\-]/n) {|s| sprintf('%%%02x', s[0]) }
1446
- end
1447
- private :urlencode
1549
+ require 'net/http/response'
1550
+ require 'net/http/responses'
1448
1551
 
1449
- # Set the Authorization: header for "Basic" authorization.
1450
- def basic_auth(account, password)
1451
- @header['authorization'] = [basic_encode(account, password)]
1452
- end
1453
-
1454
- # Set Proxy-Authorization: header for "Basic" authorization.
1455
- def proxy_basic_auth(account, password)
1456
- @header['proxy-authorization'] = [basic_encode(account, password)]
1457
- end
1458
-
1459
- def basic_encode(account, password)
1460
- 'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n")
1461
- end
1462
- private :basic_encode
1463
-
1464
- end
1465
-
1466
-
1467
- #
1468
- # Parent of HTTPRequest class. Do not use this directly; use
1469
- # a subclass of HTTPRequest.
1470
- #
1471
- # Mixes in the HTTPHeader module.
1472
- #
1473
- class HTTPGenericRequest
1474
-
1475
- include HTTPHeader
1476
-
1477
- BUFSIZE = 16*1024
1478
-
1479
- def initialize(m, reqbody, resbody, path, initheader = nil)
1480
- @method = m
1481
- @request_has_body = reqbody
1482
- @response_has_body = resbody
1483
- raise ArgumentError, "HTTP request path is empty" if path.empty?
1484
- @path = path
1485
- initialize_http_header initheader
1486
- self['Accept'] ||= '*/*'
1487
- @body = nil
1488
- @body_stream = nil
1489
- end
1490
-
1491
- attr_reader :method
1492
- attr_reader :path
1493
-
1494
- def inspect
1495
- "\#<#{self.class} #{@method}>"
1496
- end
1497
-
1498
- def request_body_permitted?
1499
- @request_has_body
1500
- end
1501
-
1502
- def response_body_permitted?
1503
- @response_has_body
1504
- end
1505
-
1506
- def body_exist?
1507
- warn "Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?" if $VERBOSE
1508
- response_body_permitted?
1509
- end
1510
-
1511
- attr_reader :body
1512
-
1513
- def body=(str)
1514
- @body = str
1515
- @body_stream = nil
1516
- str
1517
- end
1518
-
1519
- attr_reader :body_stream
1520
-
1521
- def body_stream=(input)
1522
- @body = nil
1523
- @body_stream = input
1524
- input
1525
- end
1526
-
1527
- def set_body_internal(str) #:nodoc: internal use only
1528
- raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
1529
- self.body = str if str
1530
- end
1531
-
1532
- #
1533
- # write
1534
- #
1535
-
1536
- def exec(sock, ver, path) #:nodoc: internal use only
1537
- if @body
1538
- send_request_with_body sock, ver, path, @body
1539
- elsif @body_stream
1540
- send_request_with_body_stream sock, ver, path, @body_stream
1541
- else
1542
- write_header sock, ver, path
1543
- end
1544
- end
1545
-
1546
- private
1547
-
1548
- def send_request_with_body(sock, ver, path, body)
1549
- self.content_length = body.length
1550
- delete 'Transfer-Encoding'
1551
- supply_default_content_type
1552
- write_header sock, ver, path
1553
- sock.write body
1554
- end
1555
-
1556
- def send_request_with_body_stream(sock, ver, path, f)
1557
- unless content_length() or chunked?
1558
- raise ArgumentError,
1559
- "Content-Length not given and Transfer-Encoding is not `chunked'"
1560
- end
1561
- supply_default_content_type
1562
- write_header sock, ver, path
1563
- if chunked?
1564
- while s = f.read(BUFSIZE)
1565
- sock.write(sprintf("%x\r\n", s.length) << s << "\r\n")
1566
- end
1567
- sock.write "0\r\n\r\n"
1568
- else
1569
- while s = f.read(BUFSIZE)
1570
- sock.write s
1571
- end
1572
- end
1573
- end
1574
-
1575
- def supply_default_content_type
1576
- return if content_type()
1577
- warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE
1578
- set_content_type 'application/x-www-form-urlencoded'
1579
- end
1580
-
1581
- def write_header(sock, ver, path)
1582
- buf = "#{@method} #{path} HTTP/#{ver}\r\n"
1583
- each_capitalized do |k,v|
1584
- buf << "#{k}: #{v}\r\n"
1585
- end
1586
- buf << "\r\n"
1587
- sock.write buf
1588
- end
1589
-
1590
- end
1591
-
1592
-
1593
- #
1594
- # HTTP request class. This class wraps request header and entity path.
1595
- # You *must* use its subclass, Net::HTTP::Get, Post, Head.
1596
- #
1597
- class HTTPRequest < HTTPGenericRequest
1598
-
1599
- # Creates HTTP request object.
1600
- def initialize(path, initheader = nil)
1601
- super self.class::METHOD,
1602
- self.class::REQUEST_HAS_BODY,
1603
- self.class::RESPONSE_HAS_BODY,
1604
- path, initheader
1605
- end
1606
- end
1607
-
1608
-
1609
- class HTTP # reopen
1610
- #
1611
- # HTTP 1.1 methods --- RFC2616
1612
- #
1613
-
1614
- class Get < HTTPRequest
1615
- METHOD = 'GET'
1616
- REQUEST_HAS_BODY = false
1617
- RESPONSE_HAS_BODY = true
1618
- end
1619
-
1620
- class Head < HTTPRequest
1621
- METHOD = 'HEAD'
1622
- REQUEST_HAS_BODY = false
1623
- RESPONSE_HAS_BODY = false
1624
- end
1625
-
1626
- class Post < HTTPRequest
1627
- METHOD = 'POST'
1628
- REQUEST_HAS_BODY = true
1629
- RESPONSE_HAS_BODY = true
1630
- end
1631
-
1632
- class Put < HTTPRequest
1633
- METHOD = 'PUT'
1634
- REQUEST_HAS_BODY = true
1635
- RESPONSE_HAS_BODY = true
1636
- end
1637
-
1638
- class Delete < HTTPRequest
1639
- METHOD = 'DELETE'
1640
- REQUEST_HAS_BODY = false
1641
- RESPONSE_HAS_BODY = true
1642
- end
1643
-
1644
- class Options < HTTPRequest
1645
- METHOD = 'OPTIONS'
1646
- REQUEST_HAS_BODY = false
1647
- RESPONSE_HAS_BODY = false
1648
- end
1649
-
1650
- class Trace < HTTPRequest
1651
- METHOD = 'TRACE'
1652
- REQUEST_HAS_BODY = false
1653
- RESPONSE_HAS_BODY = true
1654
- end
1655
-
1656
- #
1657
- # WebDAV methods --- RFC2518
1658
- #
1659
-
1660
- class Propfind < HTTPRequest
1661
- METHOD = 'PROPFIND'
1662
- REQUEST_HAS_BODY = true
1663
- RESPONSE_HAS_BODY = true
1664
- end
1665
-
1666
- class Proppatch < HTTPRequest
1667
- METHOD = 'PROPPATCH'
1668
- REQUEST_HAS_BODY = true
1669
- RESPONSE_HAS_BODY = true
1670
- end
1671
-
1672
- class Mkcol < HTTPRequest
1673
- METHOD = 'MKCOL'
1674
- REQUEST_HAS_BODY = true
1675
- RESPONSE_HAS_BODY = true
1676
- end
1677
-
1678
- class Copy < HTTPRequest
1679
- METHOD = 'COPY'
1680
- REQUEST_HAS_BODY = false
1681
- RESPONSE_HAS_BODY = true
1682
- end
1683
-
1684
- class Move < HTTPRequest
1685
- METHOD = 'MOVE'
1686
- REQUEST_HAS_BODY = false
1687
- RESPONSE_HAS_BODY = true
1688
- end
1689
-
1690
- class Lock < HTTPRequest
1691
- METHOD = 'LOCK'
1692
- REQUEST_HAS_BODY = true
1693
- RESPONSE_HAS_BODY = true
1694
- end
1695
-
1696
- class Unlock < HTTPRequest
1697
- METHOD = 'UNLOCK'
1698
- REQUEST_HAS_BODY = true
1699
- RESPONSE_HAS_BODY = true
1700
- end
1701
- end
1702
-
1703
-
1704
- ###
1705
- ### Response
1706
- ###
1707
-
1708
- # HTTP exception class.
1709
- # You must use its subclasses.
1710
- module HTTPExceptions
1711
- def initialize(msg, res) #:nodoc:
1712
- super msg
1713
- @response = res
1714
- end
1715
- attr_reader :response
1716
- alias data response #:nodoc: obsolete
1717
- end
1718
- class HTTPError < ProtocolError
1719
- include HTTPExceptions
1720
- end
1721
- class HTTPRetriableError < ProtoRetriableError
1722
- include HTTPExceptions
1723
- end
1724
- class HTTPServerException < ProtoServerError
1725
- # We cannot use the name "HTTPServerError", it is the name of the response.
1726
- include HTTPExceptions
1727
- end
1728
- class HTTPFatalError < ProtoFatalError
1729
- include HTTPExceptions
1730
- end
1731
-
1732
-
1733
- # HTTP response class. This class wraps response header and entity.
1734
- # Mixes in the HTTPHeader module, which provides access to response
1735
- # header values both via hash-like methods and individual readers.
1736
- # Note that each possible HTTP response code defines its own
1737
- # HTTPResponse subclass. These are listed below.
1738
- # All classes are
1739
- # defined under the Net module. Indentation indicates inheritance.
1740
- #
1741
- # xxx HTTPResponse
1742
- #
1743
- # 1xx HTTPInformation
1744
- # 100 HTTPContinue
1745
- # 101 HTTPSwitchProtocol
1746
- #
1747
- # 2xx HTTPSuccess
1748
- # 200 HTTPOK
1749
- # 201 HTTPCreated
1750
- # 202 HTTPAccepted
1751
- # 203 HTTPNonAuthoritativeInformation
1752
- # 204 HTTPNoContent
1753
- # 205 HTTPResetContent
1754
- # 206 HTTPPartialContent
1755
- #
1756
- # 3xx HTTPRedirection
1757
- # 300 HTTPMultipleChoice
1758
- # 301 HTTPMovedPermanently
1759
- # 302 HTTPFound
1760
- # 303 HTTPSeeOther
1761
- # 304 HTTPNotModified
1762
- # 305 HTTPUseProxy
1763
- # 307 HTTPTemporaryRedirect
1764
- #
1765
- # 4xx HTTPClientError
1766
- # 400 HTTPBadRequest
1767
- # 401 HTTPUnauthorized
1768
- # 402 HTTPPaymentRequired
1769
- # 403 HTTPForbidden
1770
- # 404 HTTPNotFound
1771
- # 405 HTTPMethodNotAllowed
1772
- # 406 HTTPNotAcceptable
1773
- # 407 HTTPProxyAuthenticationRequired
1774
- # 408 HTTPRequestTimeOut
1775
- # 409 HTTPConflict
1776
- # 410 HTTPGone
1777
- # 411 HTTPLengthRequired
1778
- # 412 HTTPPreconditionFailed
1779
- # 413 HTTPRequestEntityTooLarge
1780
- # 414 HTTPRequestURITooLong
1781
- # 415 HTTPUnsupportedMediaType
1782
- # 416 HTTPRequestedRangeNotSatisfiable
1783
- # 417 HTTPExpectationFailed
1784
- #
1785
- # 5xx HTTPServerError
1786
- # 500 HTTPInternalServerError
1787
- # 501 HTTPNotImplemented
1788
- # 502 HTTPBadGateway
1789
- # 503 HTTPServiceUnavailable
1790
- # 504 HTTPGatewayTimeOut
1791
- # 505 HTTPVersionNotSupported
1792
- #
1793
- # xxx HTTPUnknownResponse
1794
- #
1795
- class HTTPResponse
1796
- # true if the response has body.
1797
- def HTTPResponse.body_permitted?
1798
- self::HAS_BODY
1799
- end
1800
-
1801
- def HTTPResponse.exception_type # :nodoc: internal use only
1802
- self::EXCEPTION_TYPE
1803
- end
1804
- end # reopened after
1805
-
1806
- # :stopdoc:
1807
-
1808
- class HTTPUnknownResponse < HTTPResponse
1809
- HAS_BODY = true
1810
- EXCEPTION_TYPE = HTTPError
1811
- end
1812
- class HTTPInformation < HTTPResponse # 1xx
1813
- HAS_BODY = false
1814
- EXCEPTION_TYPE = HTTPError
1815
- end
1816
- class HTTPSuccess < HTTPResponse # 2xx
1817
- HAS_BODY = true
1818
- EXCEPTION_TYPE = HTTPError
1819
- end
1820
- class HTTPRedirection < HTTPResponse # 3xx
1821
- HAS_BODY = true
1822
- EXCEPTION_TYPE = HTTPRetriableError
1823
- end
1824
- class HTTPClientError < HTTPResponse # 4xx
1825
- HAS_BODY = true
1826
- EXCEPTION_TYPE = HTTPServerException # for backward compatibility
1827
- end
1828
- class HTTPServerError < HTTPResponse # 5xx
1829
- HAS_BODY = true
1830
- EXCEPTION_TYPE = HTTPFatalError # for backward compatibility
1831
- end
1832
-
1833
- class HTTPContinue < HTTPInformation # 100
1834
- HAS_BODY = false
1835
- end
1836
- class HTTPSwitchProtocol < HTTPInformation # 101
1837
- HAS_BODY = false
1838
- end
1839
-
1840
- class HTTPOK < HTTPSuccess # 200
1841
- HAS_BODY = true
1842
- end
1843
- class HTTPCreated < HTTPSuccess # 201
1844
- HAS_BODY = true
1845
- end
1846
- class HTTPAccepted < HTTPSuccess # 202
1847
- HAS_BODY = true
1848
- end
1849
- class HTTPNonAuthoritativeInformation < HTTPSuccess # 203
1850
- HAS_BODY = true
1851
- end
1852
- class HTTPNoContent < HTTPSuccess # 204
1853
- HAS_BODY = false
1854
- end
1855
- class HTTPResetContent < HTTPSuccess # 205
1856
- HAS_BODY = false
1857
- end
1858
- class HTTPPartialContent < HTTPSuccess # 206
1859
- HAS_BODY = true
1860
- end
1861
-
1862
- class HTTPMultipleChoice < HTTPRedirection # 300
1863
- HAS_BODY = true
1864
- end
1865
- class HTTPMovedPermanently < HTTPRedirection # 301
1866
- HAS_BODY = true
1867
- end
1868
- class HTTPFound < HTTPRedirection # 302
1869
- HAS_BODY = true
1870
- end
1871
- HTTPMovedTemporarily = HTTPFound
1872
- class HTTPSeeOther < HTTPRedirection # 303
1873
- HAS_BODY = true
1874
- end
1875
- class HTTPNotModified < HTTPRedirection # 304
1876
- HAS_BODY = false
1877
- end
1878
- class HTTPUseProxy < HTTPRedirection # 305
1879
- HAS_BODY = false
1880
- end
1881
- # 306 unused
1882
- class HTTPTemporaryRedirect < HTTPRedirection # 307
1883
- HAS_BODY = true
1884
- end
1885
-
1886
- class HTTPBadRequest < HTTPClientError # 400
1887
- HAS_BODY = true
1888
- end
1889
- class HTTPUnauthorized < HTTPClientError # 401
1890
- HAS_BODY = true
1891
- end
1892
- class HTTPPaymentRequired < HTTPClientError # 402
1893
- HAS_BODY = true
1894
- end
1895
- class HTTPForbidden < HTTPClientError # 403
1896
- HAS_BODY = true
1897
- end
1898
- class HTTPNotFound < HTTPClientError # 404
1899
- HAS_BODY = true
1900
- end
1901
- class HTTPMethodNotAllowed < HTTPClientError # 405
1902
- HAS_BODY = true
1903
- end
1904
- class HTTPNotAcceptable < HTTPClientError # 406
1905
- HAS_BODY = true
1906
- end
1907
- class HTTPProxyAuthenticationRequired < HTTPClientError # 407
1908
- HAS_BODY = true
1909
- end
1910
- class HTTPRequestTimeOut < HTTPClientError # 408
1911
- HAS_BODY = true
1912
- end
1913
- class HTTPConflict < HTTPClientError # 409
1914
- HAS_BODY = true
1915
- end
1916
- class HTTPGone < HTTPClientError # 410
1917
- HAS_BODY = true
1918
- end
1919
- class HTTPLengthRequired < HTTPClientError # 411
1920
- HAS_BODY = true
1921
- end
1922
- class HTTPPreconditionFailed < HTTPClientError # 412
1923
- HAS_BODY = true
1924
- end
1925
- class HTTPRequestEntityTooLarge < HTTPClientError # 413
1926
- HAS_BODY = true
1927
- end
1928
- class HTTPRequestURITooLong < HTTPClientError # 414
1929
- HAS_BODY = true
1930
- end
1931
- HTTPRequestURITooLarge = HTTPRequestURITooLong
1932
- class HTTPUnsupportedMediaType < HTTPClientError # 415
1933
- HAS_BODY = true
1934
- end
1935
- class HTTPRequestedRangeNotSatisfiable < HTTPClientError # 416
1936
- HAS_BODY = true
1937
- end
1938
- class HTTPExpectationFailed < HTTPClientError # 417
1939
- HAS_BODY = true
1940
- end
1941
-
1942
- class HTTPInternalServerError < HTTPServerError # 500
1943
- HAS_BODY = true
1944
- end
1945
- class HTTPNotImplemented < HTTPServerError # 501
1946
- HAS_BODY = true
1947
- end
1948
- class HTTPBadGateway < HTTPServerError # 502
1949
- HAS_BODY = true
1950
- end
1951
- class HTTPServiceUnavailable < HTTPServerError # 503
1952
- HAS_BODY = true
1953
- end
1954
- class HTTPGatewayTimeOut < HTTPServerError # 504
1955
- HAS_BODY = true
1956
- end
1957
- class HTTPVersionNotSupported < HTTPServerError # 505
1958
- HAS_BODY = true
1959
- end
1960
-
1961
- # :startdoc:
1962
-
1963
-
1964
- class HTTPResponse # reopen
1965
-
1966
- CODE_CLASS_TO_OBJ = {
1967
- '1' => HTTPInformation,
1968
- '2' => HTTPSuccess,
1969
- '3' => HTTPRedirection,
1970
- '4' => HTTPClientError,
1971
- '5' => HTTPServerError
1972
- }
1973
- CODE_TO_OBJ = {
1974
- '100' => HTTPContinue,
1975
- '101' => HTTPSwitchProtocol,
1976
-
1977
- '200' => HTTPOK,
1978
- '201' => HTTPCreated,
1979
- '202' => HTTPAccepted,
1980
- '203' => HTTPNonAuthoritativeInformation,
1981
- '204' => HTTPNoContent,
1982
- '205' => HTTPResetContent,
1983
- '206' => HTTPPartialContent,
1984
-
1985
- '300' => HTTPMultipleChoice,
1986
- '301' => HTTPMovedPermanently,
1987
- '302' => HTTPFound,
1988
- '303' => HTTPSeeOther,
1989
- '304' => HTTPNotModified,
1990
- '305' => HTTPUseProxy,
1991
- '307' => HTTPTemporaryRedirect,
1992
-
1993
- '400' => HTTPBadRequest,
1994
- '401' => HTTPUnauthorized,
1995
- '402' => HTTPPaymentRequired,
1996
- '403' => HTTPForbidden,
1997
- '404' => HTTPNotFound,
1998
- '405' => HTTPMethodNotAllowed,
1999
- '406' => HTTPNotAcceptable,
2000
- '407' => HTTPProxyAuthenticationRequired,
2001
- '408' => HTTPRequestTimeOut,
2002
- '409' => HTTPConflict,
2003
- '410' => HTTPGone,
2004
- '411' => HTTPLengthRequired,
2005
- '412' => HTTPPreconditionFailed,
2006
- '413' => HTTPRequestEntityTooLarge,
2007
- '414' => HTTPRequestURITooLong,
2008
- '415' => HTTPUnsupportedMediaType,
2009
- '416' => HTTPRequestedRangeNotSatisfiable,
2010
- '417' => HTTPExpectationFailed,
2011
-
2012
- '500' => HTTPInternalServerError,
2013
- '501' => HTTPNotImplemented,
2014
- '502' => HTTPBadGateway,
2015
- '503' => HTTPServiceUnavailable,
2016
- '504' => HTTPGatewayTimeOut,
2017
- '505' => HTTPVersionNotSupported
2018
- }
2019
-
2020
- class << HTTPResponse
2021
- def read_new(sock) #:nodoc: internal use only
2022
- httpv, code, msg = read_status_line(sock)
2023
- res = response_class(code).new(httpv, code, msg)
2024
- each_response_header(sock) do |k,v|
2025
- res.add_field k, v
2026
- end
2027
- res
2028
- end
2029
-
2030
- private
2031
-
2032
- def read_status_line(sock)
2033
- str = sock.readline
2034
- m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)\s*(.*)\z/in.match(str) or
2035
- raise HTTPBadResponse, "wrong status line: #{str.dump}"
2036
- m.captures
2037
- end
2038
-
2039
- def response_class(code)
2040
- CODE_TO_OBJ[code] or
2041
- CODE_CLASS_TO_OBJ[code[0,1]] or
2042
- HTTPUnknownResponse
2043
- end
2044
-
2045
- def each_response_header(sock)
2046
- while true
2047
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
2048
- break if line.empty?
2049
- m = /\A([^:]+):\s*/.match(line) or
2050
- raise HTTPBadResponse, 'wrong header line format'
2051
- yield m[1], m.post_match
2052
- end
2053
- end
2054
- end
2055
-
2056
- # next is to fix bug in RDoc, where the private inside class << self
2057
- # spills out.
2058
- public
2059
-
2060
- include HTTPHeader
2061
-
2062
- def initialize(httpv, code, msg) #:nodoc: internal use only
2063
- @http_version = httpv
2064
- @code = code
2065
- @message = msg
2066
- initialize_http_header nil
2067
- @body = nil
2068
- @read = false
2069
- end
2070
-
2071
- # The HTTP version supported by the server.
2072
- attr_reader :http_version
2073
-
2074
- # HTTP result code string. For example, '302'. You can also
2075
- # determine the response type by which response subclass the
2076
- # response object is an instance of.
2077
- attr_reader :code
2078
-
2079
- # HTTP result message. For example, 'Not Found'.
2080
- attr_reader :message
2081
- alias msg message # :nodoc: obsolete
2082
-
2083
- def inspect
2084
- "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
2085
- end
2086
-
2087
- # For backward compatibility.
2088
- # To allow Net::HTTP 1.1 style assignment
2089
- # e.g.
2090
- # response, body = Net::HTTP.get(....)
2091
- #
2092
- def to_ary
2093
- warn "net/http.rb: warning: Net::HTTP v1.1 style assignment found at #{caller(1)[0]}; use `response = http.get(...)' instead." if $VERBOSE
2094
- res = self.dup
2095
- class << res
2096
- undef to_ary
2097
- end
2098
- [res, res.body]
2099
- end
2100
-
2101
- #
2102
- # response <-> exception relationship
2103
- #
2104
-
2105
- def code_type #:nodoc:
2106
- self.class
2107
- end
2108
-
2109
- def error! #:nodoc:
2110
- raise error_type().new(@code + ' ' + @message.dump, self)
2111
- end
2112
-
2113
- def error_type #:nodoc:
2114
- self.class::EXCEPTION_TYPE
2115
- end
2116
-
2117
- # Raises HTTP error if the response is not 2xx.
2118
- def value
2119
- error! unless self.kind_of?(HTTPSuccess)
2120
- end
2121
-
2122
- #
2123
- # header (for backward compatibility only; DO NOT USE)
2124
- #
2125
-
2126
- def response #:nodoc:
2127
- warn "#{caller(1)[0]}: warning: HTTPResponse#response is obsolete" if $VERBOSE
2128
- self
2129
- end
2130
-
2131
- def header #:nodoc:
2132
- warn "#{caller(1)[0]}: warning: HTTPResponse#header is obsolete" if $VERBOSE
2133
- self
2134
- end
2135
-
2136
- def read_header #:nodoc:
2137
- warn "#{caller(1)[0]}: warning: HTTPResponse#read_header is obsolete" if $VERBOSE
2138
- self
2139
- end
2140
-
2141
- #
2142
- # body
2143
- #
2144
-
2145
- def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only
2146
- @socket = sock
2147
- @body_exist = reqmethodallowbody && self.class.body_permitted?
2148
- begin
2149
- yield
2150
- self.body # ensure to read body
2151
- ensure
2152
- @socket = nil
2153
- end
2154
- end
2155
-
2156
- # Gets entity body. If the block given, yields it to +block+.
2157
- # The body is provided in fragments, as it is read in from the socket.
2158
- #
2159
- # Calling this method a second or subsequent time will return the
2160
- # already read string.
2161
- #
2162
- # http.request_get('/index.html') {|res|
2163
- # puts res.read_body
2164
- # }
2165
- #
2166
- # http.request_get('/index.html') {|res|
2167
- # p res.read_body.object_id # 538149362
2168
- # p res.read_body.object_id # 538149362
2169
- # }
2170
- #
2171
- # # using iterator
2172
- # http.request_get('/index.html') {|res|
2173
- # res.read_body do |segment|
2174
- # print segment
2175
- # end
2176
- # }
2177
- #
2178
- def read_body(dest = nil, &block)
2179
- if @read
2180
- raise IOError, "#{self.class}\#read_body called twice" if dest or block
2181
- return @body
2182
- end
2183
- to = procdest(dest, block)
2184
- stream_check
2185
- if @body_exist
2186
- read_body_0 to
2187
- @body = to
2188
- else
2189
- @body = nil
2190
- end
2191
- @read = true
2192
-
2193
- @body
2194
- end
2195
-
2196
- # Returns the entity body.
2197
- #
2198
- # Calling this method a second or subsequent time will return the
2199
- # already read string.
2200
- #
2201
- # http.request_get('/index.html') {|res|
2202
- # puts res.body
2203
- # }
2204
- #
2205
- # http.request_get('/index.html') {|res|
2206
- # p res.body.object_id # 538149362
2207
- # p res.body.object_id # 538149362
2208
- # }
2209
- #
2210
- def body
2211
- read_body()
2212
- end
2213
-
2214
- alias entity body #:nodoc: obsolete
2215
-
2216
- private
2217
-
2218
- def read_body_0(dest)
2219
- if chunked?
2220
- read_chunked dest
2221
- return
2222
- end
2223
- clen = content_length()
2224
- if clen
2225
- @socket.read clen, dest, true # ignore EOF
2226
- return
2227
- end
2228
- clen = range_length()
2229
- if clen
2230
- @socket.read clen, dest
2231
- return
2232
- end
2233
- @socket.read_all dest
2234
- end
2235
-
2236
- def read_chunked(dest)
2237
- len = nil
2238
- total = 0
2239
- while true
2240
- line = @socket.readline
2241
- hexlen = line.slice(/[0-9a-fA-F]+/) or
2242
- raise HTTPBadResponse, "wrong chunk size line: #{line}"
2243
- len = hexlen.hex
2244
- break if len == 0
2245
- @socket.read len, dest; total += len
2246
- @socket.read 2 # \r\n
2247
- end
2248
- until @socket.readline.empty?
2249
- # none
2250
- end
2251
- end
2252
-
2253
- def stream_check
2254
- raise IOError, 'attempt to read body out of block' if @socket.closed?
2255
- end
2256
-
2257
- def procdest(dest, block)
2258
- raise ArgumentError, 'both arg and block given for HTTP method' \
2259
- if dest and block
2260
- if block
2261
- ReadAdapter.new(block)
2262
- else
2263
- dest || ''
2264
- end
2265
- end
2266
-
2267
- end
2268
-
2269
-
2270
- # :enddoc:
2271
-
2272
- #--
2273
- # for backward compatibility
2274
- class HTTP
2275
- ProxyMod = ProxyDelta
2276
- end
2277
- module NetPrivate
2278
- HTTPRequest = ::Net::HTTPRequest
2279
- end
1552
+ require 'net/http/proxy_delta'
2280
1553
 
2281
- HTTPInformationCode = HTTPInformation
2282
- HTTPSuccessCode = HTTPSuccess
2283
- HTTPRedirectionCode = HTTPRedirection
2284
- HTTPRetriableCode = HTTPRedirection
2285
- HTTPClientErrorCode = HTTPClientError
2286
- HTTPFatalErrorCode = HTTPClientError
2287
- HTTPServerErrorCode = HTTPServerError
2288
- HTTPResponceReceiver = HTTPResponse
1554
+ require 'net/http/backward'
2289
1555
 
2290
- end # module Net