http_request.rb 1.0.1

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 +7 -0
  2. data/README.rdoc +189 -0
  3. data/lib/http_request.rb +286 -0
  4. metadata +55 -0
data/Changelog ADDED
@@ -0,0 +1,7 @@
1
+ v1.1
2
+ * new feature: upload or download files by ftp
3
+
4
+ v1.0
5
+ * support get, post, put, delete etc. http methods
6
+ * upload files
7
+ * and more...
data/README.rdoc ADDED
@@ -0,0 +1,189 @@
1
+ == Introduction
2
+
3
+ The HttpRequest class is based on the 'net/http' and 'net/ftp' libraries, so the return type is Net::HTTPResponse or Net::FTP when you call get or post or other methods by HttpRequest.xxx or HttpRequest.ftp
4
+
5
+ == Options
6
+
7
+ you can call like HttpRequest.get(options), the options parameter is a hash, support following keys:
8
+ :url => String, the url you want to request
9
+ :parameters => String or Hash, parameters will send to the url
10
+ :redirect => Boolean, whether support redirect to, default is true
11
+ :redirect_limits => Fixnum, maximal times for redirect if enabled
12
+ :ssl_port => Fixnum, ssl port, default is 443
13
+ :headers => Hash, you can add some custom http headers
14
+ :files => for upload files
15
+
16
+ # proxy settings
17
+ :proxy_addr => String, proxy address
18
+ :proxy_port => Fixnum, proxy port
19
+ :proxy_user => String, proxy username
20
+ :proxy_pass => String, proxy password
21
+
22
+ == Examples for your ruby program:
23
+
24
+ include http_request.rb first
25
+ require '/path/to/http_request.rb'
26
+
27
+ get
28
+ puts HttpRequest.get('http://www.github.com')
29
+
30
+ get with query string, 4 are same
31
+ puts HttpRequest.get('http://www.google.com/search?hl=en&q=ruby&start=0&sa=N')
32
+ puts HttpRequest.get(:url => 'http://www.google.com/search', :parameters => 'hl=en&q=ruby&start=0&sa=N')
33
+ puts HttpRequest.get({:url => 'http://www.google.com/search', :parameters => 'hl=en&q=ruby&start=0&sa=N'})
34
+ puts HttpRequest.get({:url => 'http://www.google.com/search', :parameters => {:hl => 'en', :q => 'ruby', :start => 0, :sa => 'N'}})
35
+
36
+ post with some paramet
37
+ puts HttpRequest.get(:url => 'http://localhost/test.php', :parameters => 'from=http_request.rb').body
38
+ puts HttpRequest.get(:url => 'http://localhost/test.php', :parameters => {:name => 'Ruby', :time => 'Now'}).body
39
+
40
+ also support other http methods, such as put, delete, trace, options, move etc.
41
+ HttpRequest.put(:url => 'http://www.example.com', :parameters => 'some=vars')
42
+ HttpRequest.delete('http://www.example.com/article/1')
43
+ HttpRequest.trace('http://www.example.com/')
44
+
45
+ basic authorization
46
+ HttpRequest.get('http://admin:pass@auth.cnzxh.net/secret/get/file')
47
+
48
+ proxy support
49
+ HttpRequest.get(:url => 'http://www.example.com/', :proxy_addr => 'your.proxy.address', :proxy_port => 80)
50
+ HttpRequest.get(:url => 'http://www.example.com/', :proxy_addr => 'your.proxy.address', :proxy_port => 80, :proxy_user => 'admin', :proxy_pass => '123123')
51
+
52
+ fetch headers
53
+ HttpRequest.get('http://www.example.com/').each {|k, v|
54
+ print "#{k} : #{v}"
55
+ }
56
+
57
+ fetch cookies
58
+ hp = HttpRequest.get('http://www.yahoo.com')
59
+ hp.cookies.each {|k, v|
60
+ puts "#{k} => #{v}"
61
+ }
62
+
63
+ add cookies into header
64
+ HttpRequest.get(:url => 'http://www.example.com/', :cookies => {:login => 'Yes', :userid => 101})
65
+ HttpRequest.get(:url => 'http://www.example.com/', :cookies => 'login=Yes; userId=101')
66
+
67
+ upload file by post method
68
+ HttpRequest.post(
69
+ :url => 'http://localhost/upload.php',
70
+ :files => [{
71
+ :file_name => 'test.txt', # original file name, default is rand name such as 0cdex_0
72
+ :field_name => 'user_file', # input field name, default is "files[]"
73
+ :content_type => 'text/plain', # content type, default is application/octet-stream
74
+ :file_content => 'Have a nice day!' # file content
75
+ }]
76
+ )
77
+
78
+ upload more than 1 file
79
+ files = [
80
+ {:file_name => 'a.txt', :file_content => 'just for test'},
81
+ {:file_name => 'b.csv', :file_content => "a,b,c\nd,e,f"}
82
+ ]
83
+ HttpRequest.post(
84
+ :url => 'http://localhost/upload.php',
85
+ :files => files
86
+ )
87
+
88
+ upload files with parameters
89
+ HttpRequest.post(
90
+ :url => 'http://localhost/upload.php',
91
+ :parameters => {:name => 'zhou', :age => '?'},
92
+ :files => [{:file_content => 'so easy:-)'}]
93
+ )
94
+ HttpRequest.post(
95
+ :url => 'http://localhost/upload.php',
96
+ :parameters => 'target=php&client=ruby',
97
+ :files => [{:file_content => 'so easy:-)'}]
98
+ )
99
+
100
+ want to upload a binary file such as photo?
101
+ HttpRequest.post(
102
+ :url => 'http://localhost/upload.php',
103
+ :parameters => {:title => 'Nice photo', :description => 'some description here.'},
104
+ :files => [{:file_name => 'nice.jpg', :field_name => 'photo', :file_content => File.read('/path/to/nice.jpg')}]
105
+ )
106
+
107
+ upload file by put method, more can check http://www.php.net/manual/en/features.file-upload.put-method.php
108
+ HttpRequest.put(
109
+ :url => 'http://localhost/upload.php',
110
+ :parameters => 'file content here'
111
+ )
112
+
113
+ == Examples in command line:
114
+
115
+ You need to do like "chmod +x http_request.rb" first.
116
+ Usage: ./http_request.rb method url [parameters]
117
+
118
+ get a file and print the content
119
+ $./http_request.rb get http://feeds.feedburner.com/RidingRails
120
+ $./http_request.rb get 'http://www.google.com/search?hl=en&q=ruby&start=0&sa=N'
121
+
122
+ get but just print header
123
+ $./http_request.rb get_only_header http://feeds.feedburner.com/RidingRails
124
+
125
+ get header and content
126
+ $./http_request.rb get_with_header http://feeds.feedburner.com/RidingRails
127
+
128
+ download and save as a file
129
+ $./http_request.rb http://rubyforge.org/frs/download.php/51094/RMagick-2.9.1.tar.bz2 > rmagick.tar.bz2
130
+
131
+ post
132
+ $./http_request.rb post http://localhost/test.php 'name=Ruby&time=Now'
133
+
134
+ such as "get_only_header" and "get_with_header", post and other http methods also can do such as "post_only_header", "put_with_header" etc.
135
+
136
+ == Examples for FTP (since 1.0.1):
137
+
138
+ download and save to
139
+ ftp = HttpRequest.ftp(:get, :url => 'ftp://user:pass@my.domain.name/path/to/hello.mp3', :to => '/tmp/hello.mp3')
140
+
141
+ upload from local
142
+ ftp = HttpRequest.ftp(:put, :url => 'ftp://user:pass@my.domain.name/path/to/hello.mp3', :from => '/tmp/hello.mp3')
143
+
144
+ get server info
145
+ puts HttpRequest.ftp(:status, :url => 'ftp://user:pass@my.domain.name/')
146
+
147
+ create a new directory (only for last directory)
148
+ HttpRequest.ftp(:mkdir, :url => 'ftp://user:pass@my.domain.name/path/to/newdir')
149
+ HttpRequest.ftp(:mkdir, :url => 'ftp://user:pass@my.domain.name/newdir')
150
+
151
+ remove a directory (only for last directory)
152
+ HttpRequest.ftp(:mkdir, :url => 'ftp://user:pass@my.domain.name/path/to/willbe_removed_dir')
153
+
154
+ list files
155
+ puts HttpRequest.ftp(:list, :url => 'ftp://user:pass@my.domain.name/')
156
+
157
+ list files as array
158
+ HttpRequest.ftp(:nlst, :url => 'ftp://my.domain.name/', :username => 'user', :password => 'pass').each {|f|
159
+ puts f
160
+ }
161
+
162
+ anonymous login
163
+ puts HttpRequest.ftp(:status, :url => 'ftp://my.domain.name/')
164
+
165
+ working as the "net/ftp" style, need set :close to false
166
+ ftp = HttpRequest.ftp(:status, :url => 'ftp://user:pass@my.domain.name/', :close => false)
167
+ puts ftp.response # get status from the ftp server
168
+ ftp.chdir('/musics')
169
+ ftp.getbinaryfile('test.ogg', '/tmp/test.ogg')
170
+ ftp.close
171
+
172
+ download multiple files from a directory
173
+ ftp = HttpRequest.ftp('nlst', :url => 'ftp://user:pass@my.domain.name/mp3/', :close => false)
174
+ ftp.response.each {|f|
175
+ puts "downloading....#{f}"
176
+ ftp.get(f, '/tmp/downloads/' + File.basename(f))
177
+ }
178
+ ftp.close
179
+
180
+ == TODO
181
+
182
+ ......
183
+
184
+ == LATEST VERSION
185
+ 1.0.1
186
+
187
+ == Author
188
+
189
+ xianhua.zhou<xianhua.zhou at gmail.com>, homepage: http://my.cnzxh.net
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # == Description
4
+ #
5
+ # This is a small, lightweight, powerful HttpRequest class based on the 'net/http' and 'net/ftp' libraries,
6
+ # it's easy to use to send http request and get response, also can use it as a shell script in command line.
7
+ #
8
+ # == Example
9
+ #
10
+ # Please read README.rdoc
11
+ #
12
+ # == Version
13
+ #
14
+ # v1.0.1
15
+ #
16
+ # Last Change: 11 Apail, 2009
17
+ #
18
+ # == Author
19
+ #
20
+ # xianhua.zhou<xianhua.zhou@gmail.com>
21
+ # homepage: http://my.cnzxh.net
22
+ #
23
+ #
24
+ require 'net/http'
25
+ require 'net/https'
26
+ require 'cgi'
27
+ require 'singleton'
28
+
29
+ class HttpRequest
30
+ include Singleton
31
+
32
+ def self.http_methods
33
+ %w{get head post put proppatch lock unlock options propfind delete move copy mkcol trace}
34
+ end
35
+
36
+ # initialize
37
+ def init_args(method, options)
38
+ options = {:url => options.to_s} if [String, Array].include? options.class
39
+ @options = {
40
+ :ssl_port => 443,
41
+ :redirect_limits => 5,
42
+ :redirect => true,
43
+ :url => nil
44
+ }
45
+ @options.merge!(options)
46
+ @uri = URI(@options[:url])
47
+ @uri.path = '/' if @uri.path.empty?
48
+ @headers = {
49
+ 'Host' => @uri.host,
50
+ 'Referer' => @options[:url],
51
+ 'Accept-Language' => 'en-us,zh-cn;q=0.7,en;q=0.3',
52
+ 'Accept-Charset' => 'zh-cn,zh;q=0.5',
53
+ 'Accept' => 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',
54
+ 'Cache-Control' => 'max-age=0',
55
+ 'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.7) Gecko/2009030423 Ubuntu/8.04 (hardy) Firefox/3.0.7',
56
+ 'Connection' => 'keep-alive'
57
+ }
58
+
59
+ # Basic Authenication
60
+ @headers['Authorization'] = "Basic " + [@uri.userinfo].pack('m').delete!("\r\n") if @uri.userinfo
61
+
62
+ # headers
63
+ @options[:headers].each {|k, v| @headers[k] = v} if @options[:headers].is_a? Hash
64
+
65
+ # add cookies if have
66
+ if @options[:cookies]
67
+ if @options[:cookies].is_a? Hash
68
+ cookies = []
69
+ @options[:cookies].each {|k, v|
70
+ cookies << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
71
+ }
72
+ cookies = cookies.join('; ')
73
+ else
74
+ cookies = @options[:cookies].to_s
75
+ end
76
+ @headers['Cookie'] = cookies unless cookies.empty?
77
+ end
78
+
79
+ @redirect_times = 0 if @options[:redirect]
80
+ end
81
+
82
+ # send request
83
+ def request(method, opt)
84
+ init_args(method, opt)
85
+ @options[:method] = method
86
+
87
+ # for upload files
88
+ if @options[:files].is_a?(Array) && 'post'.eql?(method)
89
+ build_multipart
90
+ else
91
+ if @options[:parameters].is_a? Hash
92
+ @options[:parameters] = @options[:parameters].collect{|k, v|
93
+ CGI.escape(k.to_s) + '=' + CGI.escape(v.to_s)
94
+ }.join('&')
95
+ end
96
+ end
97
+
98
+ http = if @options[:proxy_addr]
99
+ if @options[:proxy_user] and @options[:proxy_pass]
100
+ Net::HTTP::Proxy(@options[:proxy_addr], @options[:proxy_port], @options[:proxy_user], @options[:proxy_pass]).new(@u.host, @u.port)
101
+ else
102
+ Net::HTTP::Proxy(@options[:proxy_addr], @options[:proxy_port]).new(@uri.host, @uri.port)
103
+ end
104
+ else
105
+ Net::HTTP.new(@uri.host, @uri.port)
106
+ end
107
+
108
+ # ssl support
109
+ http.use_ssl = true if @uri.scheme =~ /^https$/i
110
+
111
+ # get data by post or get method.
112
+ response = send_request http
113
+
114
+ return response unless @options[:redirect]
115
+
116
+ # redirect....===>>>
117
+ case response
118
+ when Net::HTTPRedirection
119
+ @options[:url] = if response['location'] =~ /^http[s]*:\/\//i
120
+ response['location']
121
+ else
122
+ @uri.scheme + '://' + @uri.host + ':' + @uri.port.to_s + response['location']
123
+ end
124
+ @redirect_times = 0 unless @redirect_times
125
+ @redirect_times = @redirect_times.succ
126
+ raise 'too deep redirect...' if @redirect_times > @options[:redirect_limits]
127
+ request('get', @options)
128
+ else
129
+ response
130
+ end
131
+ end
132
+
133
+ # for ftp
134
+ def self.ftp(method, options)
135
+ require 'net/ftp'
136
+ options = {:close => true}.merge(options)
137
+ options[:url] = "ftp://#{options[:url]}" unless options[:url] =~ /^ftp:\/\//
138
+ uri = URI(options[:url])
139
+ guest_name, guest_pass = 'anonymous', 'guest@' + uri.host
140
+ unless options[:username]
141
+ options[:username], options[:password] = uri.userinfo ? uri.userinfo.split(':') : [guest_name, guest_pass]
142
+ end
143
+ options[:username] = guest_user unless options[:username]
144
+ options[:password] = guest_pass unless options[:password]
145
+ ftp = Net::FTP.open(uri.host, options[:username], options[:password])
146
+ return ftp unless method
147
+ stat = case method.to_sym
148
+ when :get
149
+ options[:to] = File.basename(uri.path) unless options[:to]
150
+ ftp.getbinaryfile(uri.path, options[:to])
151
+ when :put
152
+ ftp.putbinaryfile(options[:from], uri.path)
153
+ when :mkdir, :rmdir, :delete, :size, :mtime, :list, :nlst
154
+ ftp.method(method).call(uri.path)
155
+ when :rename
156
+ ftp.rename(uri.path, options[:to]) if options[:to]
157
+ when :status
158
+ ftp.status
159
+ else
160
+ return ftp
161
+ end
162
+ if options[:close]
163
+ ftp.close
164
+ stat
165
+ else
166
+ ftp.response = stat
167
+ ftp
168
+ end
169
+ end
170
+
171
+ # catch all of http requests
172
+ def self.method_missing(method_name, args)
173
+ method_name = method_name.to_s.downcase
174
+ raise NoHttpMethodException, "No such http method can be called: #{method_name}" unless self.http_methods.include?(method_name)
175
+ self.instance.request(method_name, args)
176
+ end
177
+
178
+ private
179
+
180
+ # for upload files by post method
181
+ def build_multipart
182
+ require 'md5'
183
+ boundary = MD5.md5(rand.to_s).to_s[0..5]
184
+ @headers['Content-type'] = "multipart/form-data, boundary=#{boundary}"
185
+ multipart = []
186
+ if @options[:parameters]
187
+ @options[:parameters] = CGI.parse(@options[:parameters]) if @options[:parameters].is_a? String
188
+ if @options[:parameters].is_a? Hash
189
+ @options[:parameters].each {|k, v|
190
+ multipart << "--#{boundary}"
191
+ multipart << "Content-disposition: form-data; name=\"#{CGI.escape(k.to_s)}\""
192
+ multipart << "\r\n#{CGI.escape(v.to_s)}"
193
+ }
194
+ end
195
+ end
196
+ @options[:files].each_with_index {|f, index|
197
+ f[:field_name] ||= "files[]"
198
+ f[:file_name] ||= "#{boundary}_#{index}"
199
+ f[:transfer_encoding] ||= "binary"
200
+ f[:content_type] ||= 'application/octet-stream'
201
+ multipart << "--#{boundary}"
202
+ multipart << "Content-disposition: form-data; name=\"#{f[:field_name]}\"; filename=\"#{f[:file_name]}\""
203
+ multipart << "Content-type: #{f[:content_type]}"
204
+ multipart << "Content-Transfer-Encoding: #{f[:transfer_encoding]}"
205
+ multipart << "\r\n#{f[:file_content]}"
206
+ }
207
+ multipart << "--#{boundary}--"
208
+ multipart = multipart.join("\r\n")
209
+ @headers['Content-length'] = "#{multipart.size}"
210
+ @options[:parameters] = multipart
211
+ end
212
+
213
+ # send request
214
+ def send_request(http)
215
+ case @options[:method]
216
+ when /^(get|head|options|delete|move|copy|trace|)$/
217
+ @options[:parameters] = @uri.query.to_s if @options[:parameters].to_s.empty?
218
+ @options[:parameters] = "?#{@options[:parameters]}" unless @options[:parameters].empty?
219
+ http.method(@options[:method]).call("#{@uri.path}#{@options[:parameters]}", @headers)
220
+ else
221
+ http.method(@options[:method]).call(@uri.path, @options[:parameters], @headers)
222
+ end
223
+ end
224
+ end
225
+
226
+ # get cookies as hash
227
+ class Net::HTTPResponse
228
+ def cookies
229
+ cookies = {}
230
+ ignored_cookie_names = %w{expires domain path secure httponly}
231
+ self['set-cookie'].split(/[;,]/).each {|it|
232
+ next unless it.include? '='
233
+ eq = it.index('=')
234
+ key = it[0...eq].strip
235
+ value = it[eq.succ..-1]
236
+ next if ignored_cookie_names.include? key.downcase
237
+ cookies[key] = value
238
+ }
239
+ cookies
240
+ end
241
+ end
242
+
243
+ # for ftp response
244
+ class Net::FTP
245
+ def response=(response)
246
+ @_response = response
247
+ end
248
+
249
+ def response
250
+ @_response
251
+ end
252
+ end
253
+
254
+ # exception
255
+ class NoHttpMethodException < Exception; end
256
+
257
+ # for command line
258
+ if __FILE__.eql? $0
259
+ method, url, params = ARGV
260
+ exit unless method
261
+ source_method = method
262
+ method = method.split('_')[0] if method.include? '_'
263
+
264
+ # fix path of the url
265
+ url = "http://#{url}" unless url =~ /^(http:\/\/)/i
266
+
267
+ params = if params
268
+ "{:url => '#{url}', :parameters => '" + params + "'}"
269
+ else
270
+ "'#{url}'"
271
+ end
272
+
273
+ if HttpRequest.http_methods.include?(method) && url
274
+ http = eval("HttpRequest.#{method}(#{params})")
275
+ case source_method
276
+ when /_only_header$/
277
+ http.each{|k,v| puts "#{k}: #{v}"}
278
+ when /_with_header$/
279
+ http.each{|k,v| puts "#{k}: #{v}"}
280
+ print http.body unless http.body.to_s.empty?
281
+ else
282
+ print http.body unless http.body.to_s.empty?
283
+ end
284
+ end
285
+
286
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_request.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - xianhua.zhou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-11 00:00:00 +08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: xianhua.zhou@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - Changelog
26
+ - README.rdoc
27
+ - lib/http_request.rb
28
+ has_rdoc: true
29
+ homepage: http://httprequest.rubyforge.org
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project: http_request.rb
50
+ rubygems_version: 1.3.1
51
+ signing_key:
52
+ specification_version: 2
53
+ summary: http_request.rb is a small, lightweight, powerful HttpRequest class based on the 'net/http' and 'net/ftp' libraries
54
+ test_files: []
55
+