simplehttp 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGELOG +0 -0
- data/LICENSE +58 -0
- data/README +74 -0
- data/Rakefile +120 -0
- data/TODO +26 -0
- data/lib/simple_http.rb +361 -0
- data/test/http_test.rb +193 -0
- data/test/http_test_server.rb +90 -0
- metadata +54 -0
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Tim Becker (tim@kuriositaet.de)
|
data/CHANGELOG
ADDED
File without changes
|
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,74 @@
|
|
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
|
+
FEATURES / USAGE
|
7
|
+
|
8
|
+
* No fuss one line GET and POST requests:
|
9
|
+
|
10
|
+
str = SimpleHttp.get "http://www.example.com"
|
11
|
+
str = SimpleHttp.get "www.example.com"
|
12
|
+
|
13
|
+
* Can use URI or String url interchangibly
|
14
|
+
|
15
|
+
str = SimpleHttp.get URI.parse "http://www.example.com/"
|
16
|
+
|
17
|
+
* Transparent Proxy Handling. Uses the 'http_proxy' environment
|
18
|
+
variable if set, also provides a +set_proxy+ method.
|
19
|
+
|
20
|
+
http = SimpleHttp.new "http://www.example.com"
|
21
|
+
http.set_proxy "http://proxy.example.com:8000"
|
22
|
+
http.post "query" => "example_query"
|
23
|
+
|
24
|
+
* POST sends ruby Hashes as 'application/x-www-form/urlencoded' per
|
25
|
+
default, but can send any data.
|
26
|
+
|
27
|
+
http = SimpleHttp.new "http://www.example.com/image_upload"
|
28
|
+
http.post imageData, "img/png"
|
29
|
+
|
30
|
+
* Automatically handles SSL
|
31
|
+
|
32
|
+
str = SimpleHttp.get "https://secure.example.com"
|
33
|
+
|
34
|
+
* Easy HTTP Basic Authentication
|
35
|
+
str = SimpleHttp.get URI.parse("http://usr:pwd@www.example.com")
|
36
|
+
#or
|
37
|
+
http = SimpleHttp.new "http://www.example.com"
|
38
|
+
http.basic_authentication "user", "password"
|
39
|
+
http.post "query" => "example_query"
|
40
|
+
|
41
|
+
* Access headers of the request or response
|
42
|
+
http = SimpleHttp.new "www.example.com"
|
43
|
+
http.request_header["X-Custom-Header"]="useful header"
|
44
|
+
|
45
|
+
* Automatically follows Http Redirects.
|
46
|
+
|
47
|
+
|
48
|
+
The +get+ and +post+ methods return a +String+ containing the
|
49
|
+
body of the request if the request was successful (HTTP 200). In case of
|
50
|
+
a redirect, the redirect is followed and the ultimate response is
|
51
|
+
returned. Per Default, up to three redirects are followed, this
|
52
|
+
behaviour can be modified by setting +follow_num_redirects+.
|
53
|
+
|
54
|
+
In case of any other type of response, an exception is raised.
|
55
|
+
|
56
|
+
The default behaviour can be modified by registering handlers
|
57
|
+
using the +register_response_handler+ method. E.g. if you'd like to
|
58
|
+
retrieve the +Date+ header instead of the body for successful
|
59
|
+
transactions:
|
60
|
+
|
61
|
+
http = SimpleHttp.new ...
|
62
|
+
http.register_response_handler(Net::HTTPSuccess) {|req,res,http|
|
63
|
+
res['date']
|
64
|
+
}
|
65
|
+
|
66
|
+
Or you'd like to print the +Location+ and then raise an exception in
|
67
|
+
case of a redirect:
|
68
|
+
|
69
|
+
|
70
|
+
http = SimpleHttp.new ...
|
71
|
+
http.register_response_handler(Net::HTTPRedirect) {|req,res,http|
|
72
|
+
puts res['location']
|
73
|
+
raise "REDIRECT not allowed!"
|
74
|
+
}
|
data/Rakefile
ADDED
@@ -0,0 +1,120 @@
|
|
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
|
+
|
23
|
+
# This is the task that generates the +rdoc+ documentation from the
|
24
|
+
# source files. Instantiating Rake::RDocTask automatically generates a
|
25
|
+
# task called `rdoc`.
|
26
|
+
|
27
|
+
Rake::RDocTask.new do |rd|
|
28
|
+
# Options for documenation generation are specified inside of
|
29
|
+
# this block. For example the following line specifies that the
|
30
|
+
# content of the README file should be the main page of the
|
31
|
+
# documenation.
|
32
|
+
rd.main = "README"
|
33
|
+
|
34
|
+
# The following line specifies all the files to extract
|
35
|
+
# documenation from.
|
36
|
+
rd.rdoc_files.include( "README", "AUTHORS", "LICENSE", "TODO",
|
37
|
+
"CHANGELOG", "bin/**/*", "lib/**/*.rb",
|
38
|
+
"examples/**/*rb","test/**/*.rb", "doc/*.rdoc")
|
39
|
+
# This one specifies the output directory ...
|
40
|
+
rd.rdoc_dir = "doc/html"
|
41
|
+
|
42
|
+
# Or the HTML title of the generated documentation set.
|
43
|
+
rd.title = "simple_http: Simple Http client lib."
|
44
|
+
|
45
|
+
# These are options specifiying how source code inlined in the
|
46
|
+
# documentation should be formatted.
|
47
|
+
|
48
|
+
rd.options = ["--line-numbers", "--inline-source"]
|
49
|
+
|
50
|
+
# Check:
|
51
|
+
# `rdoc --help` for more rdoc options
|
52
|
+
# the {rdoc documenation home}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html]
|
53
|
+
# or the documentation for the +Rake::RDocTask+ task[http://rake.rubyforge.org/classes/Rake/RDocTask.html]
|
54
|
+
end
|
55
|
+
|
56
|
+
# The GemPackageTask facilitates getting all your files collected
|
57
|
+
# together into gem archives. You can also use it to generate tarball
|
58
|
+
# and zip archives.
|
59
|
+
|
60
|
+
# First you'll need to assemble a gemspec
|
61
|
+
|
62
|
+
PROJECT_NAME = "simplehttp"
|
63
|
+
PKG_VERSION = SimpleHttp::VERSION
|
64
|
+
PKG_FILES = FileList['lib/**/*.rb', 'bin/**/*', 'examples/**/*', '[A-Z]*', 'test/**/*'].to_a
|
65
|
+
|
66
|
+
spec = Gem::Specification.new do |s|
|
67
|
+
s.platform = Gem::Platform::RUBY
|
68
|
+
s.summary = "simple_http: Simple Http client lib."
|
69
|
+
s.name = PROJECT_NAME
|
70
|
+
s.version = PKG_VERSION
|
71
|
+
s.files = PKG_FILES
|
72
|
+
s.requirements << "none"
|
73
|
+
s.require_path = 'lib'
|
74
|
+
s.description = <<END_DESC
|
75
|
+
Wrapper around net/http to provide quick and dirty http access.
|
76
|
+
END_DESC
|
77
|
+
end
|
78
|
+
|
79
|
+
# Adding a new GemPackageTask adds a task named `package`, which generates
|
80
|
+
# packages as gems, tarball and zip archives.
|
81
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
82
|
+
pkg.need_zip = true
|
83
|
+
pkg.need_tar_gz = true
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# This task is used to demonstrate how to upload files to Rubyforge.
|
88
|
+
# Calling `upload_page` creates a current version of the +rdoc+
|
89
|
+
# documentation and uploads it to the Rubyforge homepage of the project,
|
90
|
+
# assuming it's hosted there and naming conventions haven't changed.
|
91
|
+
#
|
92
|
+
# This task uses `sh` to call the `scp` binary, which is plattform
|
93
|
+
# dependant and may not be installed on your computer if you're using
|
94
|
+
# Windows. I'm currently not aware of any pure ruby way to do scp
|
95
|
+
# transfers.
|
96
|
+
|
97
|
+
RubyForgeUser="a2800276"
|
98
|
+
RubyForgeProject=PROJECT_NAME
|
99
|
+
|
100
|
+
desc "Upload the web pages to the web."
|
101
|
+
task :upload_pages => ["rdoc", "clean"] do
|
102
|
+
if RubyForgeProject then
|
103
|
+
path = "/var/www/gforge-projects/#{RubyForgeProject}"
|
104
|
+
sh "scp -r doc/html/* #{RubyForgeUser}@rubyforge.org:#{path}"
|
105
|
+
sh "scp doc/images/*.png #{RubyForgeUser}@rubyforge.org:#{path}/images"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
# This task will run the unit tests provided in files called
|
111
|
+
# `test/test*.rb`. The task itself can be run with a call to `rake test`
|
112
|
+
|
113
|
+
Rake::TestTask.new do |t|
|
114
|
+
t.libs << "test"
|
115
|
+
t.libs << "lib"
|
116
|
+
t.test_files = FileList['test/*.rb']
|
117
|
+
t.verbose = true
|
118
|
+
end
|
119
|
+
|
120
|
+
|
data/TODO
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
* There seems to be a bug in webrick that it doesn't recognize the
|
2
|
+
Content-Length header if using basic authentication. The POST test
|
3
|
+
cases lead to a:
|
4
|
+
ERROR HTTPRequest#fixup: WEBrick::HTTPStatus::LengthRequired occured.
|
5
|
+
even though the Content-Length header is set correctly in the http
|
6
|
+
packet...
|
7
|
+
|
8
|
+
* I've not figured out how to set_up and teardown webbrick properly.
|
9
|
+
Since webbrick blocks after calling `start`, it needs to started in a
|
10
|
+
seperate thread. I didn't handle communication with it properly
|
11
|
+
though. Test::Unit calls set_up and teardown before
|
12
|
+
and after executing each test... method, and not as I expected, before
|
13
|
+
and after each test file. This leads to a new TestServer being
|
14
|
+
instantiated which complains "bind-adress already in use", because the
|
15
|
+
other instance wasn't properly shut down. I tried to dix this by setting
|
16
|
+
up the server in the constructor, but that has the same effect.
|
17
|
+
It seems like a new instance of TestCase is instantiated to run every
|
18
|
+
single test... method.
|
19
|
+
|
20
|
+
* There also seems to be something screwy about how rake calls the
|
21
|
+
tests. Some ruby files seem to be included twice. This leads to
|
22
|
+
"already initialized constant" error in the output of the unit tests.
|
23
|
+
|
24
|
+
* The two previous bugs aren't really problematic, because they only
|
25
|
+
make the output of the tests ugly. They should be easy to fix... (But
|
26
|
+
they're not high on my list of priorities.)
|
data/lib/simple_http.rb
ADDED
@@ -0,0 +1,361 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'uri'
|
4
|
+
require 'cgi'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
|
8
|
+
# Wrapper around ruby's standard net/http classes. Currently, only GET
|
9
|
+
# and POST https methods are supported. `SimpleHttp` provides class
|
10
|
+
# methods `get` and `post` to handle basic functionality. In case more
|
11
|
+
# complicated requests need to be made or default settings need to be
|
12
|
+
# overriden, it's possible to instantiate `SimpleHttp` and use instance
|
13
|
+
# methods `get` and `put`.
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# Features:
|
17
|
+
#
|
18
|
+
# * Handles Redirects automatically
|
19
|
+
# * Proxy used transparently if http_proxy environment variable is
|
20
|
+
# set.
|
21
|
+
# * SSL handled automatically
|
22
|
+
# * fault tolerant uri, e.g. all of these would work:
|
23
|
+
# "www.example.com", "www.example.com/", "http://www.example.com"
|
24
|
+
#
|
25
|
+
# Some usage examples:
|
26
|
+
# # plain GET (using class methods)
|
27
|
+
# SimpleHttp.get "www.example.com"
|
28
|
+
#
|
29
|
+
# # POST using the instance methods
|
30
|
+
# uri = URI.parse "https://www.example.com/index.html"
|
31
|
+
# sh = SimpleHttp uri
|
32
|
+
# sh.set_proxy "my.proxy", "8080"
|
33
|
+
# sh.post {"query" => "query_data"}
|
34
|
+
#
|
35
|
+
# # POST using class methods.
|
36
|
+
# binaryData = getImage
|
37
|
+
# SimpleData.post binaryData, "image/png"
|
38
|
+
#
|
39
|
+
# # GET requst with a custom request_header
|
40
|
+
# sh = SimpleHttp.new "http://www.example.com"
|
41
|
+
# sh.request_headers= {'X-Special-Http-Header'=>'my-value'}
|
42
|
+
# sh.get
|
43
|
+
class SimpleHttp
|
44
|
+
|
45
|
+
VERSION='0.1.0'
|
46
|
+
|
47
|
+
attr_accessor :proxy_host, :proxy_port, :proxy_user, :proxy_pwd, :uri, :request_headers, :response_handlers, :follow_num_redirects
|
48
|
+
|
49
|
+
RESPONSE_HANDLERS = {
|
50
|
+
Net::HTTPResponse => lambda { |request, response, http|
|
51
|
+
raise response.to_s
|
52
|
+
},
|
53
|
+
Net::HTTPSuccess => lambda { |request, response, http|
|
54
|
+
return response.body
|
55
|
+
},
|
56
|
+
Net::HTTPRedirection => lambda { |request, response, http|
|
57
|
+
raise "too many redirects!" unless http.follow_num_redirects > 0
|
58
|
+
|
59
|
+
# create a new SimpleHttp for the location
|
60
|
+
# refered to decreasing the remaining redirects
|
61
|
+
# by one.
|
62
|
+
sh = SimpleHttp.new response['location']
|
63
|
+
sh.follow_num_redirects = http.follow_num_redirects-1
|
64
|
+
|
65
|
+
# copy the response handlers used in the current
|
66
|
+
# request in case they were non standard.
|
67
|
+
sh.response_handlers = http.response_handlers
|
68
|
+
|
69
|
+
# http doesn't permit redirects for methods
|
70
|
+
# other than GET of HEAD, so we complain in case
|
71
|
+
# we get them in response to a POST request. (Or
|
72
|
+
# anything other than GET, for that matter.)
|
73
|
+
|
74
|
+
if request.class == Net::HTTP::Get
|
75
|
+
return sh.get
|
76
|
+
else
|
77
|
+
raise "Not a valid HTTP method for redirection: #{request.class}"
|
78
|
+
|
79
|
+
end
|
80
|
+
}
|
81
|
+
|
82
|
+
}
|
83
|
+
|
84
|
+
# SimpleHttp can either be used directly through the +get+ and
|
85
|
+
# +post+ class methods or be instantiated, in case you need to
|
86
|
+
# to add custom behaviour to the requests.
|
87
|
+
#
|
88
|
+
# @param may be a URI or a String.
|
89
|
+
#
|
90
|
+
# Example:
|
91
|
+
# http = SimpleHttp.new(URI.parse("http://www.example.com"))
|
92
|
+
# http = SimpleHttp.new "www.example.com"
|
93
|
+
# http = SimpleHttp.new "http://usr:pwd@www.example.com:1234"
|
94
|
+
def initialize uri
|
95
|
+
set_proxy ENV['http_proxy'] if ENV['http_proxy']
|
96
|
+
|
97
|
+
if uri.class == String
|
98
|
+
|
99
|
+
unless uri =~ /^https?:\/\//
|
100
|
+
uri = "http://#{uri}"
|
101
|
+
end
|
102
|
+
|
103
|
+
uri = URI.parse uri
|
104
|
+
|
105
|
+
end
|
106
|
+
@uri = uri
|
107
|
+
if !@uri.path || "" == @uri.path.strip
|
108
|
+
@uri.path="/"
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
@request_headers={}
|
113
|
+
@response_handlers=RESPONSE_HANDLERS.clone
|
114
|
+
@follow_num_redirects=3
|
115
|
+
|
116
|
+
if @uri.user
|
117
|
+
basic_authentication @uri.user, @uri.password
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
# Provides facilities to perform http basic authentication. You
|
124
|
+
# don't need to provide +usr+ and +pwd+ if they are already included
|
125
|
+
# in the uri, i.e. http://user:password@www.example.com/
|
126
|
+
#
|
127
|
+
|
128
|
+
def basic_authentication usr, pwd
|
129
|
+
str = Base64.encode64("#{usr}:#{pwd}")
|
130
|
+
str = "Basic #{str}"
|
131
|
+
@request_headers["Authorization"]=str
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# this method can be used to register response handlers for specific
|
136
|
+
# http responses in case you need to override the default behaviour.
|
137
|
+
# Defaults are:
|
138
|
+
#
|
139
|
+
# HTTPSuccess : return the body of the response
|
140
|
+
# HTTPRedirection : follow the redirection until success
|
141
|
+
# Others : raise an exception
|
142
|
+
#
|
143
|
+
# `clazz` is the subclass of HTTPResponse (or HTTPResponse in case you
|
144
|
+
# want to define "default" behaviour) that you are registering the
|
145
|
+
# handler for.
|
146
|
+
#
|
147
|
+
# `block` is the handler itself, if a response of the appropriate class
|
148
|
+
# is received, `block` is called with three parameters: the the
|
149
|
+
# Net::HTTPRequest, the actual HTTPResponse object that was received
|
150
|
+
# and a reference to the instance of `SimpleHttp` that is executing the
|
151
|
+
# call.
|
152
|
+
#
|
153
|
+
# example:
|
154
|
+
#
|
155
|
+
# # to override the default action of following a HTTP
|
156
|
+
# # redirect, you could register the folllowing handler:
|
157
|
+
#
|
158
|
+
# sh = SimpleHttp "www.example.com"
|
159
|
+
# sh.register_response_handler Net::HTTPRedirection {|request, response, shttp|
|
160
|
+
# response['location']
|
161
|
+
# }
|
162
|
+
#
|
163
|
+
|
164
|
+
def register_response_handler clazz, &block
|
165
|
+
c = clazz
|
166
|
+
while c != Object
|
167
|
+
# completely unnecessary sanity check to make sure parameter
|
168
|
+
# `clazz` is in fact a HTTPResponse ...
|
169
|
+
if c == Net::HTTPResponse
|
170
|
+
@response_handlers[clazz]=block
|
171
|
+
return
|
172
|
+
end
|
173
|
+
c = c.superclass
|
174
|
+
end
|
175
|
+
|
176
|
+
raise "Trying to register a response handler for non-response class: #{clazz}"
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# Set the proxy to use for the http request.
|
181
|
+
# Note that you don't need to set the proxy in case the
|
182
|
+
# `http_proxy` environment variable is set. To override
|
183
|
+
# previous proxy settings and connect directly, call
|
184
|
+
# `set_proxy nil`
|
185
|
+
#
|
186
|
+
# usage:
|
187
|
+
# http = SimpleHttp.new "www.example.com"
|
188
|
+
#
|
189
|
+
# http.set_proxy "http://proxy:8000"
|
190
|
+
# or:
|
191
|
+
# http.set_proxy(URI.parse("http://proxy:8000"))
|
192
|
+
# or:
|
193
|
+
# http.set_proxy 'proxy', '8000', 'my_user', 'secret'
|
194
|
+
# or:
|
195
|
+
# http.set_proxy nil # to override previous proxy
|
196
|
+
# settings and make the request directly.
|
197
|
+
#
|
198
|
+
|
199
|
+
|
200
|
+
def set_proxy proxy, port=nil, user=nil, pwd=nil
|
201
|
+
|
202
|
+
|
203
|
+
if !proxy
|
204
|
+
@proxy_host=@proxy_port=@proxy_user=@proxy_pwd=nil
|
205
|
+
return
|
206
|
+
end
|
207
|
+
|
208
|
+
if proxy.class == String
|
209
|
+
if !port && !user && !pwd
|
210
|
+
proxy = URI.parse(proxy)
|
211
|
+
else
|
212
|
+
@proxy_host= host
|
213
|
+
@proxy_port= port
|
214
|
+
@proxy_user= user
|
215
|
+
@proxy_pwd = pwd
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
if proxy.class == URI::HTTP
|
220
|
+
@proxy_host= proxy.host
|
221
|
+
@proxy_port= proxy.port
|
222
|
+
@proxy_user= proxy.user
|
223
|
+
@proxy_pwd = proxy.password
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# interal
|
228
|
+
# Takes a HTTPResponse (or subclass) and determines how to
|
229
|
+
# handle the response. Default behaviour is:
|
230
|
+
#
|
231
|
+
# HTTPSuccess : return the body of the response
|
232
|
+
# HTTPRedirection : follow the redirect until success.
|
233
|
+
# default : raise the HTTPResponse.
|
234
|
+
#
|
235
|
+
# the default behaviour can be overidden by registering a
|
236
|
+
# response handler using the `register_response_handler` method.
|
237
|
+
#
|
238
|
+
|
239
|
+
def handle_response http_request, http_response
|
240
|
+
raise "Not a Net::HTTPResponse" unless http_response.is_a? Net::HTTPResponse
|
241
|
+
|
242
|
+
c = http_response.class
|
243
|
+
while c!=Object
|
244
|
+
# the response_handlers hash contains a handler
|
245
|
+
# for the specific response class.
|
246
|
+
if @response_handlers[c]
|
247
|
+
return @response_handlers[c].call(http_request, http_response, self)
|
248
|
+
end
|
249
|
+
|
250
|
+
c=c.superclass
|
251
|
+
end
|
252
|
+
|
253
|
+
# if we reached this place, no handler was registered
|
254
|
+
# for this response. default is to return the response.
|
255
|
+
|
256
|
+
return http_response
|
257
|
+
end
|
258
|
+
|
259
|
+
# internal
|
260
|
+
def do_http request
|
261
|
+
response = nil
|
262
|
+
|
263
|
+
http = Net::HTTP.new(@uri.host, @uri.port, @proxy_host,
|
264
|
+
@proxy_port, @proxy_user, @proxy_pwd)
|
265
|
+
http.use_ssl = @uri.scheme == 'https'
|
266
|
+
|
267
|
+
# add custom request headers.
|
268
|
+
|
269
|
+
@request_headers.each {|key,value|
|
270
|
+
request[key]=value;
|
271
|
+
}
|
272
|
+
|
273
|
+
handle_response(request, http.request(request));
|
274
|
+
end
|
275
|
+
|
276
|
+
# internal
|
277
|
+
def make_query query
|
278
|
+
return query unless query && query.class == Hash
|
279
|
+
str = ""
|
280
|
+
query.collect { |key, value|
|
281
|
+
str += CGI::escape(key) + "=" + CGI::escape(value)
|
282
|
+
}
|
283
|
+
str
|
284
|
+
end
|
285
|
+
|
286
|
+
# Make a simple GET request to the provided URI.
|
287
|
+
#
|
288
|
+
# Example:
|
289
|
+
# puts(SimpleHttp.get("www.example.com"))
|
290
|
+
def self.get uri, query=nil
|
291
|
+
http = SimpleHttp.new uri
|
292
|
+
http.get query
|
293
|
+
end
|
294
|
+
|
295
|
+
# Make a POST request to the provided URI.
|
296
|
+
#
|
297
|
+
# Example:
|
298
|
+
# puts(SimpleHttp.post("www.example.com", "query"=>"my_query"))
|
299
|
+
#
|
300
|
+
# Alternatively, you can post any sort of data, but will have to
|
301
|
+
# set the appriate content_type:
|
302
|
+
#
|
303
|
+
# SimpleHttp.post("http://www.example.com/", binary_data, "img/png")
|
304
|
+
|
305
|
+
def self.post uri, query=nil, content_type='application/x-www-form-urlencoded'
|
306
|
+
http = SimpleHttp.new uri
|
307
|
+
http.post query, content_type
|
308
|
+
end
|
309
|
+
|
310
|
+
# Call the +get+ method as an instance method if you need to
|
311
|
+
# modify the default behaviour of the library, or set special
|
312
|
+
# headers:
|
313
|
+
#
|
314
|
+
# http = SimpleHttp.new "www.example.com"
|
315
|
+
# http.request_headers["X-Special"]="whatever"
|
316
|
+
# str = http.get
|
317
|
+
def get query = nil
|
318
|
+
if (query = make_query query)
|
319
|
+
@uri.query = @uri.query ? @uri.query+"&"+query : query
|
320
|
+
end
|
321
|
+
full_path = @uri.path + (@uri.query ? "?#{@uri.query}" : "")
|
322
|
+
|
323
|
+
req = Net::HTTP::Get.new(full_path)
|
324
|
+
# puts Net::HTTP::Proxy(@proxy_host, @proxy_port, @proxy_user, @proxy_pwd).get(@uri)
|
325
|
+
do_http req
|
326
|
+
end
|
327
|
+
|
328
|
+
#
|
329
|
+
# Post the query data to the url.
|
330
|
+
# The body of the request remains empty if query=nil.
|
331
|
+
# In case `query` is a `Hash`, it's assumed that we are
|
332
|
+
# sending a form.
|
333
|
+
# In case `query` is a `String`, it's also assumed that a
|
334
|
+
# form is being sent, UNLESS the `content_type` parameter
|
335
|
+
# is set.
|
336
|
+
#
|
337
|
+
def post query=nil, content_type='application/x-www-form-urlencoded'
|
338
|
+
req = Net::HTTP::Post.new(@uri.path)
|
339
|
+
|
340
|
+
req.body= make_query query if query
|
341
|
+
req.content_type=content_type if query
|
342
|
+
req.content_length=query ? req.body.length : 0
|
343
|
+
|
344
|
+
do_http req
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
#ht = SimpleHttp.new "http://www.google.com/aldfksjaldskjfalskjfdlk"
|
350
|
+
##ht.register_response_handler(Net::HTTPRedirection) {|req, res, ht| puts res['location']}
|
351
|
+
#puts ht.get.class
|
352
|
+
##puts(ht.get("q"=>"bla"))
|
353
|
+
#
|
354
|
+
##puts (SimpleHttp.get "http://www.google.com")
|
355
|
+
#
|
356
|
+
#['http://www.google.com/', 'www.google.com', 'https://www.google.com'].each {|u|
|
357
|
+
# SimpleHttp.new u
|
358
|
+
#}
|
359
|
+
##puts ht.post
|
360
|
+
|
361
|
+
|
data/test/http_test.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'simple_http.rb'
|
2
|
+
require 'http_test_server.rb'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'uri'
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
# These tests communicate with a corresponding http server (TestServer), which is
|
9
|
+
# implemented in `http_test_server.rb`
|
10
|
+
|
11
|
+
class SimpleHttpTest < Test::Unit::TestCase
|
12
|
+
def initialize *args
|
13
|
+
super *args
|
14
|
+
# create webbrick server in a separate thread
|
15
|
+
Thread.new {
|
16
|
+
TestServer.new.start
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
#@t.shutdown # webrick blocks in a weird way, can't
|
22
|
+
#commnicate with it in a different thread. this, of
|
23
|
+
#course, is really ugly.
|
24
|
+
end
|
25
|
+
|
26
|
+
# Tests of SimpleHttp class method behaviour.
|
27
|
+
|
28
|
+
def test_get_class_method
|
29
|
+
# string url
|
30
|
+
ret = SimpleHttp.get "http://127.0.0.1:12345/test1"
|
31
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "basic GET 1 test failed.");
|
32
|
+
|
33
|
+
# string url, with query
|
34
|
+
ret = SimpleHttp.get "http://127.0.0.1:12345/test1?query=true"
|
35
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "basic GET 2 test failed.");
|
36
|
+
|
37
|
+
# uri
|
38
|
+
uri = URI.parse "http://127.0.0.1:12345/test1?query=true"
|
39
|
+
ret = SimpleHttp.get uri
|
40
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "basic GET 3 test failed.");
|
41
|
+
|
42
|
+
#string with query as hash
|
43
|
+
ret = SimpleHttp.get "http://127.0.0.1:12345/test2", "query" => "query_test"
|
44
|
+
assert_equal("query_test", ret, "basic GET (query) 4 test failed.");
|
45
|
+
|
46
|
+
#uri with existing query + query as hash.
|
47
|
+
uri = URI.parse "http://127.0.0.1:12345/test2?query2=true"
|
48
|
+
ret = SimpleHttp.get uri, "query" => "query_test"
|
49
|
+
assert_equal("query_test", ret, "basic GET (query) 4.1 test failed.");
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
# Tests for http GET calls implemented using instantiated SimpleHttp objects.
|
54
|
+
|
55
|
+
def test_get_class_instance_method
|
56
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/test1"
|
57
|
+
ret = http.get
|
58
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "instance GET 1 test failed.");
|
59
|
+
|
60
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/test2?query=query_test"
|
61
|
+
ret = http.get
|
62
|
+
assert_equal("query_test", ret, "instance GET 2 test (query)");
|
63
|
+
|
64
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/query_test2?query=query_test"
|
65
|
+
ret = http.get "query2"=>"query2_test"
|
66
|
+
assert_equal("query2_test", ret, "instance GET 2.1 test (add to existing query")
|
67
|
+
|
68
|
+
http = SimpleHttp.new(URI.parse("http://127.0.0.1:12345/query_test2?bla=true"))
|
69
|
+
ret = http.get "query2" => "query_test"
|
70
|
+
assert_equal("query_test", ret, "basic GET (query) 3 test failed.")
|
71
|
+
|
72
|
+
# GET requst with a custom request_header
|
73
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/header_test"
|
74
|
+
http.request_headers= {'x-special-http-header'=>'my-value'}
|
75
|
+
ret = http.get
|
76
|
+
assert_equal("my-value", ret, "GET header test 4")
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
# http POST calls using class methods.
|
82
|
+
#
|
83
|
+
def test_post_class_method
|
84
|
+
|
85
|
+
# string url
|
86
|
+
ret = SimpleHttp.post "http://127.0.0.1:12345/test1"
|
87
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "basic POST 1 test failed.");
|
88
|
+
|
89
|
+
|
90
|
+
#string with query as hash
|
91
|
+
ret = SimpleHttp.post "http://127.0.0.1:12345/test2", "query" => "query_test"
|
92
|
+
assert_equal("query_test", ret, "basic POST (query) 2 test failed.");
|
93
|
+
|
94
|
+
#uri with existing query + query as hash.
|
95
|
+
uri = URI.parse "http://127.0.0.1:12345/test2"
|
96
|
+
ret = SimpleHttp.post uri, "query" => "query_test"
|
97
|
+
assert_equal("query_test", ret, "basic POST (query) 2.1 test failed.");
|
98
|
+
|
99
|
+
# post something other than a form.
|
100
|
+
ret = SimpleHttp.post "http://127.0.0.1:12345/post_data_test", TestServer::POST_DATA, "misc/test-data"
|
101
|
+
assert_equal(TestServer::POST_DATA, ret, "class Post data test")
|
102
|
+
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def test_post_instance_method
|
108
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/test1"
|
109
|
+
ret = http.post
|
110
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "instance POST 1 test failed.");
|
111
|
+
|
112
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/test2"
|
113
|
+
ret = http.post "query" => "query_test"
|
114
|
+
assert_equal("query_test", ret, "instance POST 2 test (query)");
|
115
|
+
|
116
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/query_test2?query=query_test"
|
117
|
+
ret = http.post "query2"=>"query2_test"
|
118
|
+
assert_equal("query2_test", ret, "instance POST 2.1 test (add to existing query")
|
119
|
+
|
120
|
+
http = SimpleHttp.new(URI.parse("http://127.0.0.1:12345/query_test2?bla=true"))
|
121
|
+
ret = http.post "query2" => "query_test"
|
122
|
+
assert_equal("query_test", ret, "basic POST (query) 3 test failed.")
|
123
|
+
|
124
|
+
# POST requst with a custom request_header
|
125
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/header_test"
|
126
|
+
http.request_headers= {'x-special-http-header'=>'my-value'}
|
127
|
+
ret = http.post
|
128
|
+
assert_equal("my-value", ret, "POST header test 4")
|
129
|
+
|
130
|
+
# POST request with a custom data type (not posting a form.)
|
131
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/post_data_test"
|
132
|
+
ret = http.post TestServer::POST_DATA, "misc/test-data"
|
133
|
+
assert_equal(TestServer::POST_DATA, ret, "Post data test")
|
134
|
+
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_basic_auth
|
139
|
+
|
140
|
+
# string url
|
141
|
+
ret = SimpleHttp.get "http://test:pwd@127.0.0.1:12345/basic_auth"
|
142
|
+
assert_equal(TestServer::SUCCESS_TEXT_1, ret, "basic auth get class 1 test failed.");
|
143
|
+
|
144
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/basic_auth"
|
145
|
+
http.basic_authentication "test", "pwd"
|
146
|
+
ret = http.get
|
147
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_1, "basic auth get instance 2 test failed.");
|
148
|
+
#string with query as hash
|
149
|
+
ret = SimpleHttp.post "http://test:pwd@127.0.0.1:12345/basic_auth", "query" => "query_test"
|
150
|
+
assert_equal(TestServer::SUCCESS_TEXT_1, ret, "basic auth post class 3 test failed.");
|
151
|
+
|
152
|
+
http = SimpleHttp.new "http://127.0.0.1:12345/basic_auth"
|
153
|
+
http.basic_authentication "test", "pwd"
|
154
|
+
ret = http.post TestServer::POST_DATA, "misc/test-data"
|
155
|
+
assert_equal(TestServer::SUCCESS_TEXT_1, ret, "Post data test")
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_response_handler
|
159
|
+
assert_raise(RuntimeError) {
|
160
|
+
ret = SimpleHttp.get "http://test:pwd@127.0.0.1:12345/non_existant"
|
161
|
+
}
|
162
|
+
|
163
|
+
http = SimpleHttp.new "http://test:pwd@127.0.0.1:12345/non_existant"
|
164
|
+
http.register_response_handler(Net::HTTPNotFound) { |req, res, http|
|
165
|
+
res.code
|
166
|
+
}
|
167
|
+
ret = http.get
|
168
|
+
assert_equal("404", ret, "response handler test 2")
|
169
|
+
|
170
|
+
http = SimpleHttp.new "http://test:pwd@127.0.0.1:12345/redirect1"
|
171
|
+
http.register_response_handler(Net::HTTPRedirection) { |req, res, http|
|
172
|
+
res['location']
|
173
|
+
}
|
174
|
+
ret = http.get
|
175
|
+
assert_equal("http://127.0.0.1:12345/redirect2", ret, "response handler test 3")
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_redirect
|
180
|
+
assert_raise(RuntimeError) {
|
181
|
+
http = SimpleHttp.new "http://test:pwd@127.0.0.1:12345/redirect1"
|
182
|
+
ret = http.get
|
183
|
+
}
|
184
|
+
|
185
|
+
ret = SimpleHttp.get "http://test:pwd@127.0.0.1:12345/redirect"
|
186
|
+
assert_equal(ret, TestServer::SUCCESS_TEXT_0, "redirect test 2");
|
187
|
+
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
end
|
193
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
|
3
|
+
include WEBrick
|
4
|
+
class TestServer
|
5
|
+
SUCCESS_TEXT_0 = "success_0"
|
6
|
+
SUCCESS_TEXT_1 = "success_1"
|
7
|
+
SUCCESS_TEXT_2 = "success_2"
|
8
|
+
SUCCESS_TEXT_3 = "success_3"
|
9
|
+
SUCCESS_TEXT_4 = "success_4"
|
10
|
+
SUCCESS_TEXT_5 = "success_5"
|
11
|
+
SUCCESS_TEXT_6 = "success_6"
|
12
|
+
SUCCESS_TEXT_7 = "success_7"
|
13
|
+
SUCCESS_TEXT_8 = "success_8"
|
14
|
+
SUCCESS_TEXT_9 = "success_9"
|
15
|
+
|
16
|
+
POST_DATA = [0xbe, 0x00, 0x12, 0x23, 0x45, 0x67, 0x89, 0xAB].join
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@server = HTTPServer.new(
|
20
|
+
:Port => 12345
|
21
|
+
)
|
22
|
+
|
23
|
+
add_tests
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
@server.start
|
28
|
+
end
|
29
|
+
|
30
|
+
def shutdown
|
31
|
+
@server.shutdown
|
32
|
+
end
|
33
|
+
|
34
|
+
def dbg str
|
35
|
+
puts "!!!!!!!!! #{str}"
|
36
|
+
end
|
37
|
+
def add_tests
|
38
|
+
# return a text
|
39
|
+
@server.mount_proc("/test1"){|req, res|
|
40
|
+
res.body=SUCCESS_TEXT_0
|
41
|
+
}
|
42
|
+
#return value of query param named "query"
|
43
|
+
@server.mount_proc("/test2"){|req, res|
|
44
|
+
res.body=req.query["query"]
|
45
|
+
}
|
46
|
+
|
47
|
+
# return value of query param named "query2"
|
48
|
+
@server.mount_proc("/query_test2"){|req, res|
|
49
|
+
res.body=req.query["query2"]
|
50
|
+
}
|
51
|
+
|
52
|
+
# return value of request header named "X-Special-Http-Header"
|
53
|
+
@server.mount_proc("/header_test"){|req, res|
|
54
|
+
res.body=req.header["x-special-http-header"][0]
|
55
|
+
}
|
56
|
+
|
57
|
+
# return value of request header named "X-Special-Http-Header"
|
58
|
+
@server.mount_proc("/post_data_test"){|req, res|
|
59
|
+
ctype = req.header['content-type'][0]
|
60
|
+
if "misc/test-data" == ctype
|
61
|
+
res.body=req.body
|
62
|
+
else
|
63
|
+
res.body="failed, content-type: #{ctype}"
|
64
|
+
end
|
65
|
+
}
|
66
|
+
|
67
|
+
@server.mount_proc("/basic_auth") {|req, res|
|
68
|
+
|
69
|
+
auth = Base64.decode64(req.header['authorization'][0].split[1])
|
70
|
+
usr, pwd = auth.split(':')
|
71
|
+
if ('test'==usr && 'pwd'==pwd)
|
72
|
+
res.body=SUCCESS_TEXT_1
|
73
|
+
else
|
74
|
+
res.status=403
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
1.upto(6) {|i|
|
79
|
+
@server.mount_proc("/redirect#{i}") { |req, res|
|
80
|
+
res.status=301
|
81
|
+
res.header['location']="http://127.0.0.1:12345/redirect#{i+1}"
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
@server.mount_proc("/redirect") { |req, res|
|
86
|
+
res.status=301
|
87
|
+
res.header['location']="http://127.0.0.1:12345/test1"
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: simplehttp
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-02-08 00:00:00 +01:00
|
8
|
+
summary: "simple_http: Simple Http client lib."
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: Wrapper around net/http to provide quick and dirty http access.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- lib/simple_http.rb
|
33
|
+
- AUTHORS
|
34
|
+
- CHANGELOG
|
35
|
+
- LICENSE
|
36
|
+
- Rakefile
|
37
|
+
- README
|
38
|
+
- TODO
|
39
|
+
- test/http_test.rb
|
40
|
+
- test/http_test_server.rb
|
41
|
+
test_files: []
|
42
|
+
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
requirements:
|
52
|
+
- none
|
53
|
+
dependencies: []
|
54
|
+
|