em-http-request 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
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