fresh_simplehttp 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1,4 @@
1
+ * Tim Becker (tim@kuriositaet.de)
2
+ * Minero Aoki (setup.rb)
3
+ * Clint Pachl
4
+ * Dave Myron
data/CHANGELOG ADDED
@@ -0,0 +1,20 @@
1
+ = Mon Sep 22 15:12:44 CEST 2008
2
+ * General code cleanup
3
+ * Additional Docs
4
+ * Reluctantly changes tabs to (ruby default) spaces (YUCK!)
5
+ = Mon Sep 22 13:25:22 CEST 2008
6
+ * bugfix: uri query parameter preserved on post req
7
+
8
+ = Sun Sep 21 18:29:20 CEST 2008
9
+ * changes to redirect handling
10
+ * bugfix make_query
11
+
12
+ = Wed Sep 26 16:25:55 2007
13
+ implemented +head+, +options+ and +trace+,
14
+ made filenames easier. 'simple_http' -> 'simplehttp'
15
+
16
+ = Fri Feb 9 12:23:20 CET 2007
17
+ * easier access to response headers
18
+ * pass through headers during redirects
19
+ * more tests and documentation
20
+ * included `setup.rb`
data/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ This package is copyrighted free software by Tim Becker <tim@kuriositaet.de>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ (see COPYING.txt file), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
58
+
data/README ADDED
@@ -0,0 +1,96 @@
1
+ = SimpleHttp - a simplified wrapper around Net::Http
2
+
3
+ SimpleHttp aims to reduce the complexity of Net::Http while providing
4
+ the most commonly used (by me) http functionality.
5
+
6
+ INSTALLATION
7
+
8
+ * Using +gem+
9
+
10
+ gem install simplehttp
11
+
12
+ * Using +setup.rb+
13
+
14
+ ruby setup.rb config
15
+ ruby setup.rb install
16
+
17
+ * tarball and zip packages are available from
18
+ RubyForge[http://rubyforge.org/projects/simplehttp/]
19
+
20
+
21
+
22
+ FEATURES / USAGE
23
+
24
+ * Require the lib:
25
+
26
+ require 'simplehttp'
27
+
28
+ * No fuss one line GET and POST requests:
29
+
30
+ str = SimpleHttp.get "http://www.example.com"
31
+ str = SimpleHttp.get "www.example.com"
32
+
33
+ * Can use URI or String url interchangibly
34
+
35
+ str = SimpleHttp.get URI.parse "http://www.example.com/"
36
+
37
+ * Transparent Proxy Handling. Uses the 'http_proxy' environment
38
+ variable if set, also provides a +set_proxy+ method.
39
+
40
+ http = SimpleHttp.new "http://www.example.com"
41
+ http.set_proxy "http://proxy.example.com:8000"
42
+ http.post "query" => "example_query"
43
+
44
+ * POST sends ruby Hashes as 'application/x-www-form/urlencoded' per
45
+ default, but can send any data.
46
+
47
+ http = SimpleHttp.new "http://www.example.com/image_upload"
48
+ http.post imageData, "img/png"
49
+
50
+ * Automatically handles SSL
51
+
52
+ str = SimpleHttp.get "https://secure.example.com"
53
+
54
+ * Easy HTTP Basic Authentication
55
+ str = SimpleHttp.get URI.parse("http://usr:pwd@www.example.com")
56
+ #or
57
+ http = SimpleHttp.new "http://www.example.com"
58
+ http.basic_authentication "user", "password"
59
+ http.post "query" => "example_query"
60
+
61
+ * Access headers of the request or response
62
+ http = SimpleHttp.new "www.example.com"
63
+ http.request_headers["X-Custom-Header"]="useful header"
64
+ http.get
65
+ puts "server set cookie: #{http.response_headers['set-cookie']}"
66
+
67
+ * Automatically follows Http Redirects.
68
+
69
+
70
+ The +get+ and +post+ methods return a +String+ containing the
71
+ body of the request if the request was successful (HTTP 200). In case of
72
+ a redirect, the redirect is followed and the ultimate response is
73
+ returned. Per Default, up to three redirects are followed, this
74
+ behaviour can be modified by setting +follow_num_redirects+.
75
+
76
+ In case of any other type of response, an exception is raised.
77
+
78
+ The default behaviour can be modified by registering handlers
79
+ using the +register_response_handler+ method. E.g. if you'd like to
80
+ retrieve the +Date+ header instead of the body for successful
81
+ transactions:
82
+
83
+ http = SimpleHttp.new ...
84
+ http.register_response_handler(Net::HTTPSuccess) {|req,res,http|
85
+ res['date']
86
+ }
87
+
88
+ Or you'd like to print the +Location+ and then raise an exception in
89
+ case of a redirect:
90
+
91
+
92
+ http = SimpleHttp.new ...
93
+ http.register_response_handler(Net::HTTPRedirect) {|req,res,http|
94
+ puts res['location']
95
+ raise "REDIRECT not allowed!"
96
+ }
data/Rakefile ADDED
@@ -0,0 +1,137 @@
1
+ require "rake/rdoctask"
2
+ require "rake/gempackagetask"
3
+ require "rake/testtask"
4
+ require "rake/clean"
5
+ require "rubygems"
6
+
7
+ require "lib/simple_http"
8
+
9
+ # Specifies the default task to execute. This is often the "test" task
10
+ # and we'll change things around as soon as we have some tests.
11
+
12
+ task :default => [:rdoc]
13
+
14
+ # The directory to generate +rdoc+ in.
15
+ RDOC_DIR="doc/html"
16
+
17
+ # This global variable contains files that will be erased by the `clean` task.
18
+ # The `clean` task itself is automatically generated by requiring `rake/clean`.
19
+
20
+ CLEAN << RDOC_DIR
21
+
22
+ begin
23
+ require 'jeweler'
24
+ Jeweler::Tasks.new do |gemspec|
25
+ gemspec.name = "fresh_simplehttp"
26
+ gemspec.summary = "simple_http: Simple Http client lib."
27
+ gemspec.description = "simple_http: Simple Http client lib. Use to do http requests without noise."
28
+ gemspec.email = "wilkerlucio@gmail.com"
29
+ gemspec.homepage = "http://github.com/wilkerlucio/simplehttp"
30
+ gemspec.authors = ["Wilker Lucio"]
31
+
32
+ gemspec.files.exclude "pkg/**/*"
33
+ gemspec.files.exclude "test/**/*"
34
+ end
35
+ Jeweler::GemcutterTasks.new
36
+ rescue LoadError
37
+ puts "Jeweler not available. Install it with: gem install jeweler"
38
+ end
39
+
40
+ # This is the task that generates the +rdoc+ documentation from the
41
+ # source files. Instantiating Rake::RDocTask automatically generates a
42
+ # task called `rdoc`.
43
+
44
+ Rake::RDocTask.new do |rd|
45
+ # Options for documenation generation are specified inside of
46
+ # this block. For example the following line specifies that the
47
+ # content of the README file should be the main page of the
48
+ # documenation.
49
+ rd.main = "README"
50
+
51
+ # The following line specifies all the files to extract
52
+ # documenation from.
53
+ rd.rdoc_files.include( "README", "AUTHORS", "LICENSE", "TODO",
54
+ "CHANGELOG", "bin/**/*", "lib/**/*.rb",
55
+ "examples/**/*rb","test/**/*.rb", "doc/*.rdoc")
56
+ # This one specifies the output directory ...
57
+ rd.rdoc_dir = "doc/html"
58
+
59
+ # Or the HTML title of the generated documentation set.
60
+ rd.title = "simple_http: Simple Http client lib."
61
+
62
+ # These are options specifiying how source code inlined in the
63
+ # documentation should be formatted.
64
+
65
+ rd.options = ["--line-numbers", "--inline-source"]
66
+
67
+ # Check:
68
+ # `rdoc --help` for more rdoc options
69
+ # the {rdoc documenation home}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html]
70
+ # or the documentation for the +Rake::RDocTask+ task[http://rake.rubyforge.org/classes/Rake/RDocTask.html]
71
+ end
72
+
73
+ # The GemPackageTask facilitates getting all your files collected
74
+ # together into gem archives. You can also use it to generate tarball
75
+ # and zip archives.
76
+
77
+ # First you'll need to assemble a gemspec
78
+
79
+ PROJECT_NAME = "simplehttp"
80
+ PKG_VERSION = SimpleHttp::VERSION
81
+ PKG_FILES = FileList['lib/**/*.rb', 'bin/**/*', 'examples/**/*', '[A-Z]*', 'test/**/*'].to_a
82
+
83
+ spec = Gem::Specification.new do |s|
84
+ s.platform = Gem::Platform::RUBY
85
+ s.summary = "simple_http: Simple Http client lib."
86
+ s.name = PROJECT_NAME
87
+ s.version = PKG_VERSION
88
+ s.files = PKG_FILES
89
+ s.requirements << "none"
90
+ s.require_path = 'lib'
91
+ s.description = <<END_DESC
92
+ Wrapper around net/http to provide quick and dirty http access.
93
+ END_DESC
94
+ end
95
+
96
+ # Adding a new GemPackageTask adds a task named `package`, which generates
97
+ # packages as gems, tarball and zip archives.
98
+ Rake::GemPackageTask.new(spec) do |pkg|
99
+ pkg.need_zip = true
100
+ pkg.need_tar_gz = true
101
+ end
102
+
103
+
104
+ # This task is used to demonstrate how to upload files to Rubyforge.
105
+ # Calling `upload_page` creates a current version of the +rdoc+
106
+ # documentation and uploads it to the Rubyforge homepage of the project,
107
+ # assuming it's hosted there and naming conventions haven't changed.
108
+ #
109
+ # This task uses `sh` to call the `scp` binary, which is plattform
110
+ # dependant and may not be installed on your computer if you're using
111
+ # Windows. I'm currently not aware of any pure ruby way to do scp
112
+ # transfers.
113
+
114
+ RubyForgeUser="a2800276"
115
+ RubyForgeProject=PROJECT_NAME
116
+
117
+ desc "Upload the web pages to the web."
118
+ task :upload_pages => ["clean", :rdoc] do
119
+ if RubyForgeProject then
120
+ path = "/var/www/gforge-projects/#{RubyForgeProject}"
121
+ sh "scp -r doc/html/* #{RubyForgeUser}@rubyforge.org:#{path}"
122
+ sh "scp doc/images/*.png #{RubyForgeUser}@rubyforge.org:#{path}/images"
123
+ end
124
+ end
125
+
126
+
127
+ # This task will run the unit tests provided in files called
128
+ # `test/test*.rb`. The task itself can be run with a call to `rake test`
129
+
130
+ Rake::TestTask.new do |t|
131
+ t.libs << "test"
132
+ t.libs << "lib"
133
+ t.test_files = FileList['test/*.rb']
134
+ t.verbose = true
135
+ end
136
+
137
+
data/TODO ADDED
@@ -0,0 +1,28 @@
1
+ * Provide tests and documentation for +head+, +options+ and +trace+
2
+
3
+ * There seems to be a bug in webrick that it doesn't recognize the
4
+ Content-Length header if using basic authentication. The POST test
5
+ cases lead to a:
6
+ ERROR HTTPRequest#fixup: WEBrick::HTTPStatus::LengthRequired occured.
7
+ even though the Content-Length header is set correctly in the http
8
+ packet...
9
+
10
+ * I've not figured out how to set_up and teardown webbrick properly.
11
+ Since webbrick blocks after calling `start`, it needs to started in a
12
+ seperate thread. I didn't handle communication with it properly
13
+ though. Test::Unit calls set_up and teardown before
14
+ and after executing each test... method, and not as I expected, before
15
+ and after each test file. This leads to a new TestServer being
16
+ instantiated which complains "bind-adress already in use", because the
17
+ other instance wasn't properly shut down. I tried to dix this by setting
18
+ up the server in the constructor, but that has the same effect.
19
+ It seems like a new instance of TestCase is instantiated to run every
20
+ single test... method.
21
+
22
+ * There also seems to be something screwy about how rake calls the
23
+ tests. Some ruby files seem to be included twice. This leads to
24
+ "already initialized constant" error in the output of the unit tests.
25
+
26
+ * The two previous bugs aren't really problematic, because they only
27
+ make the output of the tests ugly. They should be easy to fix... (But
28
+ they're not high on my list of priorities.)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.7
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{fresh_simplehttp}
8
+ s.version = "0.1.7"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Wilker Lucio"]
12
+ s.date = %q{2010-04-22}
13
+ s.description = %q{simple_http: Simple Http client lib. Use to do http requests without noise.}
14
+ s.email = %q{wilkerlucio@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ "AUTHORS",
22
+ "CHANGELOG",
23
+ "LICENSE",
24
+ "README",
25
+ "Rakefile",
26
+ "TODO",
27
+ "VERSION",
28
+ "fresh_simplehttp.gemspec",
29
+ "lib/fresh_simplehttp.rb",
30
+ "lib/simple_http.rb",
31
+ "lib/simplehttp.rb",
32
+ "setup.rb",
33
+ "simplehttp.gemspec"
34
+ ]
35
+ s.homepage = %q{http://github.com/wilkerlucio/simplehttp}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.6}
39
+ s.summary = %q{simple_http: Simple Http client lib.}
40
+ s.test_files = [
41
+ "test/http_test.rb",
42
+ "test/http_test_server.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
55
+
@@ -0,0 +1,7 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+
5
+ # kept for backwards compatibility
6
+ #
7
+ require 'simplehttp.rb'
@@ -0,0 +1,7 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+
5
+ # kept for backwards compatibility
6
+ #
7
+ require 'simplehttp.rb'
data/lib/simplehttp.rb ADDED
@@ -0,0 +1,482 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+
5
+ require 'net/http'
6
+ require 'net/https'
7
+ require 'uri'
8
+ require 'cgi'
9
+ require 'base64'
10
+
11
+
12
+ # Wrapper around ruby's standard net/http classes. Currently, only GET
13
+ # and POST https methods are supported. `SimpleHttp` provides class
14
+ # methods `get` and `post` to handle basic functionality. In case more
15
+ # complicated requests need to be made or default settings need to be
16
+ # overriden, it's possible to instantiate `SimpleHttp` and use instance
17
+ # methods `get` and `put`.
18
+ #
19
+ #
20
+ # Features:
21
+ #
22
+ # * Handles Redirects automatically
23
+ # * Proxy used transparently if http_proxy environment variable is
24
+ # set.
25
+ # * SSL handled automatically
26
+ # * fault tolerant uri, e.g. all of these would work:
27
+ # "www.example.com", "www.example.com/", "http://www.example.com"
28
+ #
29
+ # Some usage examples:
30
+ # # plain GET (using class methods)
31
+ # SimpleHttp.get "www.example.com"
32
+ #
33
+ # # POST using the instance methods
34
+ # uri = URI.parse "https://www.example.com/index.html"
35
+ # sh = SimpleHttp uri
36
+ # sh.set_proxy "my.proxy", "8080"
37
+ # sh.post {"query" => "query_data"}
38
+ #
39
+ # # POST using class methods.
40
+ # binaryData = getImage
41
+ # SimpleData.post binaryData, "image/png"
42
+ #
43
+ # # GET requst with a custom request_header
44
+ # sh = SimpleHttp.new "http://www.example.com"
45
+ # sh.request_headers= {'X-Special-Http-Header'=>'my-value'}
46
+ # sh.get
47
+ class SimpleHttp
48
+
49
+ VERSION='0.1.5'
50
+
51
+ # Host component of proxy uri
52
+ attr_accessor :proxy_host
53
+ # Port component of proxy uri
54
+ attr_accessor :proxy_port
55
+ # Proxy User
56
+ attr_accessor :proxy_user
57
+ # Proxy Password
58
+ attr_accessor :proxy_pwd
59
+ # The +URI+ object to connect to
60
+ attr_reader :uri
61
+ # +Hash+ of headers that will be sent in the request.
62
+ attr_accessor :request_headers
63
+ # +Hash+ of headers that were set in the response.
64
+ attr_accessor :response_headers
65
+ # A +Hash+ of handlers for each class of HTTPResponse.
66
+ attr_accessor :response_handlers
67
+ # The number of redirects we should follow. Default 5.
68
+ # An exception gets raised after the fifth redirect.
69
+ attr_accessor :follow_num_redirects
70
+
71
+ RESPONSE_HANDLERS = {
72
+ Net::HTTPResponse => lambda { |request, response, http|
73
+ http._update_response_headers(response)
74
+ raise "#{response.to_s} : #{response.code} : #{http.uri}"
75
+ },
76
+ Net::HTTPSuccess => lambda { |request, response, http|
77
+ http._update_response_headers(response)
78
+ #http.cookies += response.cookies
79
+ case request
80
+ when Net::HTTP::Head, Net::HTTP::Options
81
+ http.response_headers
82
+ else
83
+ response.body
84
+ end
85
+ },
86
+ Net::HTTPRedirection => lambda { |request, response, http|
87
+ raise "too many redirects!" unless http.follow_num_redirects > 0
88
+ # create a new SimpleHttp for the location
89
+ # refered to decreasing the remaining redirects
90
+ # by one.
91
+
92
+ if (location = response['location']) !~ /^https?:\/\//
93
+ new_location = "#{http.uri.scheme}://#{http.uri.host}"
94
+ if location =~ /^\//
95
+ new_location += location
96
+ else
97
+ new_location += "/#{http.uri.path}/#{location}"
98
+ end
99
+ location = new_location
100
+ end
101
+
102
+ sh = SimpleHttp.new location
103
+ #STDERR.puts location
104
+ sh.follow_num_redirects = http.follow_num_redirects-1
105
+
106
+ # copy the response handlers used in the current
107
+ # request in case they were non standard.
108
+ sh.response_handlers = http.response_handlers
109
+
110
+ # copy the request headers
111
+ sh.request_headers=http.request_headers
112
+ sh.response_headers=http.response_headers
113
+ #sh.cookies+=http.cookies
114
+
115
+ # copy host and port
116
+ sh.uri.host = http.uri.host
117
+ sh.uri.port = http.uri.port
118
+
119
+ # HTTP doesn't permit redirects for methods other than
120
+ # GET or HEAD. The exception is 303 redirects, which
121
+ # should automatically follow the redirect URI using a
122
+ # GET method regardless of the initial method. For
123
+ # other classes of redirection, the client is required
124
+ # to prompt the user before redirection occurs. Because
125
+ # that's not a feasible action for this library, all
126
+ # 3xx redirect URIs are followed using a GET method.
127
+ #
128
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
129
+
130
+ case request
131
+ when Net::HTTP::Get,
132
+ Net::HTTP::Head,
133
+ Net::HTTP::Options
134
+ sh.get
135
+ when Net::HTTP::Post
136
+ sh.request_headers['content-length']=nil
137
+ sh.get
138
+ else
139
+ raise "Not a valid HTTP method for redirection: #{request.class}"
140
+ end
141
+
142
+ }
143
+
144
+ }
145
+
146
+ # SimpleHttp can either be used directly through the +get+ and
147
+ # +post+ class methods or be instantiated, in case you need to
148
+ # to add custom behaviour to the requests.
149
+ #
150
+ # @param may be a URI or a String.
151
+ #
152
+ # Example:
153
+ # http = SimpleHttp.new(URI.parse("http://www.example.com"))
154
+ # http = SimpleHttp.new "www.example.com"
155
+ # http = SimpleHttp.new "http://usr:pwd@www.example.com:1234"
156
+ def initialize uri
157
+ set_proxy ENV['http_proxy'] if ENV['http_proxy']
158
+
159
+ if uri.class == String
160
+ unless uri =~ /^https?:\/\//
161
+ uri = "http://#{uri}"
162
+ end
163
+ uri = URI.parse uri
164
+ end
165
+ @uri = uri
166
+
167
+ if !@uri.path || "" == @uri.path.strip
168
+ @uri.path="/"
169
+ end
170
+
171
+ @request_headers={}
172
+ @response_headers={}
173
+ @cookies=[]
174
+ @response_handlers=RESPONSE_HANDLERS.clone
175
+ @follow_num_redirects=5
176
+
177
+ if @uri.user
178
+ basic_authentication @uri.user, @uri.password
179
+ end
180
+
181
+ end
182
+
183
+ #
184
+ # Provides facilities to perform http basic authentication. You
185
+ # don't need to provide +usr+ and +pwd+ if they are already included
186
+ # in the uri, i.e. http://user:password@www.example.com/
187
+ #
188
+ # Usage:
189
+ # sh = SimpleHttp.new "www.example.com/password_protected_resource"
190
+ # sh.basic_authentication "user_name", "secret_password"
191
+ # sh.get
192
+ #
193
+
194
+ def basic_authentication usr, pwd
195
+ @basic_auth = [usr, pwd]
196
+ end
197
+
198
+ #
199
+ # This method can be used to register response handlers for specific
200
+ # http responses in case you need to override the default behaviour.
201
+ # Defaults are:
202
+ #
203
+ # <b>HTTPSuccess (200-206)</b> :: return the body of the response
204
+ # <b>HTTPRedirection (300-307)</b> :: follow the redirection until success
205
+ # *Others* :: raise an exception
206
+ #
207
+ # ===Parameters:
208
+ #
209
+ # +clazz+ is the subclass of <code>Net::HTTPResponse</code> (or +HTTPResponse+ in case you
210
+ # want to define "default" behaviour) that you are registering the
211
+ # handler for. E.g. to register a handler for a HTTP 303 response, +clazz+
212
+ # needs to be +HTTPSeeOther+.
213
+ #
214
+ # +block+ is the handler itself. When a response of the appropriate class
215
+ # is received by the library, +block+ is called with three parameters: the
216
+ # 'raw' <code>Net::HTTPRequest</code>, the actual +HTTPResponse+ object that was received
217
+ # and a reference to the instance of +SimpleHttp+ that is executing the
218
+ # call.
219
+ #
220
+ # ===Example:
221
+ #
222
+ # # to override the default action of following a HTTP
223
+ # # redirect, you could register the folllowing handler:
224
+ #
225
+ # sh = SimpleHttp "www.example.com"
226
+ # sh.register_response_handler Net::HTTPRedirection {|request, response, shttp|
227
+ # response['location']
228
+ # }
229
+ #
230
+
231
+ def register_response_handler clazz, &block
232
+ # completely unnecessary sanity check to make sure parameter
233
+ # `clazz` is in fact a HTTPResponse ...
234
+ unless clazz.ancestors.include? Net::HTTPResponse
235
+ raise "Trying to register a response handler for non-response class: #{clazz}"
236
+ end
237
+ @response_handlers[clazz]=block
238
+
239
+ end
240
+
241
+ #
242
+ # Set the proxy to use for the http request.
243
+ #
244
+ # Note: you don't need to set the proxy in case the
245
+ # +http_proxy+ environment variable is set.
246
+ #
247
+ # To override previous proxy settings and connect directly,
248
+ # call +set_proxy+ +nil+.
249
+ #
250
+ # ===Usage:
251
+ #
252
+ # http = SimpleHttp.new "www.example.com"
253
+ #
254
+ # http.set_proxy "http://proxy:8000"
255
+ # or:
256
+ # http.set_proxy(URI.parse("http://proxy:8000"))
257
+ # or:
258
+ # http.set_proxy 'proxy', '8000', 'my_user', 'secret'
259
+ # or:
260
+ # http.set_proxy nil # to override previous proxy
261
+ # settings and make the request directly.
262
+ #
263
+
264
+
265
+ def set_proxy proxy, port=nil, user=nil, pwd=nil
266
+
267
+
268
+ if !proxy
269
+ @proxy_host=@proxy_port=@proxy_user=@proxy_pwd=nil
270
+ return
271
+ end
272
+
273
+ if String === proxy
274
+ if !port && !user && !pwd
275
+ proxy = URI.parse(proxy)
276
+ else
277
+ @proxy_host= host
278
+ @proxy_port= port
279
+ @proxy_user= user
280
+ @proxy_pwd = pwd
281
+ end
282
+ end
283
+
284
+ if URI::HTTP === proxy
285
+ @proxy_host= proxy.host
286
+ @proxy_port= proxy.port
287
+ @proxy_user= proxy.user
288
+ @proxy_pwd = proxy.password
289
+ end
290
+ end
291
+
292
+ # ===Internal
293
+ # Takes a HTTPResponse (or subclass) and determines how to
294
+ # handle the response. Default behaviour is:
295
+ #
296
+ # HTTPSuccess : return the body of the response
297
+ # HTTPRedirection : follow the redirect until success.
298
+ # default : raise the HTTPResponse.
299
+ #
300
+ # the default behaviour can be overidden by registering a
301
+ # response handler using the `register_response_handler` method.
302
+ #
303
+
304
+ def _handle_response http_request, http_response
305
+ raise "Not a Net::HTTPResponse" unless http_response.is_a? Net::HTTPResponse
306
+
307
+ c = http_response.class
308
+ # Go up the inheritance chain to find the most specific handler
309
+ # for the class of response we received.
310
+ while c!=Object
311
+ # the response_handlers hash contains a handler
312
+ # for the specific response class.
313
+ if @response_handlers[c]
314
+ return @response_handlers[c].call(http_request, http_response, self)
315
+ end
316
+ c=c.superclass
317
+ end
318
+
319
+ # if we reached this place, no handler was registered
320
+ # for this response. default is to return the response.
321
+
322
+ return http_response
323
+ end
324
+
325
+ # ===Internal
326
+ #
327
+ # ===Parameter
328
+ # +request+ the <code>Net::HTTPRequest</code> to process.
329
+ def _do_http request
330
+ http = Net::HTTP.new(@uri.host, @uri.port,
331
+ @proxy_host, @proxy_port, @proxy_user, @proxy_pwd)
332
+ http.use_ssl = @uri.scheme == 'https'
333
+ request.basic_auth(@basic_auth[0], @basic_auth[1]) if @basic_auth
334
+
335
+ # add custom request headers.
336
+ @request_headers.each {|key,value|
337
+ request[key]=value;
338
+ }
339
+
340
+ response = http.request(request)
341
+ _handle_response(request, response);
342
+ end
343
+
344
+ # ===Internal
345
+ def _make_query query
346
+ return query unless query && query.class == Hash
347
+ query.inject([]) do |s, (key, value)|
348
+ s << CGI::escape(key) + "=" + CGI::escape(value)
349
+ end.join('&')
350
+ end
351
+
352
+ # Make a simple GET request to the provided URI.
353
+ #
354
+ # ===Parameter
355
+ #
356
+ # +uri+ :: the uri to connect to, may be a +URI+ or a +String+
357
+ # +query+ :: the query part of the +get+, may be a +String+ or +Hash+
358
+ #
359
+ # ===Usage:
360
+ #
361
+ # puts(SimpleHttp.get("www.example.com"))
362
+ # puts(SimpleHttp.get("www.example.com", "param"=>"value")
363
+ def self.get uri, query=nil
364
+ http = SimpleHttp.new uri
365
+ http.get query
366
+ end
367
+
368
+ # Make a simple +HEAD+ request
369
+ #
370
+ # ===Parameter
371
+ # see +get+
372
+ def self.head uri, query=nil
373
+ http = SimpleHttp.new uri
374
+ http.head query
375
+ end
376
+
377
+ # Make a simple +OPTIONS+ request
378
+ def self.options uri
379
+ http = SimpleHttp.new uri
380
+ http.options
381
+ end
382
+
383
+ # Make a simple +TRACE+ request
384
+ def self.trace uri
385
+ http = SimpleHttp.new uri
386
+ http.trace
387
+ end
388
+
389
+ # Make a POST request to the provided URI.
390
+ #
391
+ # ===Example:
392
+ # puts(SimpleHttp.post("www.example.com", "query"=>"my_query"))
393
+ #
394
+ # Alternatively, to post arbitrary data, all you need to do is
395
+ # set the appriate +content_type+:
396
+ #
397
+ # SimpleHttp.post("http://www.example.com/", binary_data, "img/png")
398
+
399
+ def self.post uri, query=nil, content_type='application/x-www-form-urlencoded'
400
+ http = SimpleHttp.new uri
401
+ http.post query, content_type
402
+ end
403
+
404
+ # Call the +get+ method as an instance method if you need to
405
+ # modify the default behaviour of the library, or set special
406
+ # headers:
407
+ #
408
+ # http = SimpleHttp.new "www.example.com"
409
+ # http.request_headers["X-Special"]="whatever"
410
+ # str = http.get
411
+ def get query = nil
412
+ req = Net::HTTP::Get.new( _handle_path(query) )
413
+ # puts Net::HTTP::Proxy(@proxy_host, @proxy_port, @proxy_user, @proxy_pwd).get(@uri)
414
+ _do_http req
415
+ end
416
+
417
+ #
418
+ # Call the +head+ method as an instance method.
419
+ # see +head+
420
+ def head query = nil
421
+ req = Net::HTTP::Head.new( _handle_path(query) )
422
+ # puts Net::HTTP::Proxy(@proxy_host, @proxy_port, @proxy_user, @proxy_pwd).get(@uri)
423
+ _do_http req
424
+ end
425
+
426
+ # Call http +options+ method. Returns the response
427
+ # see +options+
428
+ def options
429
+ # we don't support sending a payload in options' body.
430
+ req = Net::HTTP::Options.new(@uri.path)
431
+ _do_http req
432
+ end
433
+
434
+ # Call http +trace+ method. Returns the response
435
+ # see +trace+
436
+ def trace
437
+ # payload?
438
+ req = Net::HTTP::Trace.new(@uri.path)
439
+ _do_http req
440
+ end
441
+
442
+ #
443
+ # Post the query data to the url.
444
+ #
445
+ # The body of the request remains empty if query=nil.
446
+ #
447
+ # In case +query+ is a +Hash+, it's assumed that we are
448
+ # sending a form.
449
+ #
450
+ # In case +query+ is a +String+, it's also assumed that a
451
+ # form is being sent, UNLESS the +content_type+ parameter
452
+ # is set.
453
+ #
454
+ def post query=nil, content_type='application/x-www-form-urlencoded'
455
+ req = Net::HTTP::Post.new( _handle_path() )
456
+ req.body= _make_query query if query
457
+ req.content_type=content_type if query
458
+ req.content_length=query ? req.body.length : 0
459
+
460
+ _do_http req
461
+ end
462
+
463
+ def _handle_path query=nil
464
+ if (query = _make_query query)
465
+ @uri.query = @uri.query ? @uri.query+"&"+query : query
466
+ end
467
+ path = @uri.query ? "#{uri.path}?#{@uri.query}" : @uri.path
468
+ end
469
+
470
+ # ===Internal
471
+ # Used in the response handler to set the value of the
472
+ # response header fields.
473
+ def _update_response_headers http_response
474
+ http_response.each_header {|key, value|
475
+ self.response_headers[key]=value
476
+ }
477
+ end
478
+
479
+ end
480
+
481
+
482
+