http_request.rb 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. data/Changelog +3 -0
  2. data/README.rdoc +1 -1
  3. data/lib/http_request.rb +522 -522
  4. metadata +2 -2
data/Changelog CHANGED
@@ -1,3 +1,6 @@
1
+ v1.1.9
2
+ * fixed parameters when uploading files (it's double escaped)
3
+
1
4
  v1.1.8
2
5
  * fixed parameters when uploading files (it's double escaped)
3
6
 
data/README.rdoc CHANGED
@@ -227,4 +227,4 @@ download multiple files from a directory
227
227
  bug fixing, testing and testing...
228
228
 
229
229
  == LATEST VERSION
230
- 1.1.8
230
+ 1.1.9
data/lib/http_request.rb CHANGED
@@ -11,9 +11,9 @@
11
11
  #
12
12
  # == Version
13
13
  #
14
- # v1.1.7
14
+ # v1.1.9
15
15
  #
16
- # Last Change: 18 Aug, 2010
16
+ # Last Change: 13 Sep, 2010
17
17
  #
18
18
  # == Author
19
19
  #
@@ -29,514 +29,514 @@ require 'digest/md5'
29
29
  require 'stringio'
30
30
 
31
31
  class HttpRequest
32
- include Singleton
33
- class << self
34
- # version
35
- VERSION = '1.1.7'.freeze
36
- def version;VERSION;end
37
-
38
- # avaiabled http methods
39
- def http_methods
40
- %w{get head post put proppatch lock unlock options propfind delete move copy mkcol trace}
41
- end
42
-
43
- # return data with or without block
44
- def data(response, &block)
45
- response.url = @@__url if defined? @@__url
46
- block_given? ? block.call(response) : response
47
- end
48
-
49
- # update cookies
50
- def update_cookies(response)
51
- return unless response.header['set-cookie']
52
- response.get_fields('set-cookie').each {|k|
53
- k, v = k.split(';')[0].split('=')
54
- @@__cookies[k] = v
55
- }
56
- end
57
-
58
- # return cookies
59
- def cookies
60
- @@__cookies
61
- end
62
-
63
- # check the http resource whether or not available
64
- def available?(url, timeout = 5)
65
- timeout(timeout) {
66
- u = URI(url)
67
- s = TCPSocket.new(u.host, u.port)
68
- s.close
69
- }
70
- return true
71
- rescue Exception => e
72
- return false
73
- end
74
- end
75
-
76
- def data(response, &block)
77
- self.class.data(response, &block)
78
- end
79
-
80
- # send request by some given parameters
81
- def request(method, options, &block)
82
-
83
- # parse the @options
84
- parse_options(method, options)
85
-
86
- # parse and merge for the options[:parameters]
87
- parse_parameters
88
-
89
- # send http request and get the response
90
- response = send_request_and_get_response
91
-
92
- return data(response, &block) unless @options[:redirect]
93
-
94
- # redirect?
95
- process_redirection response, &block
96
- end
97
-
98
- # catch all available http requests
99
- def self.method_missing(method_name, *options, &block)
100
- options = if options.size.eql? 2
101
- options.last.merge({:url => options.first})
102
- else
103
- options.first
104
- end
105
- @@redirect_times = 0
106
- # we need to retrieve the cookies from last http response before reset cookies if it's a Net::HTTPResponse
107
- options[:cookies] = options[:cookies].cookies if options[:cookies].is_a? Net::HTTPResponse
108
- @@__cookies = {}
109
- method_name = method_name.to_s.downcase
110
- raise NoHttpMethodException, "No such http method can be called: #{method_name}" unless self.http_methods.include?(method_name)
111
- self.instance.request(method_name, options, &block)
112
- end
113
-
114
- # for ftp, no plan to add new features to this method except bug fixing
115
- def self.ftp(method, options, &block)
116
- options = {:url => options} if options.is_a? String
117
- options = {:close => true}.merge(options)
118
- @@__url = options[:url] = "ftp://#{options[:url]}" unless options[:url] =~ /^ftp:\/\//
119
- uri = URI(options[:url])
120
- guest_name, guest_pass = 'anonymous', "guest@#{uri.host}"
121
- unless options[:username]
122
- options[:username], options[:password] =
123
- uri.userinfo ? uri.userinfo.split(':') : [guest_name, guest_pass]
124
- end
125
- options[:username] = guest_name unless options[:username]
126
- options[:password] = guest_pass if options[:password].nil?
127
- ftp = Net::FTP.open(uri.host, options[:username], options[:password])
128
- return data(ftp, &block) unless method
129
- stat = case method.to_sym
130
- when :get_as_string
131
- require 'tempfile'
132
- tmp = Tempfile.new('http_request_ftp')
133
- ftp.getbinaryfile(uri.path, tmp.path)
134
- ftp.response = tmp.read
135
- tmp.close
136
- unless block_given?
137
- ftp.close
138
- return ftp.response
139
- end
140
- when :get
141
- options[:to] = File.basename(uri.path) unless options[:to]
142
- ftp.getbinaryfile(uri.path, options[:to])
143
- when :put
144
- ftp.putbinaryfile(options[:from], uri.path)
145
- when :mkdir, :rmdir, :delete, :size, :mtime, :list, :nlst
146
- ftp.method(method).call(uri.path)
147
- when :rename
148
- ftp.rename(uri.path, options[:to]) if options[:to]
149
- when :status
150
- ftp.status
151
- else
152
- return ftp
153
- end
154
- if options[:close] and not block_given?
155
- ftp.close
156
- stat
157
- else
158
- ftp.response = stat unless ftp.response
159
- data(ftp, &block)
160
- end
161
- end
162
-
163
- private
164
-
165
- def md5(string)
166
- Digest::MD5.hexdigest string
167
- end
168
-
169
- # get params for the Digest auth
170
- # see: http://www.rooftopsolutions.nl/article/223
171
- def get_params_for_digest
172
- return '' unless @options[:auth_username] and @options[:auth_password]
173
- user, passwd = @options[:auth_username], @options[:auth_password]
174
- hr = self.class.send @options[:method],
175
- @uri.userinfo ?
176
- @@__url.sub(/:\/\/(.+?)@/, '://') :
177
- @@__url
178
-
179
- params = HttpRequestParams.parse hr['WWW-Authenticate'].split(' ', 2).last
180
- method = @options[:method].upcase
181
- cnonce = md5(rand.to_s + Time.new.to_s)
182
- nc = "00000001"
183
-
184
- data = []
185
- data << md5("#{user}:#{params['realm']}:#{passwd}") \
186
- << params['nonce'] \
187
- << ('%08x' % nc) \
188
- << cnonce \
189
- << params['qop'] \
190
- << md5("#{method}:#{@uri.path}")
191
-
192
- params = params.update({
193
- :username => user,
194
- :nc => nc,
195
- :cnonce => cnonce,
196
- :uri => @uri.path,
197
- :method => method,
198
- :response => md5(data.join(":"))
199
- })
200
-
201
- headers = []
202
- params.each {|k, v| headers << "#{k}=\"#{v}\"" }
203
- headers.join(", ")
204
- rescue
205
- ''
206
- end
207
-
208
- # for the Http Auth if need
209
- def parse_http_auth
210
- if @options[:auth] or
211
- @uri.userinfo or
212
- (@options[:auth_username] and @options[:auth_password])
213
-
214
- if @options[:auth].is_a? Hash
215
- @options[:auth_username] = @options[:auth][:username]
216
- @options[:auth_password] = @options[:auth][:password]
217
- @options[:auth] = @options[:auth][:type]
218
- elsif @uri.userinfo and (!@options[:auth_username] or !@options[:auth_password])
219
- @options[:auth_username], @options[:auth_password] = @uri.userinfo.split(/:/, 2)
220
- end
221
-
222
- if @options[:auth_username] and @options[:auth_password]
223
- # Digest Auth
224
- if @options[:auth].to_s == 'digest'
225
- digest = get_params_for_digest
226
- @headers['Authorization'] = "Digest " + digest unless digest.empty?
227
- else
228
- # Basic Auth
229
- @headers['Authorization'] = "Basic " +
230
- ["#{@options[:auth_username]}:#{@options[:auth_password]}"].pack('m').delete!("\r\n")
231
- end
232
- end
233
-
234
- end
235
- end
236
-
237
- # initialize for the http request
238
- def parse_options(method, options)
239
- options = {:url => options.to_s} if [String, Array].include? options.class
240
- @options = {
241
- :ssl_port => 443,
242
- :redirect_limits => 5,
243
- :redirect => true,
244
- :url => nil,
245
- :ajax => false,
246
- :xhr => false,
247
- :method => method
248
- }
249
- @options.merge!(options)
250
- @@__url = @options[:url]
251
- @uri = URI(@options[:url])
252
- @uri.path = '/' if @uri.path.empty?
253
- @headers = {
254
- 'Host' => @uri.host,
255
- 'Referer' => @options[:url],
256
- 'User-Agent' => 'HttpRequest.rb ' + self.class.version
257
- }
258
-
259
- # support gzip
260
- begin; require 'zlib'; rescue LoadError; end
261
- @headers['Accept-Encoding'] = 'gzip,deflate' if defined? ::Zlib
262
-
263
- # ajax calls?
264
- @headers['X-Requested-With'] = 'XMLHttpRequest' if @options[:ajax] or @options[:xhr]
265
-
266
- # Http Authenication
267
- parse_http_auth
268
-
269
- # headers
270
- @options[:headers].each {|k, v| @headers[k] = v} if @options[:headers].is_a? Hash
271
-
272
- # add cookies if have
273
- if @options[:cookies]
274
- if @options[:cookies].is_a? Hash
275
- cookies = []
276
- @options[:cookies].each {|k, v|
277
- cookies << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
278
- }
279
- cookies = cookies.join('; ')
280
- else
281
- cookies = @options[:cookies].to_s
282
- end
283
- @headers['Cookie'] = cookies unless cookies.empty?
284
- end
285
- end
286
-
287
- # parse parameters for the options[:parameters] and @uri.query
288
- def parse_parameters
289
- if @options[:parameters].is_a?(Hash)
290
- @options[:parameters] = @options[:parameters].collect{|k, v|
291
- "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
292
- }.join('&')
293
- end
294
- @options[:parameters] = '' if @options[:parameters].nil?
295
- if not @uri.query.to_s.empty?
296
- @options[:parameters] << (@options[:parameters].empty? ? @uri.query : "&#{@uri.query}")
297
- end
298
-
299
- # for uploading files
300
- build_multipart if @options[:files] and 'post'.eql?(@options[:method])
301
- end
302
-
303
- # for uploading files
304
- def build_multipart
305
- boundary = md5(rand.to_s).to_s[0..5]
306
- @headers['Content-type'] = "multipart/form-data, boundary=#{boundary}"
307
- multipart = []
308
- if @options[:parameters].is_a?(String)
309
- @options[:parameters] = CGI.parse(@options[:parameters])
310
- if @options[:parameters].is_a? Hash
311
- @options[:parameters].each {|k, v|
312
- multipart << "--#{boundary}"
313
- multipart << "Content-disposition: form-data; name=\"#{k}\""
314
- multipart << "\r\n#{v.first}"
315
- }
316
- end
317
- end
32
+ include Singleton
33
+ class << self
34
+ # version
35
+ VERSION = '1.1.9'.freeze
36
+ def version;VERSION;end
37
+
38
+ # avaiabled http methods
39
+ def http_methods
40
+ %w{get head post put proppatch lock unlock options propfind delete move copy mkcol trace}
41
+ end
42
+
43
+ # return data with or without block
44
+ def data(response, &block)
45
+ response.url = @@__url if defined? @@__url
46
+ block_given? ? block.call(response) : response
47
+ end
48
+
49
+ # update cookies
50
+ def update_cookies(response)
51
+ return unless response.header['set-cookie']
52
+ response.get_fields('set-cookie').each {|k|
53
+ k, v = k.split(';')[0].split('=')
54
+ @@__cookies[k] = v
55
+ }
56
+ end
57
+
58
+ # return cookies
59
+ def cookies
60
+ @@__cookies
61
+ end
62
+
63
+ # check the http resource whether or not available
64
+ def available?(url, timeout = 5)
65
+ timeout(timeout) {
66
+ u = URI(url)
67
+ s = TCPSocket.new(u.host, u.port)
68
+ s.close
69
+ }
70
+ return true
71
+ rescue Exception => e
72
+ return false
73
+ end
74
+ end
75
+
76
+ def data(response, &block)
77
+ self.class.data(response, &block)
78
+ end
79
+
80
+ # send request by some given parameters
81
+ def request(method, options, &block)
82
+
83
+ # parse the @options
84
+ parse_options(method, options)
85
+
86
+ # parse and merge for the options[:parameters]
87
+ parse_parameters
88
+
89
+ # send http request and get the response
90
+ response = send_request_and_get_response
91
+
92
+ return data(response, &block) unless @options[:redirect]
93
+
94
+ # redirect?
95
+ process_redirection response, &block
96
+ end
97
+
98
+ # catch all available http requests
99
+ def self.method_missing(method_name, *options, &block)
100
+ options = if options.size.eql? 2
101
+ options.last.merge({:url => options.first})
102
+ else
103
+ options.first
104
+ end
105
+ @@redirect_times = 0
106
+ # we need to retrieve the cookies from last http response before reset cookies if it's a Net::HTTPResponse
107
+ options[:cookies] = options[:cookies].cookies if options[:cookies].is_a? Net::HTTPResponse
108
+ @@__cookies = {}
109
+ method_name = method_name.to_s.downcase
110
+ raise NoHttpMethodException, "No such http method can be called: #{method_name}" unless self.http_methods.include?(method_name)
111
+ self.instance.request(method_name, options, &block)
112
+ end
113
+
114
+ # for ftp, no plan to add new features to this method except bug fixing
115
+ def self.ftp(method, options, &block)
116
+ options = {:url => options} if options.is_a? String
117
+ options = {:close => true}.merge(options)
118
+ @@__url = options[:url] = "ftp://#{options[:url]}" unless options[:url] =~ /^ftp:\/\//
119
+ uri = URI(options[:url])
120
+ guest_name, guest_pass = 'anonymous', "guest@#{uri.host}"
121
+ unless options[:username]
122
+ options[:username], options[:password] =
123
+ uri.userinfo ? uri.userinfo.split(':') : [guest_name, guest_pass]
124
+ end
125
+ options[:username] = guest_name unless options[:username]
126
+ options[:password] = guest_pass if options[:password].nil?
127
+ ftp = Net::FTP.open(uri.host, options[:username], options[:password])
128
+ return data(ftp, &block) unless method
129
+ stat = case method.to_sym
130
+ when :get_as_string
131
+ require 'tempfile'
132
+ tmp = Tempfile.new('http_request_ftp')
133
+ ftp.getbinaryfile(uri.path, tmp.path)
134
+ ftp.response = tmp.read
135
+ tmp.close
136
+ unless block_given?
137
+ ftp.close
138
+ return ftp.response
139
+ end
140
+ when :get
141
+ options[:to] = File.basename(uri.path) unless options[:to]
142
+ ftp.getbinaryfile(uri.path, options[:to])
143
+ when :put
144
+ ftp.putbinaryfile(options[:from], uri.path)
145
+ when :mkdir, :rmdir, :delete, :size, :mtime, :list, :nlst
146
+ ftp.method(method).call(uri.path)
147
+ when :rename
148
+ ftp.rename(uri.path, options[:to]) if options[:to]
149
+ when :status
150
+ ftp.status
151
+ else
152
+ return ftp
153
+ end
154
+ if options[:close] and not block_given?
155
+ ftp.close
156
+ stat
157
+ else
158
+ ftp.response = stat unless ftp.response
159
+ data(ftp, &block)
160
+ end
161
+ end
162
+
163
+ private
164
+
165
+ def md5(string)
166
+ Digest::MD5.hexdigest string
167
+ end
168
+
169
+ # get params for the Digest auth
170
+ # see: http://www.rooftopsolutions.nl/article/223
171
+ def get_params_for_digest
172
+ return '' unless @options[:auth_username] and @options[:auth_password]
173
+ user, passwd = @options[:auth_username], @options[:auth_password]
174
+ hr = self.class.send @options[:method],
175
+ @uri.userinfo ?
176
+ @@__url.sub(/:\/\/(.+?)@/, '://') :
177
+ @@__url
178
+
179
+ params = HttpRequestParams.parse hr['WWW-Authenticate'].split(' ', 2).last
180
+ method = @options[:method].upcase
181
+ cnonce = md5(rand.to_s + Time.new.to_s)
182
+ nc = "00000001"
183
+
184
+ data = []
185
+ data << md5("#{user}:#{params['realm']}:#{passwd}") \
186
+ << params['nonce'] \
187
+ << ('%08x' % nc) \
188
+ << cnonce \
189
+ << params['qop'] \
190
+ << md5("#{method}:#{@uri.path}")
191
+
192
+ params = params.update({
193
+ :username => user,
194
+ :nc => nc,
195
+ :cnonce => cnonce,
196
+ :uri => @uri.path,
197
+ :method => method,
198
+ :response => md5(data.join(":"))
199
+ })
200
+
201
+ headers = []
202
+ params.each {|k, v| headers << "#{k}=\"#{v}\"" }
203
+ headers.join(", ")
204
+ rescue
205
+ ''
206
+ end
207
+
208
+ # for the Http Auth if need
209
+ def parse_http_auth
210
+ if @options[:auth] or
211
+ @uri.userinfo or
212
+ (@options[:auth_username] and @options[:auth_password])
213
+
214
+ if @options[:auth].is_a? Hash
215
+ @options[:auth_username] = @options[:auth][:username]
216
+ @options[:auth_password] = @options[:auth][:password]
217
+ @options[:auth] = @options[:auth][:type]
218
+ elsif @uri.userinfo and (!@options[:auth_username] or !@options[:auth_password])
219
+ @options[:auth_username], @options[:auth_password] = @uri.userinfo.split(/:/, 2)
220
+ end
221
+
222
+ if @options[:auth_username] and @options[:auth_password]
223
+ # Digest Auth
224
+ if @options[:auth].to_s == 'digest'
225
+ digest = get_params_for_digest
226
+ @headers['Authorization'] = "Digest " + digest unless digest.empty?
227
+ else
228
+ # Basic Auth
229
+ @headers['Authorization'] = "Basic " +
230
+ ["#{@options[:auth_username]}:#{@options[:auth_password]}"].pack('m').delete!("\r\n")
231
+ end
232
+ end
233
+
234
+ end
235
+ end
236
+
237
+ # initialize for the http request
238
+ def parse_options(method, options)
239
+ options = {:url => options.to_s} if [String, Array].include? options.class
240
+ @options = {
241
+ :ssl_port => 443,
242
+ :redirect_limits => 5,
243
+ :redirect => true,
244
+ :url => nil,
245
+ :ajax => false,
246
+ :xhr => false,
247
+ :method => method
248
+ }
249
+ @options.merge!(options)
250
+ @@__url = @options[:url]
251
+ @uri = URI(@options[:url])
252
+ @uri.path = '/' if @uri.path.empty?
253
+ @headers = {
254
+ 'Host' => @uri.host,
255
+ 'Referer' => @options[:url],
256
+ 'User-Agent' => 'HttpRequest.rb ' + self.class.version
257
+ }
258
+
259
+ # support gzip
260
+ begin; require 'zlib'; rescue LoadError; end
261
+ @headers['Accept-Encoding'] = 'gzip,deflate' if defined? ::Zlib
262
+
263
+ # ajax calls?
264
+ @headers['X-Requested-With'] = 'XMLHttpRequest' if @options[:ajax] or @options[:xhr]
265
+
266
+ # Http Authenication
267
+ parse_http_auth
268
+
269
+ # headers
270
+ @options[:headers].each {|k, v| @headers[k] = v} if @options[:headers].is_a? Hash
271
+
272
+ # add cookies if have
273
+ if @options[:cookies]
274
+ if @options[:cookies].is_a? Hash
275
+ cookies = []
276
+ @options[:cookies].each {|k, v|
277
+ cookies << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
278
+ }
279
+ cookies = cookies.join('; ')
280
+ else
281
+ cookies = @options[:cookies].to_s
282
+ end
283
+ @headers['Cookie'] = cookies unless cookies.empty?
284
+ end
285
+ end
286
+
287
+ # parse parameters for the options[:parameters] and @uri.query
288
+ def parse_parameters
289
+ if @options[:parameters].is_a?(Hash)
290
+ @options[:parameters] = @options[:parameters].collect{|k, v|
291
+ "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
292
+ }.join('&')
293
+ end
294
+ @options[:parameters] = '' if @options[:parameters].nil?
295
+ if not @uri.query.to_s.empty?
296
+ @options[:parameters] << (@options[:parameters].empty? ? @uri.query : "&#{@uri.query}")
297
+ end
298
+
299
+ # for uploading files
300
+ build_multipart if @options[:files] and 'post'.eql?(@options[:method])
301
+ end
302
+
303
+ # for uploading files
304
+ def build_multipart
305
+ boundary = md5(rand.to_s).to_s[0..5]
306
+ @headers['Content-type'] = "multipart/form-data, boundary=#{boundary}"
307
+ multipart = []
308
+ if @options[:parameters].is_a?(String)
309
+ @options[:parameters] = CGI.parse(@options[:parameters])
310
+ if @options[:parameters].is_a? Hash
311
+ @options[:parameters].each {|k, v|
312
+ multipart << "--#{boundary}"
313
+ multipart << "Content-disposition: form-data; name=\"#{k}\""
314
+ multipart << "\r\n#{v.first}"
315
+ }
316
+ end
317
+ end
318
318
  @options[:files] = [@options[:files]] if @options[:files].is_a?(Hash)
319
- @options[:files].each_with_index {|f, index|
320
- f[:field_name] ||= "files[]"
321
- f[:file_name] ||= "#{boundary}_#{index}"
322
- f[:transfer_encoding] ||= "binary"
323
- f[:content_type] ||= 'application/octet-stream'
324
- multipart << "--#{boundary}"
325
- multipart << "Content-disposition: form-data; name=\"#{f[:field_name]}\"; filename=\"#{f[:file_name]}\""
326
- multipart << "Content-type: #{f[:content_type]}"
327
- multipart << "Content-Transfer-Encoding: #{f[:transfer_encoding]}"
328
- multipart << "\r\n#{f[:file_content]}"
329
- }
330
- multipart << "--#{boundary}--"
331
- multipart = multipart.join("\r\n")
332
- @headers['Content-length'] = "#{multipart.size}"
333
- @options[:parameters] = multipart
334
- end
335
-
336
- # send request and get the response by some options
337
- def send_request_and_get_response
338
- # for proxy
339
- http = if @options[:proxy_addr]
340
- if @options[:proxy_user] and @options[:proxy_pass]
341
- Net::HTTP::Proxy(
342
- @options[:proxy_addr],
343
- @options[:proxy_port],
344
- @options[:proxy_user],
345
- @options[:proxy_pass]
346
- ).new(@u.host, @u.port)
347
- else
348
- Net::HTTP::Proxy(
349
- @options[:proxy_addr],
350
- @options[:proxy_port]
351
- ).new(@uri.host, @uri.port)
352
- end
353
- else
354
- Net::HTTP.new(@uri.host, @uri.port)
355
- end
356
-
357
- # ssl support
358
- http.use_ssl = true if @uri.scheme =~ /^https$/i
359
-
360
- # sending request and get response
361
- send_request http
362
- end
363
-
364
- # send http request
365
- def send_request(http)
366
- # xml data?
367
- if @options[:parameters].to_s[0..4].eql?('<?xml') and @options[:method].eql? 'post'
368
- @headers['Content-Type'] = 'application/xml'
369
- @headers['Content-Length'] = @options[:parameters].size.to_s
370
- @headers['Content-MD5'] = md5(@options[:parameters]).to_s
371
- end
372
-
373
- # GO !!
374
- if @options[:method] =~ /^(get|head|options|delete|move|copy|trace|)$/
375
- @options[:parameters] = "?#{@options[:parameters]}" if @options[:parameters]
376
- path = if @options[:parameters] =~ /^\?+$/
377
- @uri.path
378
- else
379
- @uri.path + @options[:parameters]
380
- end
381
- h = http.method(@options[:method]).call(path, @headers)
382
- else
383
- h = http.method(@options[:method]).call(@uri.path, @options[:parameters], @headers)
384
- end
385
-
386
- self.class.update_cookies h
387
- h
388
- end
389
-
390
- # process the redirectation if need
391
- def process_redirection(response, &block)
392
- case response
393
- when Net::HTTPRedirection
394
- url = "#{@uri.scheme}://#{@uri.host}#{':' + @uri.port.to_s if @uri.port != 80}"
395
- last_url = @options[:url]
396
- @options[:url] = case response['location']
397
- when /^https?:\/\//i
398
- response['location']
399
- when /^\//
400
- url + response['location']
401
- when /^(\.\.\/|\.\/)/
402
- paths = (File.dirname(@uri.path) + '/' + response['location']).split('/')
403
- location = []
404
- paths.each {|path|
405
- next if path.empty? || path.eql?('.')
406
- path == '..' ? location.pop : location.push(path)
407
- }
408
- url + '/' + location.join('/')
409
- else
410
- url + File.dirname(@uri.path) + '/' + response['location']
411
- end
412
- return data(response, &block) if @@redirect_times > 2 and @options[:url].eql? last_url
413
- @@redirect_times += 1
414
- raise 'too many redirects...' if @@redirect_times > @options[:redirect_limits]
415
- if @options[:cookies].nil?
416
- @options[:cookies] = self.class.cookies
417
- else
418
- @options[:cookies] = @options[:cookies].update self.class.cookies
419
- end
420
- @options.delete :parameters
421
- @options.delete :method
422
- request('get', @options, &block)
423
- else
424
- data(response, &block)
425
- end
426
- end
319
+ @options[:files].each_with_index {|f, index|
320
+ f[:field_name] ||= "files[]"
321
+ f[:file_name] ||= "#{boundary}_#{index}"
322
+ f[:transfer_encoding] ||= "binary"
323
+ f[:content_type] ||= 'application/octet-stream'
324
+ multipart << "--#{boundary}"
325
+ multipart << "Content-disposition: form-data; name=\"#{f[:field_name]}\"; filename=\"#{f[:file_name]}\""
326
+ multipart << "Content-type: #{f[:content_type]}"
327
+ multipart << "Content-Transfer-Encoding: #{f[:transfer_encoding]}"
328
+ multipart << "\r\n#{f[:file_content]}"
329
+ }
330
+ multipart << "--#{boundary}--"
331
+ multipart = multipart.join("\r\n")
332
+ @headers['Content-length'] = "#{multipart.size}"
333
+ @options[:parameters] = multipart
334
+ end
335
+
336
+ # send request and get the response by some options
337
+ def send_request_and_get_response
338
+ # for proxy
339
+ http = if @options[:proxy_addr]
340
+ if @options[:proxy_user] and @options[:proxy_pass]
341
+ Net::HTTP::Proxy(
342
+ @options[:proxy_addr],
343
+ @options[:proxy_port],
344
+ @options[:proxy_user],
345
+ @options[:proxy_pass]
346
+ ).new(@u.host, @u.port)
347
+ else
348
+ Net::HTTP::Proxy(
349
+ @options[:proxy_addr],
350
+ @options[:proxy_port]
351
+ ).new(@uri.host, @uri.port)
352
+ end
353
+ else
354
+ Net::HTTP.new(@uri.host, @uri.port)
355
+ end
356
+
357
+ # ssl support
358
+ http.use_ssl = true if @uri.scheme =~ /^https$/i
359
+
360
+ # sending request and get response
361
+ send_request http
362
+ end
363
+
364
+ # send http request
365
+ def send_request(http)
366
+ # xml data?
367
+ if @options[:parameters].to_s[0..4].eql?('<?xml') and @options[:method].eql? 'post'
368
+ @headers['Content-Type'] = 'application/xml'
369
+ @headers['Content-Length'] = @options[:parameters].size.to_s
370
+ @headers['Content-MD5'] = md5(@options[:parameters]).to_s
371
+ end
372
+
373
+ # GO !!
374
+ if @options[:method] =~ /^(get|head|options|delete|move|copy|trace|)$/
375
+ @options[:parameters] = "?#{@options[:parameters]}" if @options[:parameters]
376
+ path = if @options[:parameters] =~ /^\?+$/
377
+ @uri.path
378
+ else
379
+ @uri.path + @options[:parameters]
380
+ end
381
+ h = http.method(@options[:method]).call(path, @headers)
382
+ else
383
+ h = http.method(@options[:method]).call(@uri.path, @options[:parameters], @headers)
384
+ end
385
+
386
+ self.class.update_cookies h
387
+ h
388
+ end
389
+
390
+ # process the redirectation if need
391
+ def process_redirection(response, &block)
392
+ case response
393
+ when Net::HTTPRedirection
394
+ url = "#{@uri.scheme}://#{@uri.host}#{':' + @uri.port.to_s if @uri.port != 80}"
395
+ last_url = @options[:url]
396
+ @options[:url] = case response['location']
397
+ when /^https?:\/\//i
398
+ response['location']
399
+ when /^\//
400
+ url + response['location']
401
+ when /^(\.\.\/|\.\/)/
402
+ paths = (File.dirname(@uri.path) + '/' + response['location']).split('/')
403
+ location = []
404
+ paths.each {|path|
405
+ next if path.empty? || path.eql?('.')
406
+ path == '..' ? location.pop : location.push(path)
407
+ }
408
+ url + '/' + location.join('/')
409
+ else
410
+ url + File.dirname(@uri.path) + '/' + response['location']
411
+ end
412
+ return data(response, &block) if @@redirect_times > 2 and @options[:url].eql? last_url
413
+ @@redirect_times += 1
414
+ raise 'too many redirects...' if @@redirect_times > @options[:redirect_limits]
415
+ if @options[:cookies].nil?
416
+ @options[:cookies] = self.class.cookies
417
+ else
418
+ @options[:cookies] = @options[:cookies].update self.class.cookies
419
+ end
420
+ @options.delete :parameters
421
+ @options.delete :method
422
+ request('get', @options, &block)
423
+ else
424
+ data(response, &block)
425
+ end
426
+ end
427
427
 
428
428
  end
429
429
 
430
430
  module Net
431
- class HTTPResponse
432
-
433
- attr_accessor :url
434
-
435
- # get cookies as a hash
436
- def cookies
437
- HttpRequest.cookies
438
- end
439
-
440
- # for gzipped body
441
- def body
442
- bd = read_body()
443
- return bd unless bd
444
- if (self['content-encoding'] == 'gzip') and defined?(::Zlib)
445
- ::Zlib::GzipReader.new(StringIO.new(bd)).read
446
- else
447
- bd
448
- end
449
- end
450
-
451
- # body
452
- def raw_body
453
- read_body()
454
- end
455
-
456
- # detect the response code
457
- #
458
- # Example:
459
- # puts HttpRequest.get('http://www.example.com').code_200?
460
- # puts HttpRequest.get('http://www.example.com').code_2xx?
461
- # HttpRequest.get('http://www.example.com/404.html') {|http|
462
- # puts "IS 4xx" if http.code_4xx?
463
- # puts "IS 404" if http.code_404?
464
- # }
465
- #
466
- # supported methods
467
- # code_1xx? code_2xx? code_3xx? code_4xx? code_5xx?
468
- # code_100? code_101? code_200? code_201? ... code_505?
469
- def method_missing(method_name)
470
- case method_name.to_s
471
- when /^(code|status)_([0-9])xx\?$/
472
- not CODE_CLASS_TO_OBJ[$2].nil? and is_a? CODE_CLASS_TO_OBJ[$2]
473
- when /^(code|status)_([0-9]+)\?$/
474
- not CODE_TO_OBJ[$2].nil? and is_a? CODE_TO_OBJ[$2]
475
- else
476
- raise NoHttpMethodException, 'Unknown method of response code!'
477
- end
478
- end
479
-
480
- end
431
+ class HTTPResponse
432
+
433
+ attr_accessor :url
434
+
435
+ # get cookies as a hash
436
+ def cookies
437
+ HttpRequest.cookies
438
+ end
439
+
440
+ # for gzipped body
441
+ def body
442
+ bd = read_body()
443
+ return bd unless bd
444
+ if (self['content-encoding'] == 'gzip') and defined?(::Zlib)
445
+ ::Zlib::GzipReader.new(StringIO.new(bd)).read
446
+ else
447
+ bd
448
+ end
449
+ end
450
+
451
+ # body
452
+ def raw_body
453
+ read_body()
454
+ end
455
+
456
+ # detect the response code
457
+ #
458
+ # Example:
459
+ # puts HttpRequest.get('http://www.example.com').code_200?
460
+ # puts HttpRequest.get('http://www.example.com').code_2xx?
461
+ # HttpRequest.get('http://www.example.com/404.html') {|http|
462
+ # puts "IS 4xx" if http.code_4xx?
463
+ # puts "IS 404" if http.code_404?
464
+ # }
465
+ #
466
+ # supported methods
467
+ # code_1xx? code_2xx? code_3xx? code_4xx? code_5xx?
468
+ # code_100? code_101? code_200? code_201? ... code_505?
469
+ def method_missing(method_name)
470
+ case method_name.to_s
471
+ when /^(code|status)_([0-9])xx\?$/
472
+ not CODE_CLASS_TO_OBJ[$2].nil? and is_a? CODE_CLASS_TO_OBJ[$2]
473
+ when /^(code|status)_([0-9]+)\?$/
474
+ not CODE_TO_OBJ[$2].nil? and is_a? CODE_TO_OBJ[$2]
475
+ else
476
+ raise NoHttpMethodException, 'Unknown method of response code!'
477
+ end
478
+ end
479
+
480
+ end
481
481
  end
482
482
 
483
483
  # for ftp response
484
484
  class Net::FTP
485
- def response=(response)
486
- @_response = response
487
- end
485
+ def response=(response)
486
+ @_response = response
487
+ end
488
488
 
489
- def response
490
- @_response
491
- end
489
+ def response
490
+ @_response
491
+ end
492
492
  end
493
493
 
494
494
  # from Rack, parsing parameters for the Digest auth
495
495
  class HttpRequestParams < Hash
496
- def self.parse(str)
497
- split_header_value(str).inject(new) do |header, param|
498
- k, v = param.split('=', 2)
499
- header[k] = dequote(v)
500
- header
501
- end
502
- end
503
-
504
- def self.dequote(str) # From WEBrick::HTTPUtils
505
- ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
506
- ret.gsub!(/\\(.)/, "\\1")
507
- ret
508
- end
509
-
510
- def self.split_header_value(str)
511
- str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] }
512
- end
513
-
514
- def initialize
515
- super
516
-
517
- yield self if block_given?
518
- end
519
-
520
- def [](k)
521
- super k.to_s
522
- end
523
-
524
- def []=(k, v)
525
- super k.to_s, v.to_s
526
- end
527
-
528
- UNQUOTED = ['qop', 'nc', 'stale']
529
-
530
- def to_s
531
- inject([]) do |parts, (k, v)|
532
- parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v))
533
- parts
534
- end.join(', ')
535
- end
536
-
537
- def quote(str) # From WEBrick::HTTPUtils
538
- '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
539
- end
496
+ def self.parse(str)
497
+ split_header_value(str).inject(new) do |header, param|
498
+ k, v = param.split('=', 2)
499
+ header[k] = dequote(v)
500
+ header
501
+ end
502
+ end
503
+
504
+ def self.dequote(str) # From WEBrick::HTTPUtils
505
+ ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
506
+ ret.gsub!(/\\(.)/, "\\1")
507
+ ret
508
+ end
509
+
510
+ def self.split_header_value(str)
511
+ str.scan( /(\w+\=(?:"[^\"]+"|[^,]+))/n ).collect{ |v| v[0] }
512
+ end
513
+
514
+ def initialize
515
+ super
516
+
517
+ yield self if block_given?
518
+ end
519
+
520
+ def [](k)
521
+ super k.to_s
522
+ end
523
+
524
+ def []=(k, v)
525
+ super k.to_s, v.to_s
526
+ end
527
+
528
+ UNQUOTED = ['qop', 'nc', 'stale']
529
+
530
+ def to_s
531
+ inject([]) do |parts, (k, v)|
532
+ parts << "#{k}=" + (UNQUOTED.include?(k) ? v.to_s : quote(v))
533
+ parts
534
+ end.join(', ')
535
+ end
536
+
537
+ def quote(str) # From WEBrick::HTTPUtils
538
+ '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
539
+ end
540
540
  end
