em-http-request 0.3.0 → 1.0.0.beta.1

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.

Files changed (44) hide show
  1. data/.gitignore +1 -0
  2. data/Changelog.md +10 -0
  3. data/README.md +43 -160
  4. data/Rakefile +2 -73
  5. data/em-http-request.gemspec +7 -7
  6. data/examples/fetch.rb +30 -30
  7. data/examples/fibered-http.rb +38 -38
  8. data/examples/oauth-tweet.rb +49 -49
  9. data/lib/em-http.rb +4 -6
  10. data/lib/em-http/client.rb +101 -522
  11. data/lib/em-http/http_connection.rb +125 -0
  12. data/lib/em-http/http_encoding.rb +19 -12
  13. data/lib/em-http/http_header.rb +2 -17
  14. data/lib/em-http/http_options.rb +37 -19
  15. data/lib/em-http/request.rb +33 -66
  16. data/lib/em-http/version.rb +2 -2
  17. data/spec/client_spec.rb +575 -0
  18. data/spec/dns_spec.rb +41 -0
  19. data/spec/encoding_spec.rb +6 -6
  20. data/spec/external_spec.rb +99 -0
  21. data/spec/fixtures/google.ca +13 -17
  22. data/spec/helper.rb +17 -8
  23. data/spec/http_proxy_spec.rb +53 -0
  24. data/spec/middleware_spec.rb +114 -0
  25. data/spec/multi_spec.rb +11 -38
  26. data/spec/pipelining_spec.rb +38 -0
  27. data/spec/redirect_spec.rb +114 -0
  28. data/spec/socksify_proxy_spec.rb +24 -0
  29. data/spec/ssl_spec.rb +20 -0
  30. data/spec/stallion.rb +7 -63
  31. metadata +59 -39
  32. data/examples/websocket-handler.rb +0 -28
  33. data/examples/websocket-server.rb +0 -8
  34. data/ext/buffer/em_buffer.c +0 -639
  35. data/ext/buffer/extconf.rb +0 -53
  36. data/ext/http11_client/ext_help.h +0 -14
  37. data/ext/http11_client/extconf.rb +0 -6
  38. data/ext/http11_client/http11_client.c +0 -328
  39. data/ext/http11_client/http11_parser.c +0 -418
  40. data/ext/http11_client/http11_parser.h +0 -48
  41. data/ext/http11_client/http11_parser.rl +0 -170
  42. data/lib/em-http/mock.rb +0 -137
  43. data/spec/mock_spec.rb +0 -166
  44. data/spec/request_spec.rb +0 -1003
data/spec/dns_spec.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::HttpRequest do
4
+
5
+ it "should fail gracefully on an invalid host in Location header" do
6
+ EventMachine.run {
7
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect/badhost', :connect_timeout => 0.1).get :redirects => 1
8
+ http.callback { failed(http) }
9
+ http.errback {
10
+ http.error.should match('unable to resolve server address')
11
+ EventMachine.stop
12
+ }
13
+ }
14
+ end
15
+
16
+ it "should fail GET on DNS timeout" do
17
+ EventMachine.run {
18
+ EventMachine.heartbeat_interval = 0.1
19
+ http = EventMachine::HttpRequest.new('http://127.1.1.1/', :connect_timeout => 0.1).get
20
+ http.callback { failed(http) }
21
+ http.errback {
22
+ http.response_header.status.should == 0
23
+ EventMachine.stop
24
+ }
25
+ }
26
+ end
27
+
28
+ it "should fail GET on invalid host" do
29
+ EventMachine.run {
30
+ EventMachine.heartbeat_interval = 0.1
31
+ http = EventMachine::HttpRequest.new('http://somethinglocal/', :connect_timeout => 0.1).get
32
+ http.callback { failed(http) }
33
+ http.errback {
34
+ http.error.should match(/unable to resolve server address/)
35
+ http.response_header.status.should == 0
36
+ EventMachine.stop
37
+ }
38
+ }
39
+ end
40
+
41
+ end
@@ -31,10 +31,10 @@ describe EventMachine::HttpEncoding do
31
31
  params.should == "bad%26str[key%26key][0]=bad%2B%26stuff&bad%26str[key%26key][1]=%5Btest%5D"
32
32
  end
33
33
 
