em-http-request 0.2.2 → 0.2.3
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.
Potentially problematic release.
This version of em-http-request might be problematic. Click here for more details.
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/ext/http11_client/Makefile +157 -0
- data/ext/http11_client/http11_client.bundle +0 -0
- data/lib/em-http.rb +3 -5
- data/lib/em-http/client.rb +8 -8
- data/lib/em-http/mock.rb +73 -0
- data/lib/em-http/request.rb +24 -15
- data/test/mock/fixtures/google.ca +21 -0
- data/test/mock/test_mock.rb +83 -0
- data/test/stallion.rb +11 -1
- data/test/test_multi.rb +1 -1
- data/test/test_request.rb +43 -2
- metadata +8 -5
- data/.gitignore +0 -4
data/Rakefile
CHANGED
@@ -36,6 +36,7 @@ end
|
|
36
36
|
|
37
37
|
task :spec do
|
38
38
|
sh 'spec test/test_*.rb'
|
39
|
+
sh 'spec test/mock/test_*.rb'
|
39
40
|
end
|
40
41
|
|
41
42
|
def make(makedir)
|
@@ -96,6 +97,7 @@ begin
|
|
96
97
|
gemspec.add_dependency('eventmachine', '>= 0.12.9')
|
97
98
|
gemspec.add_dependency('addressable', '>= 2.0.0')
|
98
99
|
gemspec.rubyforge_project = "em-http-request"
|
100
|
+
gemspec.files = FileList["[A-Z]*", "{lib,test,ext}/**/*"]
|
99
101
|
end
|
100
102
|
|
101
103
|
Jeweler::GemcutterTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
SHELL = /bin/sh
|
3
|
+
|
4
|
+
#### Start of system configuration section. ####
|
5
|
+
|
6
|
+
srcdir = .
|
7
|
+
topdir = /opt/local/lib/ruby/1.8/i686-darwin10
|
8
|
+
hdrdir = $(topdir)
|
9
|
+
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
10
|
+
exec_prefix = $(prefix)
|
11
|
+
prefix = $(DESTDIR)/opt/local
|
12
|
+
sharedstatedir = $(prefix)/com
|
13
|
+
mandir = $(DESTDIR)/opt/local/share/man
|
14
|
+
psdir = $(docdir)
|
15
|
+
oldincludedir = $(DESTDIR)/usr/include
|
16
|
+
localedir = $(datarootdir)/locale
|
17
|
+
bindir = $(exec_prefix)/bin
|
18
|
+
libexecdir = $(exec_prefix)/libexec
|
19
|
+
sitedir = $(libdir)/ruby/site_ruby
|
20
|
+
htmldir = $(docdir)
|
21
|
+
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
22
|
+
includedir = $(prefix)/include
|
23
|
+
infodir = $(datarootdir)/info
|
24
|
+
vendorlibdir = $(vendordir)/$(ruby_version)
|
25
|
+
sysconfdir = $(prefix)/etc
|
26
|
+
libdir = $(exec_prefix)/lib
|
27
|
+
sbindir = $(exec_prefix)/sbin
|
28
|
+
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
29
|
+
docdir = $(datarootdir)/doc/$(PACKAGE)
|
30
|
+
dvidir = $(docdir)
|
31
|
+
vendordir = $(DESTDIR)/opt/local/lib/ruby/vendor_ruby
|
32
|
+
datarootdir = $(prefix)/share
|
33
|
+
pdfdir = $(docdir)
|
34
|
+
archdir = $(rubylibdir)/$(arch)
|
35
|
+
sitearchdir = $(sitelibdir)/$(sitearch)
|
36
|
+
datadir = $(datarootdir)
|
37
|
+
localstatedir = $(prefix)/var
|
38
|
+
sitelibdir = $(sitedir)/$(ruby_version)
|
39
|
+
|
40
|
+
CC = /usr/bin/gcc-4.2
|
41
|
+
LIBRUBY = $(LIBRUBY_SO)
|
42
|
+
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
43
|
+
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
44
|
+
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
45
|
+
|
46
|
+
RUBY_EXTCONF_H =
|
47
|
+
CFLAGS = -fno-common -O2 -arch x86_64 -fno-common -pipe -fno-common $(cflags) -arch x86_64
|
48
|
+
INCFLAGS = -I. -I. -I/opt/local/lib/ruby/1.8/i686-darwin10 -I.
|
49
|
+
DEFS =
|
50
|
+
CPPFLAGS = -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -I/opt/local/include
|
51
|
+
CXXFLAGS = $(CFLAGS)
|
52
|
+
ldflags = -L. -L/opt/local/lib
|
53
|
+
dldflags =
|
54
|
+
archflag = -arch x86_64
|
55
|
+
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
|
56
|
+
LDSHARED = $(CC) -dynamic -bundle -undefined suppress -flat_namespace
|
57
|
+
AR = ar
|
58
|
+
EXEEXT =
|
59
|
+
|
60
|
+
RUBY_INSTALL_NAME = ruby
|
61
|
+
RUBY_SO_NAME = ruby
|
62
|
+
arch = i686-darwin10
|
63
|
+
sitearch = i686-darwin10
|
64
|
+
ruby_version = 1.8
|
65
|
+
ruby = /opt/local/bin/ruby
|
66
|
+
RUBY = $(ruby)
|
67
|
+
RM = rm -f
|
68
|
+
MAKEDIRS = mkdir -p
|
69
|
+
INSTALL = /usr/bin/install -c
|
70
|
+
INSTALL_PROG = $(INSTALL) -m 0755
|
71
|
+
INSTALL_DATA = $(INSTALL) -m 644
|
72
|
+
COPY = cp
|
73
|
+
|
74
|
+
#### End of system configuration section. ####
|
75
|
+
|
76
|
+
preload =
|
77
|
+
|
78
|
+
libpath = . $(libdir)
|
79
|
+
LIBPATH = -L. -L$(libdir)
|
80
|
+
DEFFILE =
|
81
|
+
|
82
|
+
CLEANFILES = mkmf.log
|
83
|
+
DISTCLEANFILES =
|
84
|
+
|
85
|
+
extout =
|
86
|
+
extout_prefix =
|
87
|
+
target_prefix =
|
88
|
+
LOCAL_LIBS =
|
89
|
+
LIBS = $(LIBRUBYARG_SHARED) -lc -lpthread -ldl -lobjc
|
90
|
+
SRCS = http11_client.c http11_parser.c
|
91
|
+
OBJS = http11_client.o http11_parser.o
|
92
|
+
TARGET = http11_client
|
93
|
+
DLLIB = $(TARGET).bundle
|
94
|
+
EXTSTATIC =
|
95
|
+
STATIC_LIB =
|
96
|
+
|
97
|
+
BINDIR = $(bindir)
|
98
|
+
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
99
|
+
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
100
|
+
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
101
|
+
|
102
|
+
TARGET_SO = $(DLLIB)
|
103
|
+
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
104
|
+
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
105
|
+
|
106
|
+
all: $(DLLIB)
|
107
|
+
static: $(STATIC_LIB)
|
108
|
+
|
109
|
+
clean:
|
110
|
+
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
111
|
+
|
112
|
+
distclean: clean
|
113
|
+
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
114
|
+
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
115
|
+
|
116
|
+
realclean: distclean
|
117
|
+
install: install-so install-rb
|
118
|
+
|
119
|
+
install-so: $(RUBYARCHDIR)
|
120
|
+
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
121
|
+
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
122
|
+
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
123
|
+
install-rb: pre-install-rb install-rb-default
|
124
|
+
install-rb-default: pre-install-rb-default
|
125
|
+
pre-install-rb: Makefile
|
126
|
+
pre-install-rb-default: Makefile
|
127
|
+
$(RUBYARCHDIR):
|
128
|
+
$(MAKEDIRS) $@
|
129
|
+
|
130
|
+
site-install: site-install-so site-install-rb
|
131
|
+
site-install-so: install-so
|
132
|
+
site-install-rb: install-rb
|
133
|
+
|
134
|
+
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
135
|
+
|
136
|
+
.cc.o:
|
137
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
138
|
+
|
139
|
+
.cxx.o:
|
140
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
141
|
+
|
142
|
+
.cpp.o:
|
143
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
144
|
+
|
145
|
+
.C.o:
|
146
|
+
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
147
|
+
|
148
|
+
.c.o:
|
149
|
+
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
150
|
+
|
151
|
+
$(DLLIB): $(OBJS) Makefile
|
152
|
+
@-$(RM) $@
|
153
|
+
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
$(OBJS): ruby.h defines.h
|
Binary file
|
data/lib/em-http.rb
CHANGED
@@ -3,10 +3,8 @@
|
|
3
3
|
# You can redistribute this under the terms of the Ruby license
|
4
4
|
# See file LICENSE for details
|
5
5
|
#++
|
6
|
-
|
7
|
-
require '
|
8
|
-
require 'eventmachine'
|
9
|
-
|
6
|
+
|
7
|
+
require 'eventmachine'
|
10
8
|
|
11
9
|
require File.dirname(__FILE__) + '/http11_client'
|
12
10
|
require File.dirname(__FILE__) + '/em_buffer'
|
@@ -15,4 +13,4 @@ require File.dirname(__FILE__) + '/em-http/core_ext/hash'
|
|
15
13
|
require File.dirname(__FILE__) + '/em-http/client'
|
16
14
|
require File.dirname(__FILE__) + '/em-http/multi'
|
17
15
|
require File.dirname(__FILE__) + '/em-http/request'
|
18
|
-
require File.dirname(__FILE__) + '/em-http/decoders'
|
16
|
+
require File.dirname(__FILE__) + '/em-http/decoders'
|
data/lib/em-http/client.rb
CHANGED
@@ -108,18 +108,18 @@ module EventMachine
|
|
108
108
|
@uri.host + (@uri.port != 80 ? ":#{@uri.port}" : "")
|
109
109
|
end
|
110
110
|
|
111
|
-
def encode_request(method, path, query)
|
112
|
-
HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(path, query)]
|
111
|
+
def encode_request(method, path, query, uri_query)
|
112
|
+
HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(path, query, uri_query)]
|
113
113
|
end
|
114
114
|
|
115
|
-
def encode_query(path, query)
|
115
|
+
def encode_query(path, query, uri_query)
|
116
116
|
encoded_query = if query.kind_of?(Hash)
|
117
117
|
query.map { |k, v| encode_param(k, v) }.join('&')
|
118
118
|
else
|
119
119
|
query.to_s
|
120
120
|
end
|
121
|
-
if
|
122
|
-
encoded_query = [encoded_query,
|
121
|
+
if !uri_query.to_s.empty?
|
122
|
+
encoded_query = [encoded_query, uri_query].reject {|part| part.empty?}.join("&")
|
123
123
|
end
|
124
124
|
return path if encoded_query.to_s.empty?
|
125
125
|
"#{path}?#{encoded_query}"
|
@@ -262,7 +262,7 @@ module EventMachine
|
|
262
262
|
end
|
263
263
|
|
264
264
|
# Build the request
|
265
|
-
request_header = encode_request(@method, @uri.path, query)
|
265
|
+
request_header = encode_request(@method, @uri.path, query, @uri.query)
|
266
266
|
request_header << encode_headers(head)
|
267
267
|
request_header << CRLF
|
268
268
|
|
@@ -367,9 +367,9 @@ module EventMachine
|
|
367
367
|
# correct location header - some servers will incorrectly give a relative URI
|
368
368
|
if @response_header.location
|
369
369
|
begin
|
370
|
-
location = URI.parse @response_header.location
|
370
|
+
location = Addressable::URI.parse @response_header.location
|
371
371
|
if location.relative?
|
372
|
-
location = (@uri.
|
372
|
+
location = (@uri.join location).to_s
|
373
373
|
@response_header[LOCATION] = location
|
374
374
|
end
|
375
375
|
rescue
|
data/lib/em-http/mock.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
module EventMachine
|
2
|
+
class HttpRequest
|
3
|
+
|
4
|
+
include HttpEncoding
|
5
|
+
|
6
|
+
class FakeHttpClient < EventMachine::HttpClient
|
7
|
+
|
8
|
+
def setup(response)
|
9
|
+
receive_data(response)
|
10
|
+
succeed(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def unbind
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
@@registry = nil
|
19
|
+
@@registry_count = nil
|
20
|
+
|
21
|
+
def self.reset_counts!
|
22
|
+
@@registry_count = Hash.new{|h,k| h[k] = Hash.new(0)}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.reset_registry!
|
26
|
+
@@registry = Hash.new{|h,k| h[k] = {}}
|
27
|
+
end
|
28
|
+
|
29
|
+
reset_counts!
|
30
|
+
reset_registry!
|
31
|
+
|
32
|
+
@@pass_through_requests = true
|
33
|
+
|
34
|
+
def self.pass_through_requests=(pass_through_requests)
|
35
|
+
@@pass_through_requests = pass_through_requests
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.pass_through_requests
|
39
|
+
@@pass_through_requests
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.register(uri, method, data)
|
43
|
+
method = method.to_s.upcase
|
44
|
+
@@registry[uri][method] = data
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.register_file(uri, method, file)
|
48
|
+
register(uri, method, File.read(file))
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.count(uri, method)
|
52
|
+
method = method.to_s.upcase
|
53
|
+
@@registry_count[uri][method]
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :real_send_request, :send_request
|
57
|
+
|
58
|
+
protected
|
59
|
+
def send_request
|
60
|
+
query = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}#{encode_query(@uri.path, @options[:query], @uri.query)}"
|
61
|
+
if s = @@registry[query] and fake = s[@method]
|
62
|
+
@@registry_count[query][@method] += 1
|
63
|
+
client = FakeHttpClient.new(nil)
|
64
|
+
client.setup(fake)
|
65
|
+
client
|
66
|
+
elsif @@pass_through_requests
|
67
|
+
real_send_request
|
68
|
+
else
|
69
|
+
raise "this request #{query} for method #{@method} isn't registered, and pass_through_requests is current set to false"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/em-http/request.rb
CHANGED
@@ -24,6 +24,8 @@ module EventMachine
|
|
24
24
|
#
|
25
25
|
|
26
26
|
class HttpRequest
|
27
|
+
|
28
|
+
attr_reader :options, :method
|
27
29
|
|
28
30
|
def initialize(host, headers = {})
|
29
31
|
@headers = headers
|
@@ -45,35 +47,42 @@ module EventMachine
|
|
45
47
|
# Called for each response body chunk (you may assume HTTP 200
|
46
48
|
# OK then)
|
47
49
|
#
|
48
|
-
|
49
|
-
def get
|
50
|
-
def head
|
51
|
-
def
|
50
|
+
|
51
|
+
def get options = {}; setup_request(:get, options); end
|
52
|
+
def head options = {}; setup_request(:head, options); end
|
53
|
+
def delete options = {}; setup_request(:delete, options); end
|
54
|
+
def put options = {}; setup_request(:put, options); end
|
55
|
+
def post options = {}; setup_request(:post, options); end
|
52
56
|
|
53
57
|
protected
|
54
58
|
|
55
|
-
def
|
59
|
+
def setup_request(method, options)
|
56
60
|
raise ArgumentError, "invalid request path" unless /^\// === @uri.path
|
57
61
|
|
62
|
+
@options = options
|
63
|
+
|
58
64
|
# default connect & inactivity timeouts
|
59
|
-
options[:timeout] = 5 if not options[:timeout]
|
65
|
+
@options[:timeout] = 5 if not @options[:timeout]
|
60
66
|
|
61
67
|
# Make sure the port is set as Addressable::URI doesn't set the
|
62
68
|
# port if it isn't there.
|
63
|
-
@uri.port
|
64
|
-
method = method.to_s.upcase
|
69
|
+
@uri.port ||= 80
|
70
|
+
@method = method.to_s.upcase
|
71
|
+
send_request
|
72
|
+
end
|
73
|
+
|
74
|
+
def send_request
|
65
75
|
begin
|
66
76
|
EventMachine.connect(@uri.host, @uri.port, EventMachine::HttpClient) { |c|
|
67
77
|
c.uri = @uri
|
68
|
-
c.method = method
|
69
|
-
c.options = options
|
70
|
-
c.comm_inactivity_timeout = options[:timeout]
|
71
|
-
c.pending_connect_timeout = options[:timeout]
|
78
|
+
c.method = @method
|
79
|
+
c.options = @options
|
80
|
+
c.comm_inactivity_timeout = @options[:timeout]
|
81
|
+
c.pending_connect_timeout = @options[:timeout]
|
72
82
|
}
|
73
|
-
rescue
|
74
|
-
raise e unless e.message == "no connection"
|
83
|
+
rescue EventMachine::ConnectionError => e
|
75
84
|
conn = EventMachine::HttpClient.new("")
|
76
|
-
conn.on_error(
|
85
|
+
conn.on_error(e.message, true)
|
77
86
|
conn
|
78
87
|
end
|
79
88
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
HTTP/1.0 200 OK
|
2
|
+
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
3
|
+
Expires: -1
|
4
|
+
Cache-Control: private, max-age=0
|
5
|
+
Content-Type: text/html; charset=ISO-8859-1
|
6
|
+
Set-Cookie: PREF=ID=9454187d21c4a6a6:TM=1258403955:LM=1258403955:S=2-mf1n5oV5yAeT9-; expires=Wed, 16-Nov-2011 20:39:15 GMT; path=/; domain=.google.ca
|
7
|
+
Set-Cookie: NID=28=lvxxVdiBQkCetu_WFaUxLyB7qPlHXS5OdAGYTqge_laVlCKVN8VYYeVBh4bNZiK_Oan2gm8oP9GA-FrZfMPC3ZMHeNq37MG2JH8AIW9LYucU8brOeuggMEbLNNXuiWg4; expires=Tue, 18-May-2010 20:39:15 GMT; path=/; domain=.google.ca; HttpOnly
|
8
|
+
Server: gws
|
9
|
+
X-XSS-Protection: 0
|
10
|
+
X-Cache: MISS from .
|
11
|
+
Via: 1.0 .:80 (squid)
|
12
|
+
Connection: close
|
13
|
+
|
14
|
+
<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"eLgBS4LROqCQedKVvfUL",kEXPI:"17259,21329,21516,22107",kCSI:{e:"17259,21329,21516,22107",ei:"eLgBS4LROqCQedKVvfUL"},kHL:"en",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||"/gen_204?atyp=i&ct="+b+"&cad="+d+"&zx="+google.time();a.src=c;e.li=f+1},lc:[],li:0};
|
15
|
+
window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{}catch(b){}window.google.jsrt_kill=1;
|
16
|
+
var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf("#")==-1){for(var c=0;c<a.length;){var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&&
|
17
|
+
window._gjuc())&&setTimeout(_gjp,500)};
|
18
|
+
window._gjp && _gjp()</script><style>td{line-height:.8em;}.gac_m td{line-height:17px;}form{margin-bottom:20px;}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{font:17px arial,sans-serif;margin-bottom:.2em;vertical-align:bottom;}input{font-family:inherit}.lsb,.gac_sb{font-size:15px;height:1.85em!important;margin:.2em;}#gbar{height:22px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#guser{padding-bottom:7px !important;text-align:right}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb3,a.gb4{color:#00c !important}.gb3{text-decoration:none}</style><script>google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="document.f.q.focus();if(document.images)new Image().src='/images/nav_logo7.png'" topmargin=3 marginheight=3><textarea id=csi style=display:none></textarea><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.ca/imghp?hl=en&tab=wi" class=gb1>Images</a> <a href="http://video.google.ca/?hl=en&tab=wv" class=gb1>Videos</a> <a href="http://maps.google.ca/maps?hl=en&tab=wl" class=gb1>Maps</a> <a href="http://news.google.ca/nwshp?hl=en&tab=wn" class=gb1>News</a> <a href="http://groups.google.ca/grphp?hl=en&tab=wg" class=gb1>Groups</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.ca/intl/en/options/" class=gb3><u>more</u> »</a></nobr></div><div id=guser width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.ca/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNG2Kt7TgMZuV7Fl3FeeTOmTWMvggA" class=gb4>iGoogle</a> | <a href="/preferences?hl=en" class=gb4>Search settings</a> | <a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.ca/" class=gb4>Sign in</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ca/images/logo.gif" width=276 id=logo onload="window.lol&&lol()"><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%> </td><td align=center nowrap><input name=hl type=hidden value=en><input name=source type=hidden value=hp><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 class=lst title="Google Search" value=""><br><input name=btnG type=submit value="Google Search" class=lsb><input name=btnI type=submit value="I'm Feeling Lucky" class=lsb></td><td nowrap width=25% align=left><font size=-2> <a href=/advanced_search?hl=en>Advanced Search</a><br> <a href=/language_tools?hl=en>Language Tools</a></font></td></tr><tr><td align=center colspan=3><font size=-1><span style="text-align:left">Search: <input id=all type=radio name=meta value="" checked><label for=all> the web </label> <input id=cty type=radio name=meta value="cr=countryCA"><label for=cty> pages from Canada </label> </span></font></td></tr></table></form><br><font size=-1>Google.ca offered in: <a href="http://www.google.ca/setprefs?sig=0_XtMil90_yvnNEW8dIglASaHCVhU=&hl=fr">fran?ais</a> </font><br><br><br><font size=-1><a href="/intl/en/ads/">Advertising Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a> - <a href="http://www.google.com/ncr">Go to Google.com</a></font><p><font size=-2>©2009 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];if(google.y)google.y.first=[];google.dstr=[];google.rein=[];window.setTimeout(function(){var a=document.createElement("script");a.src="/extern_js/f/CgJlbhICY2EgACswCjhBQB0sKzAOOAksKzAYOAQsKzAlOMmIASwrMCY4BywrMCc4Aiw/n_sssePDGvc.js";(document.getElementById("xjsd")||document.body).appendChild(a)},0);
|
19
|
+
;google.y.first.push(function(){google.ac.b=true;google.ac.i(document.f,document.f.q,'','')});google.xjs&&google.j&&google.j.xi&&google.j.xi()</script></div><script>(function(){
|
20
|
+
function a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.timers.load.t.xjs&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",a,false);else if(window.attachEvent)window.attachEvent("onload",a);google.timers.load.t.prt=(new Date).getTime();
|
21
|
+
})();
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require 'lib/em-http'
|
6
|
+
require 'lib/em-http/mock'
|
7
|
+
|
8
|
+
describe 'em-http mock' do
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
EM::HttpRequest.reset_registry!
|
12
|
+
EM::HttpRequest.reset_counts!
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should serve a fake http request from a file" do
|
16
|
+
EM::HttpRequest.register_file('http://www.google.ca:80/', :get, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
|
17
|
+
EM.run do
|
18
|
+
http = EM::HttpRequest.new('http://www.google.ca/').get
|
19
|
+
http.callback do
|
20
|
+
http.response.should == File.read(File.join(File.dirname(__FILE__), 'fixtures', 'google.ca')).split("\n\n", 2).last
|
21
|
+
EM.stop
|
22
|
+
end
|
23
|
+
http.errback do
|
24
|
+
fail
|
25
|
+
EM.stop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
EM::HttpRequest.count('http://www.google.ca:80/', :get).should == 1
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should serve a fake http request from a string" do
|
33
|
+
data = <<-HEREDOC
|
34
|
+
HTTP/1.0 200 OK
|
35
|
+
Date: Mon, 16 Nov 2009 20:39:15 GMT
|
36
|
+
Expires: -1
|
37
|
+
Cache-Control: private, max-age=0
|
38
|
+
Content-Type: text/html; charset=ISO-8859-1
|
39
|
+
Set-Cookie: PREF=ID=9454187d21c4a6a6:TM=1258403955:LM=1258403955:S=2-mf1n5oV5yAeT9-; expires=Wed, 16-Nov-2011 20:39:15 GMT; path=/; domain=.google.ca
|
40
|
+
Set-Cookie: NID=28=lvxxVdiBQkCetu_WFaUxLyB7qPlHXS5OdAGYTqge_laVlCKVN8VYYeVBh4bNZiK_Oan2gm8oP9GA-FrZfMPC3ZMHeNq37MG2JH8AIW9LYucU8brOeuggMEbLNNXuiWg4; expires=Tue, 18-May-2010 20:39:15 GMT; path=/; domain=.google.ca; HttpOnly
|
41
|
+
Server: gws
|
42
|
+
X-XSS-Protection: 0
|
43
|
+
X-Cache: MISS from .
|
44
|
+
Via: 1.0 .:80 (squid)
|
45
|
+
Connection: close
|
46
|
+
|
47
|
+
<!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"eLgBS4LROqCQedKVvfUL",kEXPI:"17259,21329,21516,22107",kCSI:{e:"17259,21329,21516,22107",ei:"eLgBS4LROqCQedKVvfUL"},kHL:"en",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||"/gen_204?atyp=i&ct="+b+"&cad="+d+"&zx="+google.time();a.src=c;e.li=f+1},lc:[],li:0};
|
48
|
+
window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{}catch(b){}window.google.jsrt_kill=1;
|
49
|
+
var _gjwl=location;function _gjuc(){var e=_gjwl.href.indexOf("#");if(e>=0){var a=_gjwl.href.substring(e);if(a.indexOf("&q=")>0||a.indexOf("#q=")>=0){a=a.substring(1);if(a.indexOf("#")==-1){for(var c=0;c<a.length;){var d=c;if(a.charAt(d)=="&")++d;var b=a.indexOf("&",d);if(b==-1)b=a.length;var f=a.substring(d,b);if(f.indexOf("fp=")==0){a=a.substring(0,c)+a.substring(b,a.length);b=c}else if(f=="cad=h")return 0;c=b}_gjwl.href="/search?"+a+"&cad=h";return 1}}}return 0}function _gjp(){!(window._gjwl.hash&&
|
50
|
+
window._gjuc())&&setTimeout(_gjp,500)};
|
51
|
+
window._gjp && _gjp()</script><style>td{line-height:.8em;}.gac_m td{line-height:17px;}form{margin-bottom:20px;}body,td,a,p,.h{font-family:arial,sans-serif}.h{color:#36c;font-size:20px}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{font:17px arial,sans-serif;margin-bottom:.2em;vertical-align:bottom;}input{font-family:inherit}.lsb,.gac_sb{font-size:15px;height:1.85em!important;margin:.2em;}#gbar{height:22px}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#guser{padding-bottom:7px !important;text-align:right}#gbar,#guser{font-size:13px;padding-top:1px !important}@media all{.gb1,.gb3{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb3,a.gb4{color:#00c !important}.gb3{text-decoration:none}</style><script>google.y={};google.x=function(e,g){google.y[e.id]=[e,g];return false};</script></head><body bgcolor=#ffffff text=#000000 link=#0000cc vlink=#551a8b alink=#ff0000 onload="document.f.q.focus();if(document.images)new Image().src='/images/nav_logo7.png'" topmargin=3 marginheight=3><textarea id=csi style=display:none></textarea><div id=gbar><nobr><b class=gb1>Web</b> <a href="http://images.google.ca/imghp?hl=en&tab=wi" class=gb1>Images</a> <a href="http://video.google.ca/?hl=en&tab=wv" class=gb1>Videos</a> <a href="http://maps.google.ca/maps?hl=en&tab=wl" class=gb1>Maps</a> <a href="http://news.google.ca/nwshp?hl=en&tab=wn" class=gb1>News</a> <a href="http://groups.google.ca/grphp?hl=en&tab=wg" class=gb1>Groups</a> <a href="http://mail.google.com/mail/?hl=en&tab=wm" class=gb1>Gmail</a> <a href="http://www.google.ca/intl/en/options/" class=gb3><u>more</u> »</a></nobr></div><div id=guser width=100%><nobr><a href="/url?sa=p&pref=ig&pval=3&q=http://www.google.ca/ig%3Fhl%3Den%26source%3Diglk&usg=AFQjCNG2Kt7TgMZuV7Fl3FeeTOmTWMvggA" class=gb4>iGoogle</a> | <a href="/preferences?hl=en" class=gb4>Search settings</a> | <a href="https://www.google.com/accounts/Login?hl=en&continue=http://www.google.ca/" class=gb4>Sign in</a></nobr></div><div class=gbh style=left:0></div><div class=gbh style=right:0></div><center><br clear=all id=lgpd><img alt="Google" height=110 src="/intl/en_ca/images/logo.gif" width=276 id=logo onload="window.lol&&lol()"><br><br><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%> </td><td align=center nowrap><input name=hl type=hidden value=en><input name=source type=hidden value=hp><input type=hidden name=ie value="ISO-8859-1"><input autocomplete="off" maxlength=2048 name=q size=55 class=lst title="Google Search" value=""><br><input name=btnG type=submit value="Google Search" class=lsb><input name=btnI type=submit value="I'm Feeling Lucky" class=lsb></td><td nowrap width=25% align=left><font size=-2> <a href=/advanced_search?hl=en>Advanced Search</a><br> <a href=/language_tools?hl=en>Language Tools</a></font></td></tr><tr><td align=center colspan=3><font size=-1><span style="text-align:left">Search: <input id=all type=radio name=meta value="" checked><label for=all> the web </label> <input id=cty type=radio name=meta value="cr=countryCA"><label for=cty> pages from Canada </label> </span></font></td></tr></table></form><br><font size=-1>Google.ca offered in: <a href="http://www.google.ca/setprefs?sig=0_XtMil90_yvnNEW8dIglASaHCVhU=&hl=fr">fran?ais</a> </font><br><br><br><font size=-1><a href="/intl/en/ads/">Advertising Programs</a> - <a href="/services/">Business Solutions</a> - <a href="/intl/en/about.html">About Google</a> - <a href="http://www.google.com/ncr">Go to Google.com</a></font><p><font size=-2>©2009 - <a href="/intl/en/privacy.html">Privacy</a></font></p></center><div id=xjsd></div><div id=xjsi><script>if(google.y)google.y.first=[];if(google.y)google.y.first=[];google.dstr=[];google.rein=[];window.setTimeout(function(){var a=document.createElement("script");a.src="/extern_js/f/CgJlbhICY2EgACswCjhBQB0sKzAOOAksKzAYOAQsKzAlOMmIASwrMCY4BywrMCc4Aiw/n_sssePDGvc.js";(document.getElementById("xjsd")||document.body).appendChild(a)},0);
|
52
|
+
;google.y.first.push(function(){google.ac.b=true;google.ac.i(document.f,document.f.q,'','')});google.xjs&&google.j&&google.j.xi&&google.j.xi()</script></div><script>(function(){
|
53
|
+
function a(){google.timers.load.t.ol=(new Date).getTime();google.report&&google.timers.load.t.xjs&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",a,false);else if(window.attachEvent)window.attachEvent("onload",a);google.timers.load.t.prt=(new Date).getTime();
|
54
|
+
})();
|
55
|
+
HEREDOC
|
56
|
+
EM::HttpRequest.register('http://www.google.ca:80/', :get, data)
|
57
|
+
EM.run do
|
58
|
+
http = EM::HttpRequest.new('http://www.google.ca/').get
|
59
|
+
http.callback do
|
60
|
+
http.response.should == data.split("\n\n", 2).last
|
61
|
+
EM.stop
|
62
|
+
end
|
63
|
+
http.errback do
|
64
|
+
fail
|
65
|
+
EM.stop
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
EM::HttpRequest.count('http://www.google.ca:80/', :get).should == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should raise an exception if pass-thru is disabled" do
|
73
|
+
EM::HttpRequest.pass_through_requests = false
|
74
|
+
EM.run do
|
75
|
+
proc {
|
76
|
+
http = EM::HttpRequest.new('http://www.google.ca/').get
|
77
|
+
}.should raise_error
|
78
|
+
EM.stop
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
data/test/stallion.rb
CHANGED
@@ -85,7 +85,13 @@ Stallion.saddle :spec do |stable|
|
|
85
85
|
|
86
86
|
elsif stable.request.head?
|
87
87
|
stable.response.status = 200
|
88
|
-
|
88
|
+
|
89
|
+
elsif stable.request.delete?
|
90
|
+
stable.response.status = 200
|
91
|
+
|
92
|
+
elsif stable.request.put?
|
93
|
+
stable.response.write stable.request.body.read
|
94
|
+
|
89
95
|
elsif stable.request.post?
|
90
96
|
if stable.request.path_info == '/echo_content_type'
|
91
97
|
stable.response.write stable.request.env["CONTENT_TYPE"]
|
@@ -130,6 +136,10 @@ Stallion.saddle :spec do |stable|
|
|
130
136
|
stable.response.status = 401
|
131
137
|
end
|
132
138
|
|
139
|
+
elsif stable.request.path_info == '/relative-location'
|
140
|
+
stable.response.status = 301
|
141
|
+
stable.response["Location"] = '/forwarded'
|
142
|
+
|
133
143
|
elsif
|
134
144
|
stable.response.write 'Hello, World!'
|
135
145
|
end
|
data/test/test_multi.rb
CHANGED
@@ -11,7 +11,7 @@ describe EventMachine::MultiRequest do
|
|
11
11
|
|
12
12
|
# add multiple requests to the multi-handler
|
13
13
|
multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'}))
|
14
|
-
multi.add(EventMachine::HttpRequest.new('http://0.0.0.0/').get(:timeout => 1))
|
14
|
+
multi.add(EventMachine::HttpRequest.new('http://0.0.0.0:8081/').get(:timeout => 1))
|
15
15
|
|
16
16
|
multi.callback {
|
17
17
|
# verify successfull request
|
data/test/test_request.rb
CHANGED
@@ -17,7 +17,7 @@ describe EventMachine::HttpRequest do
|
|
17
17
|
http.response_header.status.should == 0
|
18
18
|
EventMachine.stop
|
19
19
|
}
|
20
|
-
}
|
20
|
+
}
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should fail GET on invalid host" do
|
@@ -26,7 +26,7 @@ describe EventMachine::HttpRequest do
|
|
26
26
|
http.callback { failed }
|
27
27
|
http.errback {
|
28
28
|
http.response_header.status.should == 0
|
29
|
-
http.errors.should match(/
|
29
|
+
http.errors.should match(/unable to resolve server address/)
|
30
30
|
EventMachine.stop
|
31
31
|
}
|
32
32
|
}
|
@@ -82,6 +82,21 @@ describe EventMachine::HttpRequest do
|
|
82
82
|
}
|
83
83
|
}
|
84
84
|
end
|
85
|
+
|
86
|
+
# should be no different than a GET
|
87
|
+
it "should perform successfull DELETE with a URI passed as argument" do
|
88
|
+
EventMachine.run {
|
89
|
+
uri = URI.parse('http://127.0.0.1:8080/')
|
90
|
+
http = EventMachine::HttpRequest.new(uri).delete
|
91
|
+
|
92
|
+
http.errback { failed }
|
93
|
+
http.callback {
|
94
|
+
http.response_header.status.should == 200
|
95
|
+
http.response.should == ""
|
96
|
+
EventMachine.stop
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
85
100
|
|
86
101
|
it "should return 404 on invalid path" do
|
87
102
|
EventMachine.run {
|
@@ -134,6 +149,20 @@ describe EventMachine::HttpRequest do
|
|
134
149
|
}
|
135
150
|
end
|
136
151
|
|
152
|
+
# should be no different than a POST
|
153
|
+
it "should perform successfull PUT" do
|
154
|
+
EventMachine.run {
|
155
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').put :body => "data"
|
156
|
+
|
157
|
+
http.errback { failed }
|
158
|
+
http.callback {
|
159
|
+
http.response_header.status.should == 200
|
160
|
+
http.response.should match(/data/)
|
161
|
+
EventMachine.stop
|
162
|
+
}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
137
166
|
it "should perform successfull POST" do
|
138
167
|
EventMachine.run {
|
139
168
|
http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').post :body => "data"
|
@@ -432,4 +461,16 @@ describe EventMachine::HttpRequest do
|
|
432
461
|
}
|
433
462
|
end
|
434
463
|
end
|
464
|
+
|
465
|
+
it "should complete a Location: with a relative path" do
|
466
|
+
EventMachine.run {
|
467
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:8080/relative-location').get
|
468
|
+
|
469
|
+
http.errback { failed }
|
470
|
+
http.callback {
|
471
|
+
http.response_header['LOCATION'].should == 'http://127.0.0.1:8080/forwarded'
|
472
|
+
EventMachine.stop
|
473
|
+
}
|
474
|
+
}
|
475
|
+
end
|
435
476
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-http-request
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Grigorik
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-01 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -43,17 +43,16 @@ extra_rdoc_files:
|
|
43
43
|
- LICENSE
|
44
44
|
- README.rdoc
|
45
45
|
files:
|
46
|
-
- .gitignore
|
47
46
|
- LICENSE
|
48
47
|
- README.rdoc
|
49
48
|
- Rakefile
|
50
49
|
- VERSION
|
51
|
-
- examples/fetch.rb
|
52
|
-
- examples/fibered-http.rb
|
53
50
|
- ext/buffer/em_buffer.c
|
54
51
|
- ext/buffer/extconf.rb
|
52
|
+
- ext/http11_client/Makefile
|
55
53
|
- ext/http11_client/ext_help.h
|
56
54
|
- ext/http11_client/extconf.rb
|
55
|
+
- ext/http11_client/http11_client.bundle
|
57
56
|
- ext/http11_client/http11_client.c
|
58
57
|
- ext/http11_client/http11_parser.c
|
59
58
|
- ext/http11_client/http11_parser.h
|
@@ -62,9 +61,12 @@ files:
|
|
62
61
|
- lib/em-http/client.rb
|
63
62
|
- lib/em-http/core_ext/hash.rb
|
64
63
|
- lib/em-http/decoders.rb
|
64
|
+
- lib/em-http/mock.rb
|
65
65
|
- lib/em-http/multi.rb
|
66
66
|
- lib/em-http/request.rb
|
67
67
|
- test/helper.rb
|
68
|
+
- test/mock/fixtures/google.ca
|
69
|
+
- test/mock/test_mock.rb
|
68
70
|
- test/stallion.rb
|
69
71
|
- test/stub_server.rb
|
70
72
|
- test/test_hash.rb
|
@@ -100,6 +102,7 @@ specification_version: 3
|
|
100
102
|
summary: EventMachine based, async HTTP Request interface
|
101
103
|
test_files:
|
102
104
|
- test/helper.rb
|
105
|
+
- test/mock/test_mock.rb
|
103
106
|
- test/stallion.rb
|
104
107
|
- test/stub_server.rb
|
105
108
|
- test/test_hash.rb
|
data/.gitignore
DELETED