rubysl-net-http 1.0.1 → 2.0.4

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