541
541
 
542
542
 
@@ -545,31 +545,31 @@ class NoHttpMethodException < Exception; end
545
545
 
546
546
  # for command line
547
547
  if __FILE__.eql? $0
548
- method, url, params = ARGV
549
- exit unless method
550
- source_method = method
551
- method = method.split('_')[0] if method.include? '_'
552
-
553
- # fix path of the url
554
- url = "http://#{url}" unless url =~ /^(https?:\/\/)/i
555
-
556
- params = if params
557
- "{:url => '#{url}', :parameters => '" + params + "'}"
558
- else
559
- "'#{url}'"
560
- end
561
-
562
- if HttpRequest.http_methods.include?(method) && url
563
- http = eval("HttpRequest.#{method}(#{params})")
564
- case source_method
565
- when /_only_header$/
566
- http.each{|k,v| puts "#{k}: #{v}"}
567
- when /_with_header$/
568
- http.each{|k,v| puts "#{k}: #{v}"}
569
- print http.body unless http.body.to_s.empty?
570
- else
571
- print http.body unless http.body.to_s.empty?
572
- end
573
- end
548
+ method, url, params = ARGV
549
+ exit unless method
550
+ source_method = method
551
+ method = method.split('_')[0] if method.include? '_'
552
+
553
+ # fix path of the url
554
+ url = "http://#{url}" unless url =~ /^(https?:\/\/)/i
555
+
556
+ params = if params
557
+ "{:url => '#{url}', :parameters => '" + params + "'}"
558
+ else
559
+ "'#{url}'"
560
+ end
561
+
562
+ if HttpRequest.http_methods.include?(method) && url
563
+ http = eval("HttpRequest.#{method}(#{params})")
564
+ case source_method
565
+ when /_only_header$/
566
+ http.each{|k,v| puts "#{k}: #{v}"}
567
+ when /_with_header$/
568
+ http.each{|k,v| puts "#{k}: #{v}"}
569
+ print http.body unless http.body.to_s.empty?
570
+ else
571
+ print http.body unless http.body.to_s.empty?
572
+ end
573
+ end
574
574
 
575
575
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 1
8
- - 8
9
- version: 1.1.8
8
+ - 9
9
+ version: 1.1.9
10
10
  platform: ruby
11
11
  authors:
12
12
  - xianhua.zhou