34
- it "should be fast on long string escapes" do
35
- s = Time.now
36
- 5000.times { |n| form_encode_body({:a => "{a:'b', d:'f', g:['a','b']}"*50}) }
37
- (Time.now - s).should satisfy { |t| t < 1.5 }
38
- end
34
+ # xit "should be fast on long string escapes" do
35
+ # s = Time.now
36
+ # 5000.times { |n| form_encode_body({:a => "{a:'b', d:'f', g:['a','b']}"*50}) }
37
+ # (Time.now - s).should satisfy { |t| t < 1.5 }
38
+ # end
39
39
 
40
- end
40
+ end
@@ -0,0 +1,99 @@
1
+ require 'helper'
2
+
3
+ requires_connection do
4
+
5
+ describe EventMachine::HttpRequest do
6
+
7
+ it "should follow redirects on HEAD method (external)" do
8
+ EventMachine.run {
9
+ http = EventMachine::HttpRequest.new('http://www.google.com/').head :redirects => 1
10
+ http.errback { failed(http) }
11
+ http.callback {
12
+ http.response_header.status.should == 200
13
+ EM.stop
14
+ }
15
+ }
16
+ end
17
+
18
+ it "should perform a streaming GET" do
19
+ EventMachine.run {
20
+
21
+ # digg.com uses chunked encoding
22
+ http = EventMachine::HttpRequest.new('http://digg.com/news').get
23
+
24
+ http.errback { failed(http) }
25
+ http.callback {
26
+ http.response_header.status.should == 200
27
+ EventMachine.stop
28
+ }
29
+ }
30
+ end
31
+
32
+ it "should handle a 100 continue" do
33
+ EventMachine.run {
34
+ # 8.2.3 Use of the 100 (Continue) Status - http://www.ietf.org/rfc/rfc2616.txt
35
+ #
36
+ # An origin server SHOULD NOT send a 100 (Continue) response if
37
+ # the request message does not include an Expect request-header
38
+ # field with the "100-continue" expectation, and MUST NOT send a
39
+ # 100 (Continue) response if such a request comes from an HTTP/1.0
40
+ # (or earlier) client. There is an exception to this rule: for
41
+ # compatibility with RFC 2068, a server MAY send a 100 (Continue)
42
+ # status in response to an HTTP/1.1 PUT or POST request that does
43
+ # not include an Expect request-header field with the "100-
44
+ # continue" expectation. This exception, the purpose of which is
45
+ # to minimize any client processing delays associated with an
46
+ # undeclared wait for 100 (Continue) status, applies only to
47
+ # HTTP/1.1 requests, and not to requests with any other HTTP-
48
+ # version value.
49
+ #
50
+ # 10.1.1: 100 Continue - http://www.ietf.org/rfc/rfc2068.txt
51
+ # The client may continue with its request. This interim response is
52
+ # used to inform the client that the initial part of the request has
53
+ # been received and has not yet been rejected by the server. The client
54
+ # SHOULD continue by sending the remainder of the request or, if the
55
+ # request has already been completed, ignore this response. The server
56
+ # MUST send a final response after the request has been completed.
57
+
58
+ url = 'http://ws.serviceobjects.com/lv/LeadValidation.asmx/ValidateLead_V2'
59
+ http = EventMachine::HttpRequest.new(url).post :body => {:name => :test}
60
+
61
+ http.errback { failed(http) }
62
+ http.callback {
63
+ http.response_header.status.should == 500
64
+ http.response.should match('Missing')
65
+ EventMachine.stop
66
+ }
67
+ }
68
+ end
69
+
70
+ context "keepalive" do
71
+ it "should default to non-keepalive" do
72
+ EventMachine.run {
73
+ headers = {'If-Modified-Since' => 'Thu, 05 Aug 2010 22:54:44 GMT'}
74
+ http = EventMachine::HttpRequest.new('http://www.google.com/images/logos/ps_logo2.png').get :head => headers
75
+
76
+ http.errback { fail }
77
+ start = Time.now.to_i
78
+ http.callback {
79
+ (start - Time.now.to_i).should be_within(1).of(0)
80
+ EventMachine.stop
81
+ }
82
+ }
83
+ end
84
+
85
+ it "should work with keep-alive servers" do
86
+ EventMachine.run {
87
+ http = EventMachine::HttpRequest.new('http://mexicodiario.com/touch.public.json.php').get :keepalive => true
88
+
89
+ http.errback { failed(http) }
90
+ http.callback {
91
+ http.response_header.status.should == 200
92
+ EventMachine.stop
93
+ }
94
+ }
95
+ end
96
+ end
97
+
98
+ end
99
+ end
@@ -1,20 +1,16 @@
1
- HTTP/1.1 200 OK
2
- Date: Sat, 14 Aug 2010 21:58:26 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=11955ae9690fd292:TM=1281823106:LM=1281823106:S=wHdloFqGQ_OLSE92; expires=Mon, 13-Aug-2012 21:58:26 GMT; path=/; domain=.google.ca
7
- Set-Cookie: NID=37=USTdOsxOSMbLjphkJ3S5Ueua3Yc23COXuK_pbztcHx7JoyhomwQySrvebCf3_u8eyrBiLWssVzaZcEOiKGEJbNdy8lRhnq_mfrdz693LaMjNPh__ccW4sgn1ZO6nQltE; expires=Sun, 13-Feb-2011 21:58:26 GMT; path=/; domain=.google.ca; HttpOnly
1
+ HTTP/1.1 301 Moved Permanently
2
+ Location: http://www.google.ca/
3
+ Content-Type: text/html; charset=UTF-8
4
+ Date: Sun, 09 Jan 2011 02:51:43 GMT
5
+ Expires: Tue, 08 Feb 2011 02:51:43 GMT
6
+ Cache-Control: public, max-age=2592000
8
7
  Server: gws
