simplehttp 0.1.0
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.
- 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
|
+
|