http_request.rb 1.0.1

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