8
+ Content-Length: 218
9
9
  X-XSS-Protection: 1; mode=block
10
10
 
11
- <!doctype html><html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title><script>window.google={kEI:"ghFnTJiGG9WhnQf4o9X8BA",kEXPI:"25913,25976,26060",kCSI:{e:"25913,25976,26060",ei:"ghFnTJiGG9WhnQf4o9X8BA",expi:"25913,25976,26060"},ml:function(){},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,Toolbelt:{}};
12
- window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{}catch(u){}window.google.jsrt_kill=1;
13
- 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&&
14
- window._gjuc())&&setTimeout(_gjp,500)};
15
- window._gjp && _gjp()</script><style id=gstyle>body{margin:0}#gog{padding:3px 8px 0}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{width:496px}.tiah{width:458px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}#gbar,#guser{font-size:13px;padding-top:1px !important}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{color:#00c !important}body{background:#fff;color:black}input{-moz-box-sizing:content-box}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#4272db}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff!important}.ds{display:-moz-inline-box}.ds{border-bottom:solid 1px #e7e7e7;border-right:solid 1px #e7e7e7;display:inline-block;margin:3px 0 4px;margin-left:4px}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px;}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px;display:block}.lsb{background:url(/images/srpr/nav_logo14.png) bottom;font:15px arial,sans-serif;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}.ftl,#fll a{margin:0 12px}#addlang a{padding:0 3px}.gac_v div{display:none}.gac_v .gac_v2,.gac_bt{display:block!important}</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/srpr/nav_logo14.png'" ><textarea id=csi style=display:none></textarea><div id=ghead><div id=gbar><nobr><b class=gb1>Web</b> <a onclick=gbar.qs(this) href="http://www.google.ca/imghp?hl=en&tab=wi" class=gb1>Images</a> <a onclick=gbar.qs(this) href="http://video.google.ca/?hl=en&tab=wv" class=gb1>Videos</a> <a onclick=gbar.qs(this) href="http://maps.google.ca/maps?hl=en&tab=wl" class=gb1>Maps</a> <a onclick=gbar.qs(this) href="http://news.google.ca/nwshp?hl=en&tab=wn" class=gb1>News</a> <a onclick=gbar.qs(this) href="http://books.google.ca/bkshp?hl=en&tab=wp" class=gb1>Books</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=gb1 style="text-decoration:none"><u>more</u> &raquo;</a></nobr></div><div id=guser width=100%><nobr><span id=gbn class=gbi></span><span id=gbf class=gbf></span><span id=gbe><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> | </span><a href="/preferences?hl=en" class=gb4>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></div> <center><br clear=all id=lgpd><div id=lga><table cellpadding=0 cellspacing=0 border=0><tr><td align=right valign=bottom><img src=images/hp0.gif width=158 height=78 alt="Google"></td><td valign=bottom><img src=images/hp1.gif width=50 height=78 alt=""></td><td valign=bottom><img src=images/hp2.gif width=68 height=78 alt=""></td></tr><tr><td class=h align=right valign=top><b></b></td><td valign=top><img src=images/hp3.gif width=50 height=32 alt=""></td><td valign=top class=h><font color=#666666 style=font-size:16px><b>Canada</b></font></td></tr></table><br></div><form action="/search" name=f><table cellpadding=0 cellspacing=0><tr valign=top><td width=25%>&nbsp;</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"><div class=ds style="height:32px;margin:4px 0"><input autocomplete="off" maxlength=2048 name=q class="lst" title="Google Search" value="" size=57 style="background:#fff;border:1px solid #ccc;border-bottom-color:#999;border-right-color:#999;color:#000;font:18px arial,sans-serif bold;height:25px;margin:0;padding:5px 8px 0 6px;vertical-align:top"></div><br style="line-height:0"><span class=ds><span class=lsbb><input name=btnG type=submit value="Google Search" class=lsb></span></span><span class=ds><span class=lsbb><input name=btnI type=submit value="I&#39;m Feeling Lucky" class=lsb></span></span></td><td nowrap width=25% align=left class=sblc><a href="/advanced_search?hl=en">Advanced Search</a><a href="/language_tools?hl=en">Language Tools</a></td></tr></table></form><div style="font-size:83%;min-height:3.5em"><br><div id=als><font size=-1 id=addlang>Google.ca offered in: <a href="http://www.google.ca/setprefs?sig=0_h3wwdBzWMwIKco5_3UM-S8-NI00=&amp;hl=fr">fran�ais</a></font><br><br></div></div><div id=res></div><span id=footer><center id=fctr><div style="font-size:10pt"><div id=fll style="margin:19px auto 19px auto;text-align:center"><a href="/intl/en/ads/">Advertising&nbsp;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></div></div><p style="color:#767676;font-size:8pt">&copy; 2010 - <a href="/intl/en/privacy.html">Privacy</a></p></center></span> <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/CgJlbhICY2EgACswRTgBLCswWjgDLCswDjgXLCswFzgHLCswJzgELCswPDgDLCswCjhzQB0sKzAlOMqIASwrMEA4EiwrMEE4BSwrMFQ4ACwrMBg4BSwrMCY4DSyAAheQAhY/shQ1OaVztmo.js";(document.getElementById("xjsd")||document.body).appendChild(a);if(google.timers&&google.timers.load.t)google.timers.load.t.xjsls=(new Date).getTime();},0);
16
- ;google.neegg=1;google.y.first.push(function(){var form=document.f||document.f||document.gs;google.ac.i(form,form.q,'','','',{o:1,sw:1});google.History&&google.History.initialize('/')});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);google.fade=null;}</script></div><script>(function(){
17
- var b,d,e,f;function g(a,c){if(a.removeEventListener){a.removeEventListener("load",c,false);a.removeEventListener("error",c,false)}else{a.detachEvent("onload",c);a.detachEvent("onerror",c)}}function h(a){f=(new Date).getTime();++d;a=a||window.event;var c=a.target||a.srcElement;g(c,h)}var i=document.getElementsByTagName("img");b=i.length;d=0;for(var j=0,k;j<b;++j){k=i[j];if(k.complete||typeof k.src!="string"||!k.src)++d;else if(k.addEventListener){k.addEventListener("load",h,false);k.addEventListener("error",
18
- h,false)}else{k.attachEvent("onload",h);k.attachEvent("onerror",h)}}e=b-d;function l(){if(!google.timers.load.t)return;google.timers.load.t.ol=(new Date).getTime();google.timers.load.t.iml=f;google.kCSI.imc=d;google.kCSI.imn=b;google.kCSI.imp=e;google.report&&google.report(google.timers.load,google.kCSI)}if(window.addEventListener)window.addEventListener("load",l,false);else if(window.attachEvent)window.attachEvent("onload",l);google.timers.load.t.prt=(f=(new Date).getTime());
19
- })();
20
- </script>
11
+ <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
12
+ <TITLE>301 Moved</TITLE></HEAD><BODY>
13
+ <H1>301 Moved</H1>
14
+ The document has moved
15
+ <A HREF="http://www.google.ca/">here</A>.
16
+ </BODY></HTML>
data/spec/helper.rb CHANGED
@@ -1,8 +1,17 @@
1
- require 'rubygems'
2
- require 'rspec'
3
- require 'pp'
4
-
5
- $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
6
-
7
- require 'em-http'
8
- require 'em-websocket'
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'em-http'
5
+ require 'yajl'
6
+
7
+ require 'stallion'
8
+ require 'stub_server'
9
+
10
+ def failed(http = nil)
11
+ EventMachine.stop
12
+ http ? fail(http.error) : fail
13
+ end
14
+
15
+ def requires_connection(&blk)
16
+ blk.call if system('ping -c1 google.com &> /dev/null')
17
+ end
@@ -0,0 +1,53 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::HttpRequest do
4
+
5
+ context "connections via" do
6
+ let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8083 }} }
7
+
8
+ it "should use HTTP proxy" do
9
+ EventMachine.run {
10
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get
11
+
12
+ http.errback { failed(http) }
13
+ http.callback {
14
+ http.response_header.status.should == 200
15
+ http.response.should match('test')
16
+ EventMachine.stop
17
+ }
18
+ }
19
+ end
20
+
21
+ it "should send absolute URIs to the proxy server" do
22
+ EventMachine.run {
23
+
24
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get
25
+
26
+ http.errback { failed(http) }
27
+ http.callback {
28
+ http.response_header.status.should == 200
29
+
30
+ # The test proxy server gives the requested uri back in this header
31
+ http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/?q=test'
32
+ http.response_header['X_THE_REQUESTED_URI'].should_not == '/?q=test'
33
+ http.response.should match('test')
34
+ EventMachine.stop
35
+ }
36
+ }
37
+ end
38
+
39
+ it "should include query parameters specified in the options" do
40
+ EventMachine.run {
41
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/', proxy).get :query => { 'q' => 'test' }
42
+
43
+ http.errback { failed(http) }
44
+ http.callback {
45
+ http.response_header.status.should == 200
46
+ http.response.should match('test')
47
+ EventMachine.stop
48
+ }
49
+ }
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,114 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::HttpRequest do
4
+
5
+ module EmptyMiddleware; end
6
+
7
+ class GlobalMiddleware
8
+ def self.response(resp)
9
+ resp.response_header['X-Global'] = 'middleware'
10
+ end
11
+ end
12
+
13
+ it "should accept middleware" do
14
+ EventMachine.run {
15
+ lambda {
16
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
17
+ conn.use ResponseMiddleware
18
+ conn.use EmptyMiddleware
19
+
20
+ EM.stop
21
+ }.should_not raise_error
22
+ }
23
+ end
24
+
25
+ context "request" do
26
+ class ResponseMiddleware
27
+ def self.response(resp)
28
+ resp.response_header['X-Header'] = 'middleware'
29
+ resp.response = 'Hello, Middleware!'
30
+ end
31
+ end
32
+
33
+
34
+ it "should execute response middleware before user callbacks" do
35
+ EventMachine.run {
36
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
37
+ conn.use ResponseMiddleware
38
+
39
+ req = conn.get
40
+ req.callback {
41
+ req.response_header['X-Header'].should match('middleware')
42
+ req.response.should match('Hello, Middleware!')
43
+ EM.stop
44
+ }
45
+ }
46
+ end
47
+
48
+ it "should execute global response middleware before user callbacks" do
49
+ EventMachine.run {
50
+ EM::HttpRequest.use GlobalMiddleware
51
+
52
+ conn = EM::HttpRequest.new('http://127.0.0.1:8090')
53
+
54
+ req = conn.get
55
+ req.callback {
56
+ req.response_header['X-Global'].should match('middleware')
57
+ EM.stop
58
+ }
59
+ }
60
+ end
61
+ end
62
+
63
+ context "request" do
64
+ class RequestMiddleware
65
+ def self.request(head, body)
66
+ head['X-Middleware'] = 'middleware' # insert new header
67
+ body += ' modified' # modify post body
68
+
69
+ [head, body]
70
+ end
71
+ end
72
+
73
+ it "should execute request middleware before dispatching request" do
74
+ EventMachine.run {
75
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/')
76
+ conn.use RequestMiddleware
77
+
78
+ req = conn.post :body => "data"
79
+ req.callback {
80
+ req.response_header.status.should == 200
81
+ req.response.should match(/data modified/)
82
+ EventMachine.stop
83
+ }
84
+ }
85
+ end
86
+ end
87
+
88
+ context "jsonify" do
89
+ class JSONify
90
+ def self.request(head, body)
91
+ [head, Yajl::Encoder.encode(body)]
92
+ end
93
+
94
+ def self.response(resp)
95
+ resp.response = Yajl::Parser.parse(resp.response)
96
+ end
97
+ end
98
+
99
+ it "should use middleware to JSON encode and JSON decode the body" do
100
+ EventMachine.run {
101
+ conn = EventMachine::HttpRequest.new('http://127.0.0.1:8090/')
102
+ conn.use JSONify
103
+
104
+ req = conn.post :body => {:ruby => :hash}
105
+ req.callback {
106
+ req.response_header.status.should == 200
107
+ req.response.should == {"ruby" => "hash"}
108
+ EventMachine.stop
109
+ }
110
+ }
111
+ end
112
+ end
113
+
114
+ end
data/spec/multi_spec.rb CHANGED
@@ -10,17 +10,13 @@ describe EventMachine::MultiRequest do
10
10
  multi = EventMachine::MultiRequest.new
