em-net-http-npn47 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +54 -0
- data/Rakefile +17 -0
- data/VERSION +1 -0
- data/em-net-http.gemspec +66 -0
- data/lib/em-net-http/weary.rb +24 -0
- data/lib/em-net-http.rb +200 -0
- data/lib/test.rb +12 -0
- data/lib/test_weary.rb +22 -0
- data/spec/em-net-http_spec.rb +141 -0
- data/spec/image.jpg +0 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +39 -0
- metadata +175 -0
data/.document
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 James Fairbairn
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/jfairbairn/em-net-http.png)](http://travis-ci.org/jfairbairn/em-net-http])
|
2
|
+
|
3
|
+
Most Ruby web API libraries use <tt>Net::HTTP</tt> (because it's ubiquitous),
|
4
|
+
but I want to use them in my non-blocking EventMachine-based applications, and
|
5
|
+
I don't want Net::HTTP to block. I therefore wrote this.
|
6
|
+
|
7
|
+
Using the magic of Ruby 1.9's Fibers, we monkeypatch <tt>Net::HTTP</tt> to use
|
8
|
+
the faster, nonblocking <tt>[em-http-request][1]</tt> under the hood. Obviously this
|
9
|
+
will only work from inside the [EventMachine][2] event loop, and from within a spawned
|
10
|
+
fiber:
|
11
|
+
|
12
|
+
require 'em-net-http'
|
13
|
+
|
14
|
+
EM.run do
|
15
|
+
Fiber.new do
|
16
|
+
Net::HTTP.start('encrypted.google.com', :use_ssl=>true) do |http|
|
17
|
+
res = http.get('/search?q=james')
|
18
|
+
puts res.body
|
19
|
+
end
|
20
|
+
EM.stop_event_loop
|
21
|
+
end.resume
|
22
|
+
end
|
23
|
+
|
24
|
+
The above will run without blocking your carefully-tuned nonblocking webapp.
|
25
|
+
|
26
|
+
There are a few tests (taking advantage of the very useful [Mimic][6] gem)
|
27
|
+
that assert that responses are identical to those created by <tt>Net::HTTP</tt>.
|
28
|
+
These are by no means exhaustive; if you're using <tt>Net::HTTP</tt> in some other way
|
29
|
+
and the <tt>em-net-http</tt>'s behaviour is not what you expect, do send me a failing test
|
30
|
+
case.
|
31
|
+
|
32
|
+
Currently tested with Ruby (MRI) 1.9.1 and 1.9.2.
|
33
|
+
|
34
|
+
### Caveat
|
35
|
+
|
36
|
+
The <tt>Net::HTTP</tt> API is a many-headed hydra -- I haven't patched much of it.
|
37
|
+
Your mileage may therefore vary. Please feed me patches, pull requests and bug reports!
|
38
|
+
|
39
|
+
### Thanks
|
40
|
+
|
41
|
+
* [Luke Redpath][7], for [Mimic][6].
|
42
|
+
* [Mathieu Ravaux][8], for adding streaming and buffering support.
|
43
|
+
* [Jon Swope][9] and [Ary Borenszweig][10], for bug fixes.
|
44
|
+
|
45
|
+
[1]: http://github.com/igrigorik/em-http-request
|
46
|
+
[2]: http://rubyeventmachine.com/
|
47
|
+
[3]: http://rightaws.rubyforge.org/
|
48
|
+
[4]: http://github.com/mwunsch/weary
|
49
|
+
[5]: http://github.com/mwunsch/tumblr
|
50
|
+
[6]: http://github.com/lukeredpath/mimic
|
51
|
+
[7]: http://lukeredpath.co.uk/
|
52
|
+
[8]: http://mathieuravaux.com/
|
53
|
+
[9]: http://www.jonswope.com/
|
54
|
+
[10]: http://weblogs.manas.com.ar/ary
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
require 'rake/rdoctask'
|
10
|
+
Rake::RDocTask.new do |rdoc|
|
11
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
12
|
+
|
13
|
+
rdoc.rdoc_dir = 'rdoc'
|
14
|
+
rdoc.title = "em-net-http #{version}"
|
15
|
+
rdoc.rdoc_files.include('README*')
|
16
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
17
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.4
|
data/em-net-http.gemspec
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{em-net-http-npn47}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["James Fairbairn","Neeraj PN"]
|
9
|
+
s.date = %q{2012-11-05}
|
10
|
+
s.description = %q{Monkeypatching Net::HTTP to use em-http-request under the hood.}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"LICENSE",
|
13
|
+
"README.md"
|
14
|
+
]
|
15
|
+
s.files = [
|
16
|
+
".document",
|
17
|
+
"Gemfile",
|
18
|
+
"LICENSE",
|
19
|
+
"README.md",
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION",
|
22
|
+
"em-net-http.gemspec",
|
23
|
+
"lib/em-net-http.rb",
|
24
|
+
"lib/em-net-http/weary.rb",
|
25
|
+
"lib/test.rb",
|
26
|
+
"lib/test_weary.rb",
|
27
|
+
"spec/em-net-http_spec.rb",
|
28
|
+
"spec/image.jpg",
|
29
|
+
"spec/spec.opts",
|
30
|
+
"spec/spec_helper.rb"
|
31
|
+
]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.8.10}
|
34
|
+
s.summary = %q{Non-blocking replacement for Net::HTTP, for use in EventMachine}
|
35
|
+
|
36
|
+
if s.respond_to? :specification_version then
|
37
|
+
s.specification_version = 3
|
38
|
+
|
39
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
40
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
41
|
+
s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
|
42
|
+
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
43
|
+
s.add_runtime_dependency(%q<em-http-request>, [">= 0.2.10"])
|
44
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.5"])
|
45
|
+
s.add_development_dependency(%q<mimic>, [">= 0.3.0"])
|
46
|
+
s.add_development_dependency(%q<weary>, [">= 0"])
|
47
|
+
else
|
48
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
49
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
50
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
51
|
+
s.add_dependency(%q<em-http-request>, [">= 0.2.10"])
|
52
|
+
s.add_dependency(%q<rspec>, ["~> 2.5"])
|
53
|
+
s.add_dependency(%q<mimic>, [">= 0.3.0"])
|
54
|
+
s.add_dependency(%q<weary>, [">= 0"])
|
55
|
+
end
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
58
|
+
s.add_dependency(%q<eventmachine>, [">= 0.12.10"])
|
59
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
60
|
+
s.add_dependency(%q<em-http-request>, [">= 0.2.10"])
|
61
|
+
s.add_dependency(%q<rspec>, ["~> 2.5"])
|
62
|
+
s.add_dependency(%q<mimic>, [">= 0.3.0"])
|
63
|
+
s.add_dependency(%q<weary>, [">= 0"])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Weary
|
2
|
+
class Response
|
3
|
+
# Weary doesn't like Content-Type headers with extra bits on the end, like '; encoding=utf-8'.
|
4
|
+
def content_type ; @content_type.split(';').first ; end
|
5
|
+
|
6
|
+
def value ; self ; end
|
7
|
+
end
|
8
|
+
|
9
|
+
# Weary runs multi-threaded by default. The thread is spawned in perform!(). Let's not do that.
|
10
|
+
class Request
|
11
|
+
def perform!(&block)
|
12
|
+
@on_complete = block if block_given?
|
13
|
+
before_send.call(self) if before_send
|
14
|
+
req = http.request(request)
|
15
|
+
response = Response.new(req, self)
|
16
|
+
if response.redirected? && follows?
|
17
|
+
response.follow_redirect
|
18
|
+
else
|
19
|
+
on_complete.call(response) if on_complete
|
20
|
+
response
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/em-net-http.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'addressable/uri'
|
3
|
+
require 'em-http-request'
|
4
|
+
require 'net/http'
|
5
|
+
require 'fiber'
|
6
|
+
|
7
|
+
module EventMachine
|
8
|
+
module NetHTTP
|
9
|
+
class Response
|
10
|
+
attr_reader :code, :body, :header, :message, :http_version
|
11
|
+
alias_method :msg, :message
|
12
|
+
|
13
|
+
def initialize(response_header)
|
14
|
+
@code = response_header.http_status.to_s
|
15
|
+
@message = response_header.http_reason
|
16
|
+
@http_version = response_header.http_version
|
17
|
+
@header = response_header
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_body body
|
21
|
+
@already_buffered = true
|
22
|
+
@body = body
|
23
|
+
end
|
24
|
+
|
25
|
+
def content_type
|
26
|
+
self['content-type']
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](k)
|
30
|
+
@header[key(k)]
|
31
|
+
end
|
32
|
+
|
33
|
+
def key?(k)
|
34
|
+
@header.key? key(k)
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_body(dest=nil,&block)
|
38
|
+
@body
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_hash
|
42
|
+
h={}
|
43
|
+
@header.each do |k, v|
|
44
|
+
h[fromkey(k)] = v
|
45
|
+
end
|
46
|
+
h
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def key(k)
|
51
|
+
k.upcase.tr('-','_')
|
52
|
+
end
|
53
|
+
|
54
|
+
def fromkey(k)
|
55
|
+
k.tr('_', '-').split('-').map{|i|i.capitalize}.join('-')
|
56
|
+
end
|
57
|
+
|
58
|
+
include Enumerable
|
59
|
+
def each(&blk)
|
60
|
+
@header.each(&blk)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
module Net
|
69
|
+
class HTTPResponse
|
70
|
+
class << self
|
71
|
+
public :response_class
|
72
|
+
end
|
73
|
+
|
74
|
+
alias_method :orig_net_http_read_body, :read_body
|
75
|
+
|
76
|
+
def read_body(dest=nil, &block)
|
77
|
+
return @body if @already_buffered
|
78
|
+
return orig_net_http_read_body(dest, &block) unless ::EM.reactor_running?
|
79
|
+
if block_given?
|
80
|
+
f = Fiber.current
|
81
|
+
@httpreq.callback { |res| f.resume }
|
82
|
+
@httpreq.stream &block
|
83
|
+
Fiber.yield
|
84
|
+
else
|
85
|
+
unless @body || @already_buffered
|
86
|
+
if self.class.body_permitted?
|
87
|
+
f = Fiber.current
|
88
|
+
io = StringIO.new '', 'wb'
|
89
|
+
io.set_encoding 'ASCII-8BIT'
|
90
|
+
@httpreq.callback { |res| f.resume io.string }
|
91
|
+
@httpreq.errback { |err| f.resume err }
|
92
|
+
@httpreq.stream { |chunk| io.write chunk }
|
93
|
+
@body = Fiber.yield
|
94
|
+
end
|
95
|
+
@already_buffered = true
|
96
|
+
end
|
97
|
+
@body
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class HTTP
|
103
|
+
alias_method :orig_net_http_request, :request
|
104
|
+
|
105
|
+
alias_method :orig_net_http_do_start, :do_start
|
106
|
+
|
107
|
+
def do_start
|
108
|
+
|
109
|
+
return orig_net_http_do_start unless ::EM.reactor_running?
|
110
|
+
|
111
|
+
@started = true
|
112
|
+
end
|
113
|
+
|
114
|
+
def request(req, body = nil, &block)
|
115
|
+
|
116
|
+
return orig_net_http_request(req, body, &block) unless ::EM.reactor_running?
|
117
|
+
|
118
|
+
uri = Addressable::URI.parse("#{use_ssl? ? 'https://' : 'http://'}#{addr_port}#{req.path}")
|
119
|
+
|
120
|
+
body = body || req.body
|
121
|
+
opts = body.nil? ? {} : {:body => body}
|
122
|
+
if use_ssl?
|
123
|
+
sslopts = opts[:ssl] = {}
|
124
|
+
sslopts[:verify_peer] = verify_mode == OpenSSL::SSL::VERIFY_PEER
|
125
|
+
sslopts[:private_key_file] = key if key
|
126
|
+
sslopts[:cert_chain_file] = ca_file if ca_file
|
127
|
+
end
|
128
|
+
opts[:timeout] = self.read_timeout
|
129
|
+
|
130
|
+
headers = opts[:head] = {}
|
131
|
+
req.each do |k, v|
|
132
|
+
headers[k] = v
|
133
|
+
end
|
134
|
+
|
135
|
+
headers['content-type'] ||= "application/x-www-form-urlencoded"
|
136
|
+
|
137
|
+
t0 = Time.now
|
138
|
+
httpreq = EM::HttpRequest.new(uri).send(req.class::METHOD.downcase.to_sym, opts)
|
139
|
+
|
140
|
+
f=Fiber.current
|
141
|
+
|
142
|
+
convert_em_http_response = lambda do |res|
|
143
|
+
emres = EM::NetHTTP::Response.new(res.response_header)
|
144
|
+
emres.set_body res.response
|
145
|
+
nhresclass = Net::HTTPResponse.response_class(emres.code)
|
146
|
+
nhres = nhresclass.new(emres.http_version, emres.code, emres.message)
|
147
|
+
emres.to_hash.each do |k, v|
|
148
|
+
nhres.add_field(k, v)
|
149
|
+
end
|
150
|
+
nhres.body = emres.body if req.response_body_permitted? && nhresclass.body_permitted?
|
151
|
+
nhres.instance_variable_set '@read', true
|
152
|
+
f.resume nhres
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
if block_given?
|
157
|
+
httpreq.headers { |headers|
|
158
|
+
|
159
|
+
emres = EM::NetHTTP::Response.new(headers)
|
160
|
+
nhresclass = Net::HTTPResponse.response_class(emres.code)
|
161
|
+
nhres = nhresclass.new(emres.http_version, emres.code, emres.message)
|
162
|
+
emres.to_hash.each do |k, v|
|
163
|
+
nhres.add_field(k, v)
|
164
|
+
end
|
165
|
+
f.resume nhres
|
166
|
+
}
|
167
|
+
httpreq.errback {|err|f.resume(:error)}
|
168
|
+
|
169
|
+
nhres = yield_with_error_check(t0)
|
170
|
+
nhres.instance_variable_set :@httpreq, httpreq
|
171
|
+
|
172
|
+
yield nhres
|
173
|
+
nhres
|
174
|
+
else
|
175
|
+
httpreq.callback &convert_em_http_response
|
176
|
+
httpreq.errback {|err|f.resume(:error)}
|
177
|
+
|
178
|
+
yield_with_error_check(t0)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def yield_with_error_check(t0)
|
185
|
+
res = Fiber.yield
|
186
|
+
|
187
|
+
if res == :error
|
188
|
+
raise 'EM::HttpRequest error - request timed out' if Time.now - self.read_timeout > t0
|
189
|
+
raise 'EM::HttpRequest error - unknown error'
|
190
|
+
end
|
191
|
+
|
192
|
+
res
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Other bits and bobs.
|
199
|
+
|
200
|
+
|
data/lib/test.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$: << '.'
|
2
|
+
require File.dirname(__FILE__) + '/em-net-http'
|
3
|
+
|
4
|
+
EM.run do
|
5
|
+
Fiber.new do
|
6
|
+
Net::HTTP.start('encrypted.google.com', :use_ssl=>true, :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
|
7
|
+
res = http.get('/search?q=james')
|
8
|
+
puts res.body
|
9
|
+
end
|
10
|
+
EM.stop_event_loop
|
11
|
+
end.resume
|
12
|
+
end
|
data/lib/test_weary.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
require 'em-net-http'
|
3
|
+
require 'weary'
|
4
|
+
require 'em-net-http/weary'
|
5
|
+
|
6
|
+
EM.run do
|
7
|
+
Fiber.new do
|
8
|
+
class TwitterUser < Weary::Base
|
9
|
+
domain "http://twitter.com/users/"
|
10
|
+
|
11
|
+
get "show" do |resource|
|
12
|
+
resource.with = [:id, :user_id, :screen_name]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
user = TwitterUser.new
|
17
|
+
me = user.show(:id => "jfairbairn").perform
|
18
|
+
puts me['status']['text']
|
19
|
+
|
20
|
+
EM.stop_event_loop
|
21
|
+
end.resume
|
22
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "em-net-http" do
|
4
|
+
|
5
|
+
it 'should support streaming the response' do
|
6
|
+
assert_identical(:streamed => true) {
|
7
|
+
body = StringIO.new '', 'wb'
|
8
|
+
|
9
|
+
Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
|
10
|
+
http.request_get "/image" do |resp|
|
11
|
+
resp.should be_a_kind_of(Net::HTTPOK)
|
12
|
+
resp.read_body { |chunk| body.write chunk }
|
13
|
+
resp
|
14
|
+
end
|
15
|
+
end.tap do |resp|
|
16
|
+
resp.instance_variable_set :@streamed_body, body.string
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should support buffering the response' do
|
22
|
+
assert_identical {
|
23
|
+
Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
|
24
|
+
respone = http.request_get "/image" do |resp|
|
25
|
+
resp.should be_a_kind_of(Net::HTTPOK)
|
26
|
+
resp.read_body # force reading the body before the test tears down the EM loop
|
27
|
+
resp
|
28
|
+
end
|
29
|
+
respone.tap { respone.should be_a_kind_of(Net::HTTPOK) }
|
30
|
+
end
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'should be compatible' do
|
35
|
+
it 'for Net::HTTP.get()' do
|
36
|
+
run_requests {Net::HTTP.get(URI.parse("http://localhost:#{Mimic::MIMIC_DEFAULT_PORT}/hello"))}
|
37
|
+
@expected_res.should == @actual_res
|
38
|
+
end
|
39
|
+
|
40
|
+
# it 'for Net::HTTP.get_print()' do
|
41
|
+
# run_requests {Net::HTTP.get_print(URI.parse('http://localhost/hello'))}
|
42
|
+
# @expected_res.should == @actual_res
|
43
|
+
# end
|
44
|
+
|
45
|
+
# We don't test responses like 100 Continue at the moment.
|
46
|
+
%w(200 201 202 203 204 205 206 300 301 302 303 307 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 500 501 502 503 504 505).each do |code|
|
47
|
+
it "for Net::HTTP.start(host, port, &block) with response code #{code}" do
|
48
|
+
assert_identical {
|
49
|
+
Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
|
50
|
+
http.get("/code/#{code}").tap { |resp|
|
51
|
+
# Force the response to be buffered while we are still in the EM loop, since we shut it down EM before the verifications
|
52
|
+
resp.body
|
53
|
+
}
|
54
|
+
end
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
it "for Net::HTTP.new(host, port).start(&block) with response code #{code}" do
|
59
|
+
assert_identical {
|
60
|
+
h = Net::HTTP.new('localhost', Mimic::MIMIC_DEFAULT_PORT)
|
61
|
+
h.start do |http|
|
62
|
+
http.get("/code/#{code}")
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "with response code 304" do
|
69
|
+
assert_identical {
|
70
|
+
Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
|
71
|
+
req = Net::HTTP::Get.new('/code/304')
|
72
|
+
req['If-Modified-Since'] = Time.now.rfc2822
|
73
|
+
http.request(req)
|
74
|
+
end
|
75
|
+
}
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'with post' do
|
80
|
+
assert_identical {
|
81
|
+
Net::HTTP.start('localhost', Mimic::MIMIC_DEFAULT_PORT) do |http|
|
82
|
+
req = Net::HTTP::Post.new('/testpost')
|
83
|
+
req.body = 'hello mimic'
|
84
|
+
http.request(req)
|
85
|
+
end
|
86
|
+
}
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
def run_requests(&block)
|
93
|
+
@expected_res = yield
|
94
|
+
EM.run do
|
95
|
+
Fiber.new do
|
96
|
+
@actual_res = yield
|
97
|
+
end.resume
|
98
|
+
EM.add_periodic_timer(0.0) do
|
99
|
+
EM.stop_event_loop if @actual_res
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def assert_identical(streamed=false, &block)
|
105
|
+
run_requests(&block)
|
106
|
+
@actual_res.should be_a_kind_of(Net::HTTPResponse)
|
107
|
+
@actual_res.should match_response(@expected_res, :streamed => streamed)
|
108
|
+
end
|
109
|
+
|
110
|
+
def match_response(expected, streamed=false)
|
111
|
+
ResponseMatcher.new(expected, streamed)
|
112
|
+
end
|
113
|
+
|
114
|
+
class ResponseMatcher
|
115
|
+
def initialize(expected, streamed=false)
|
116
|
+
@expected = expected
|
117
|
+
@streamed = streamed
|
118
|
+
end
|
119
|
+
|
120
|
+
def matches?(actual)
|
121
|
+
# Dates could differ slightly :(
|
122
|
+
expected_date = Time.parse(@expected.delete('date').join)
|
123
|
+
actual_date = Time.parse(actual.delete('date').join)
|
124
|
+
actual_date.should >= expected_date
|
125
|
+
actual_date.should <= expected_date + 2
|
126
|
+
|
127
|
+
actual.class.should == @expected.class
|
128
|
+
actual.code.should == @expected.code
|
129
|
+
actual.to_hash.should == @expected.to_hash.merge({"connection" => ['close']})
|
130
|
+
|
131
|
+
if @streamed
|
132
|
+
actual.instance_variable_get(:@streamed_body).should ==
|
133
|
+
@expected.instance_variable_get(:@streamed_body)
|
134
|
+
else
|
135
|
+
actual.body.should == @expected.body
|
136
|
+
end
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/spec/image.jpg
ADDED
Binary file
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'em-net-http'
|
4
|
+
require 'time'
|
5
|
+
require 'rspec'
|
6
|
+
|
7
|
+
require 'mimic'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.before(:all) do
|
11
|
+
Mimic.mimic do
|
12
|
+
Net::HTTPResponse::CODE_TO_OBJ.each do |code, klass|
|
13
|
+
get("/code/#{code}").returning("#{code} #{klass.name}", code.to_i, {})
|
14
|
+
end
|
15
|
+
|
16
|
+
get('/hello').returning('Hello World!', 200, {'Content-Type'=>'text/plain'})
|
17
|
+
|
18
|
+
class BigImageResponse
|
19
|
+
def each
|
20
|
+
::File.open('spec/image.jpg', "rb") { |file|
|
21
|
+
while part = file.read(8192)
|
22
|
+
yield part
|
23
|
+
end
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
resp = BigImageResponse.new
|
28
|
+
get('/image').returning(resp, 200, {"Content-Type" => 'image/jpeg'})
|
29
|
+
|
30
|
+
post('/testpost') do
|
31
|
+
"You said #{request.body.read}."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
config.after(:all) do
|
37
|
+
Mimic.cleanup!
|
38
|
+
end
|
39
|
+
end
|
metadata
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-net-http-npn47
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- James Fairbairn
|
9
|
+
- Neeraj PN
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-11-05 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: eventmachine
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.12.10
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.12.10
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: addressable
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: em-http-request
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 0.2.10
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 0.2.10
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: rspec
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ~>
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '2.5'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ~>
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '2.5'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: mimic
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.3.0
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.3.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: weary
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
description: Monkeypatching Net::HTTP to use em-http-request under the hood.
|
128
|
+
email:
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files:
|
132
|
+
- LICENSE
|
133
|
+
- README.md
|
134
|
+
files:
|
135
|
+
- .document
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- VERSION
|
141
|
+
- em-net-http.gemspec
|
142
|
+
- lib/em-net-http.rb
|
143
|
+
- lib/em-net-http/weary.rb
|
144
|
+
- lib/test.rb
|
145
|
+
- lib/test_weary.rb
|
146
|
+
- spec/em-net-http_spec.rb
|
147
|
+
- spec/image.jpg
|
148
|
+
- spec/spec.opts
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage:
|
151
|
+
licenses: []
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
requirements: []
|
169
|
+
rubyforge_project:
|
170
|
+
rubygems_version: 1.8.24
|
171
|
+
signing_key:
|
172
|
+
specification_version: 3
|
173
|
+
summary: Non-blocking replacement for Net::HTTP, for use in EventMachine
|
174
|
+
test_files: []
|
175
|
+
has_rdoc:
|