11
11
 
12
12
  # add multiple requests to the multi-handler
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:8083/').get(:timeout => 1))
13
+ multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get(:query => {:q => 'test'}))
14
+ multi.add(EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get)
15
15
 
16
16
  multi.callback {
17
- # verify successful request
18
- multi.responses[:succeeded].size.should == 1
19
- multi.responses[:succeeded].first.response.should match(/test/)
20
-
21
- # verify invalid requests
22
- multi.responses[:failed].size.should == 1
23
- multi.responses[:failed].first.response_header.status.should == 0
17
+ multi.responses[:succeeded].size.should == 2
18
+ multi.responses[:succeeded][0].response.should match(/test|Hello/)
19
+ multi.responses[:succeeded][1].response.should match(/test|Hello/)
24
20
 
25
21
  EventMachine.stop
26
22
  }
@@ -29,40 +25,17 @@ describe EventMachine::MultiRequest do
29
25
 
30
26
  it "should accept multiple open connections and return once all of them are complete" do
31
27
  EventMachine.run {
32
- http1 = EventMachine::HttpRequest.new('http://127.0.0.1:8080/').get(:query => {:q => 'test'})
33
- http2 = EventMachine::HttpRequest.new('http://0.0.0.0:8083/').get(:timeout => 1)
28
+ http1 = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get(:query => {:q => 'test'})
29
+ http2 = EventMachine::HttpRequest.new('http://127.0.0.1:8090/').get
34
30
 
35
31
  multi = EventMachine::MultiRequest.new([http1, http2]) do
36
- multi.responses[:succeeded].size.should == 1
37
- multi.responses[:succeeded].first.response.should match(/test/)
38
-
39
- multi.responses[:failed].size.should == 1
40
- multi.responses[:failed].first.response_header.status.should == 0
32
+ multi.responses[:succeeded].size.should == 2
33
+ multi.responses[:succeeded][0].response.should match(/test|Hello/)
34
+ multi.responses[:succeeded][1].response.should match(/test|Hello/)
41
35
 
42
36
  EventMachine.stop
43
37
  end
44
38
  }
45
39
  end
46
40
 
47
- it "should handle multiple mock requests" do
48
- EventMachine::MockHttpRequest.register_file('http://127.0.0.1:8080/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
49
- EventMachine::MockHttpRequest.register_file('http://0.0.0.0:8083/', :get, {}, File.join(File.dirname(__FILE__), 'fixtures', 'google.ca'))
50
-
51
- EventMachine.run {
52
-
53
- # create an instance of multi-request handler, and the requests themselves
54
- multi = EventMachine::MultiRequest.new
55
-
56
- # add multiple requests to the multi-handler
57
- multi.add(EventMachine::MockHttpRequest.new('http://127.0.0.1:8080/').get)
58
- multi.add(EventMachine::MockHttpRequest.new('http://0.0.0.0:8083/').get)
59
-
60
- multi.callback {
61
- # verify successful request
62
- multi.responses[:succeeded].size.should == 2
63
-
64
- EventMachine.stop
65
- }
66
- }
67
- end
68
- end
41
+ end