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/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  Makefile
4
4
  mkmf.log
5
5
  Gemfile.lock
6
+ misc
data/Changelog.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.0.beta.1 / 2011-02-20 - The big rewrite
4
+
5
+ - Switched parser from Ragel to http_parser.rb
6
+ - Removed em_buffer C extension
7
+ - Added support for HTTP keepalive
8
+ - Added support for HTTP pipelining
9
+ - ~60% performance improvement across the board: less GC time!
10
+ - Refactored & split all tests
11
+ - Basic 100-Continue handling on POST/PUT
12
+
3
13
  ## 0.3.0 / 2011-01-15
4
14
 
5
15
  - IMPORTANT: default to non-persistent connections (timeout => 0 now requires :keepalive => true)
data/README.md CHANGED
@@ -1,175 +1,58 @@
1
- EM-HTTP-Request
2
- ===============
1
+ # EM-HTTP-Request
3
2
 
4
- Asynchronous HTTP client for Ruby, based on EventMachine runtime.
3
+ Async (EventMachine) HTTP client, with support for:
5
4
 
6
- - Ragel HTTP parser for speed & performance
7
- - Simple interface for single & parallel requests via deferred callbacks
5
+ - Asynchronous HTTP API for single & parallel request execution
6
+ - Keep-Alive and HTTP pipelining support
7
+ - Auto-follow 3xx redirects with max depth
8
8
  - Automatic gzip & deflate decoding
9
- - Basic-Auth & OAuth support
10
- - Custom timeout support
11
- - Stream response processing
12
- - Proxy support (with SSL Tunneling): CONNECT, direct & SOCKS5
13
- - Auto-follow 3xx redirects with custom max depth
14
- - Bi-directional communication with web-socket services
15
- - [Native mocking support](http://wiki.github.com/igrigorik/em-http-request/mocking-httprequest) and through [Webmock](http://github.com/bblimke/webmock)
9
+ - Streaming response processing
10
+ - Streaming file uploads
11
+ - HTTP proxy and SOCKS5 support
12
+ - Basic Auth & OAuth
13
+ - Connection-level & Global middleware support
14
+ - Ryan Dahl's HTTP parser via [http_parser.rb](https://github.com/tmm1/http_parser.rb)
15
+ - Works wherever EventMachine runs
16
16
 
17
- Getting started
18
- ---------------
17
+ ## Getting started
19
18
 
20
- gem install em-http-request
21
- irb:0> require 'em-http'
19
+ gem install em-http-request
22
20
 
23
- Or checkout [screencast / demo](http://everburning.com/news/eventmachine-screencast-em-http-request/) of using EM-HTTP-Request.
21
+ - Introductory [screencast](http://everburning.com/news/eventmachine-screencast-em-http-request/)
22
+ - [Issuing GET/POST/etc requests](https://github.com/igrigorik/em-http-request/wiki/Issuing-Requests)
23
+ - [Issuing parallel requests with Multi interface](https://github.com/igrigorik/em-http-request/wiki/Parallel-Requests)
24
+ - [Handling Redirects & Timeouts](https://github.com/igrigorik/em-http-request/wiki/Redirects-and-Timeouts)
25
+ - [Keep-Alive and HTTP Pipelining](https://github.com/igrigorik/em-http-request/wiki/Keep-Alive-and-HTTP-Pipelining)
26
+ - [Stream processing responses & uploads](https://github.com/igrigorik/em-http-request/wiki/Streaming)
27
+ - [Issuing requests through HTTP & SOCKS5 proxies](https://github.com/igrigorik/em-http-request/wiki/Proxy)
28
+ - [Basic Auth & OAuth](https://github.com/igrigorik/em-http-request/wiki/Basic-Auth-and-OAuth)
29
+ - [GZIP & Deflate decoding](https://github.com/igrigorik/em-http-request/wiki/Compression)
30
+ - [EM-HTTP Middleware](https://github.com/igrigorik/em-http-request/wiki/Middleware)
24
31
 
25
- Libraries & Applications using em-http
26
- --------------------------------------
32
+ ## Extensions
27
33
 
28
- - [chirpstream](http://github.com/joshbuddy/chirpstream) - EM client for Twitters Chirpstream API
29
- - [RDaneel](http://github.com/hasmanydevelopers/RDaneel) - Ruby crawler which respects robots.txt
30
- - [rsolr-async](http://github.com/mwmitchell/rsolr-async) - An asynchronus connection adapter for RSolr
31
- - [PubSubHubbub](http://github.com/igrigorik/PubSubHubbub) - Asynchronous PubSubHubbub ruby client
32
- - [Firering](http://github.com/EmmanuelOga/firering) - Eventmachine powered Campfire API
33
- - and many others.. drop me a link if you want yours included!
34
-
35
- Simple client example
36
- ---------------------
37
-
38
- EventMachine.run {
39
- http = EventMachine::HttpRequest.new('http://127.0.0.1/').get :query => {'keyname' => 'value'}, :timeout => 10
40
-
41
- http.callback {
42
- p http.response_header.status
43
- p http.response_header
44
- p http.response
45
-
46
- EventMachine.stop
47
- }
48
- }
49
-
50
- Multi-request example
51
- ---------------------
52
-
53
- Fire and wait for multiple requests to complete via the MultiRequest interface.
54
-
55
- EventMachine.run {
56
- multi = EventMachine::MultiRequest.new
57
-
58
- # add multiple requests to the multi-handler
59
- multi.add(EventMachine::HttpRequest.new('http://www.google.com/').get)
60
- multi.add(EventMachine::HttpRequest.new('http://www.yahoo.com/').get)
61
-
62
- multi.callback {
63
- p multi.responses[:succeeded]
64
- p multi.responses[:failed]
65
-
66
- EventMachine.stop
67
- }
68
- }
69
-
70
- Basic-Auth example
71
- ------------------
72
-
73
- Full basic author support. For OAuth, check examples/oauth-tweet.rb file.
74
-
75
- EventMachine.run {
76
- http = EventMachine::HttpRequest.new('http://www.website.com/').get :head => {'authorization' => ['user', 'pass']}
77
-
78
- http.errback { failed }
79
- http.callback {
80
- p http.response_header
81
- EventMachine.stop
82
- }
83
- }
84
-
85
-
86
- POSTing data example
87
- --------------------
34
+ Several higher-order Ruby projects have incorporated em-http and other Ruby HTTP clients:
88
35
 
89
- For multi-part uploads, please see [this gist](https://gist.github.com/778639).
36
+ - [EM-Synchrony](https://github.com/igrigorik/em-synchrony) - Collection of convenience classes and primitives to help untangle evented code (Ruby 1.9 + Fibers).
37
+ - [Rack-Client](https://github.com/halorgium/rack-client) - Use Rack API for server, test, and client side. Supports Rack middleware!
38
+ - [Example in action](https://gist.github.com/802391)
39
+ - [Faraday](https://github.com/technoweenie/faraday) - Modular HTTP client library using middleware heavily inspired by Rack.
40
+ - [Example in action](https://gist.github.com/802395)
90
41
 
91
- EventMachine.run {
92
- http1 = EventMachine::HttpRequest.new('http://www.website.com/').post :body => {"key1" => 1, "key2" => [2,3]}
93
- http2 = EventMachine::HttpRequest.new('http://www.website.com/').post :body => "some data"
42
+ ## Testing
94
43
 
95
- # ...
96
- }
44
+ - [WebMock](https://github.com/bblimke/webmock) - Library for stubbing and setting expectations on HTTP requests in Ruby.
45
+ - Example of [using WebMock, VCR & EM-HTTP](https://gist.github.com/802553)
97
46
 
98
- Streaming body processing
99
- -------------------------
47
+ ## Other libraries & applications using EM-HTTP
100
48
 
101
- Allows you to consume an HTTP stream of content in real-time. Each time a new piece of content is pushed
102
- to the client, it is passed to the stream callback for you to operate on.
103
-
104
- EventMachine.run {
105
- http = EventMachine::HttpRequest.new('http://www.website.com/').get
106
- http.stream { |chunk| print chunk }
107
- }
108
-
109
- Streaming files from disk
110
- -------------------------
111
- Allows you to efficiently stream a (large) file from disk via EventMachine's FileStream interface.
112
-
113
- EventMachine.run {
114
- http = EventMachine::HttpRequest.new('http://www.website.com/').post :file => 'largefile.txt'
115
- http.callback { |chunk| puts "Upload finished!" }
116
- }
117
-
118
- Proxy example
119
- -------------
120
- Full transparent proxy support with support for SSL tunneling.
121
-
122
- EventMachine.run {
123
- http = EventMachine::HttpRequest.new('http://www.website.com/').get :proxy => {
124
- :host => 'www.myproxy.com',
125
- :port => 8080,
126
- :authorization => ['username', 'password'] # authorization is optional
127
- }
128
-
129
- SOCKS5 Proxy example
130
- -------------
131
- Tunnel your requests via connect via SOCKS5 proxies (ssh -D port somehost).
132
-
133
- EventMachine.run {
134
- http = EventMachine::HttpRequest.new('http://www.website.com/').get :proxy => {
135
- :host => 'www.myproxy.com',
136
- :port => 8080,
137
- :type => :socks
138
- }
139
-
140
- Auto-follow 3xx redirects
141
- -------------------------
142
-
143
- Specify the max depth of redirects to follow, default is 0.
144
-
145
- EventMachine.run {
146
- http = EventMachine::HttpRequest.new('http://www.google.com/').get :redirects => 1
147
- http.callback { p http.last_effective_url }
148
- }
149
-
150
- WebSocket example
151
- -----------------
152
-
153
- [Bi-directional communication with WebSockets](http://www.igvita.com/2009/12/22/ruby-websockets-tcp-for-the-browser/): simply pass in a ws:// resource and the client will negotiate the connection upgrade for you. On successful handshake the callback is invoked, and any incoming messages will be passed to the stream callback. The client can also send data to the server at will by calling the "send" method!
154
-
155
- EventMachine.run {
156
- http = EventMachine::HttpRequest.new("ws://yourservice.com/websocket").get :timeout => 0
157
-
158
- http.errback { puts "oops" }
159
- http.callback {
160
- puts "WebSocket connected!"
161
- http.send("Hello client")
162
- }
163
-
164
- http.stream { |msg|
165
- puts "Recieved: #{msg}"
166
- http.send "Pong: #{msg}"
167
- }
168
-
169
- http.disconnect { puts "oops, dropped connection?" }
170
- }
49
+ - [chirpstream](http://github.com/joshbuddy/chirpstream) - EM client for Twitters Chirpstream API
50
+ - [rsolr-async](http://github.com/mwmitchell/rsolr-async) - An asynchronus connection adapter for RSolr
51
+ - [PubSubHubbub](http://github.com/igrigorik/PubSubHubbub) - Asynchronous PubSubHubbub ruby client
52
+ - [Firering](http://github.com/EmmanuelOga/firering) - Eventmachine powered Campfire API
53
+ - [RDaneel](http://github.com/hasmanydevelopers/RDaneel) - Ruby crawler which respects robots.txt
54
+ - and many others.. drop me a link if you want yours included!
171
55
 
172
- License
173
- -------
56
+ ### License
174
57
 
175
- (MIT License) - Copyright (c) 2011 Ilya Grigorik
58
+ (MIT License) - Copyright (c) 2011 Ilya Grigorik
data/Rakefile CHANGED
@@ -1,80 +1,9 @@
1
1
  require 'bundler'
2
+ Bundler::GemHelper.install_tasks
2
3
 
3
- Bundler.setup
4
- Bundler.require :default, :development
5
-
6
- require 'rake'
7
- require 'rake/clean'
8
- require 'rake/gempackagetask'
9
4
  require 'rspec/core/rake_task'
10
5
 
11
- require 'fileutils'
12
- include FileUtils
13
-
14
- # copied from EventMachine.
15
- MAKE = ENV['MAKE'] || if RUBY_PLATFORM =~ /mswin/ # mingw uses make.
16
- 'nmake'
17
- else
18
- 'make'
19
- end
20
-
21
- # Default Rake task is compile
22
- task :default => :compile
23
-
24
- # Rebuild parser Ragel
25
- task :ragel do
26
- Dir.chdir "ext/http11_client" do
27
- target = "http11_parser.c"
28
- File.unlink target if File.exist? target
29
- sh "ragel http11_parser.rl | rlgen-cd -G2 -o #{target}"
30
- raise "Failed to build C source" unless File.exist? target
31
- end
32
- end
33
-
34
6
  desc "Run all RSpec tests"
35
7
  RSpec::Core::RakeTask.new(:spec)
36
8
 
37
- def make(makedir)
38
- Dir.chdir(makedir) { sh MAKE }
39
- end
40
-
41
- def extconf(dir)
42
- Dir.chdir(dir) { ruby "extconf.rb" }
43
- end
44
-
45
- def setup_extension(dir, extension)
46
- ext = "ext/#{dir}"
47
- ext_so = "#{ext}/#{extension}.#{Config::MAKEFILE_CONFIG['DLEXT']}"
48
- ext_files = FileList[
49
- "#{ext}/*.c",
50
- "#{ext}/*.h",
51
- "#{ext}/extconf.rb",
52
- "#{ext}/Makefile",
53
- "lib"
54
- ]
55
-
56
- task "lib" do
57
- directory "lib"
58
- end
59
-
60
- desc "Builds just the #{extension} extension"
61
-
62
- mf = (extension + '_makefile').to_sym
63
-
64
- task mf do |t|
65
- extconf "#{ext}"
66
- end
67
-
68
- task extension.to_sym => [mf] do
69
- make "#{ext}"
70
- cp ext_so, "lib"
71
- end
72
- end
73
-
74
- setup_extension("buffer", "em_buffer")
75
- setup_extension("http11_client", "http11_client")
76
-
77
- task :compile => [:em_buffer, :http11_client]
78
-
79
- CLEAN.include ['build/*', '**/*.o', '**/*.so', '**/*.a', '**/*.log', 'pkg']
80
- CLEAN.include ['ext/buffer/Makefile', 'lib/em_buffer.*', 'lib/http11_client.*']
9
+ task :default => :spec
@@ -5,6 +5,7 @@ require "em-http/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "em-http-request"
7
7
  s.version = EventMachine::HttpRequest::VERSION
8
+
8
9
  s.platform = Gem::Platform::RUBY
9
10
  s.authors = ["Ilya Grigorik"]
10
11
  s.email = ["ilya@igvita.com"]
@@ -13,20 +14,19 @@ Gem::Specification.new do |s|
13
14
  s.description = s.summary
14
15
  s.rubyforge_project = "em-http-request"
15
16
 
16
- s.add_dependency "eventmachine", ">= 0.12.9"
17
- s.add_dependency "addressable", ">= 2.0.0"
18
- s.add_dependency "escape_utils"
17
+ s.add_dependency "eventmachine"
18
+ s.add_dependency "addressable", ">= 2.2.3"
19
+ s.add_dependency "http_parser.rb", ">= 0.5.1"
20
+ s.add_dependency "em-socksify"
19
21
 
20
22
  s.add_development_dependency "rspec"
21
23
  s.add_development_dependency "rake"
22
- s.add_development_dependency "em-websocket"
23
24
  s.add_development_dependency "rack"
25
+ s.add_development_dependency "yajl-ruby"
24
26
  s.add_development_dependency "mongrel", "~> 1.2.0.pre2"
25
27
 
26
- s.extensions = ["ext/buffer/extconf.rb", "ext/http11_client/extconf.rb"]
27
-
28
28
  s.files = `git ls-files`.split("\n")
29
29
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
30
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
31
  s.require_paths = ["lib"]
32
- end
32
+ end
data/examples/fetch.rb CHANGED
@@ -1,30 +1,30 @@
1
- require 'rubygems'
2
- require 'eventmachine'
3
- require '../lib/em-http'
4
-
5
- urls = ARGV
6
- if urls.size < 1
7
- puts "Usage: #{$0} <url> <url> <...>"
8
- exit
9
- end
10
-
11
- pending = urls.size
12
-
13
- EM.run do
14
- urls.each do |url|
15
- http = EM::HttpRequest.new(url).get
16
- http.callback {
17
- puts "#{url}\n#{http.response_header.status} - #{http.response.length} bytes\n"
18
- puts http.response
19
-
20
- pending -= 1
21
- EM.stop if pending < 1
22
- }
23
- http.errback {
24
- puts "#{url}\n" + http.error
25
-
26
- pending -= 1
27
- EM.stop if pending < 1
28
- }
29
- end
30
- end
1
+ require 'rubygems'
2
+ require 'eventmachine'
3
+ require '../lib/em-http'
4
+
5
+ urls = ARGV
6
+ if urls.size < 1
7
+ puts "Usage: #{$0} <url> <url> <...>"
8
+ exit
9
+ end
10
+
11
+ pending = urls.size
12
+
13
+ EM.run do
14
+ urls.each do |url|
15
+ http = EM::HttpRequest.new(url).get
16
+ http.callback {
17
+ puts "#{url}\n#{http.response_header.status} - #{http.response.length} bytes\n"
18
+ puts http.response
19
+
20
+ pending -= 1
21
+ EM.stop if pending < 1
22
+ }
23
+ http.errback {
24
+ puts "#{url}\n" + http.error
25
+
26
+ pending -= 1
27
+ EM.stop if pending < 1
28
+ }
29
+ end
30
+ end
@@ -1,39 +1,39 @@
1
- require 'eventmachine'
2
- require 'em-http'
3
- require 'fiber'
4
-
5
- # Using Fibers in Ruby 1.9 to simulate blocking IO / IO scheduling
6
- # while using the async EventMachine API's
7
-
8
- def async_fetch(url)
9
- f = Fiber.current
10
- http = EventMachine::HttpRequest.new(url).get :timeout => 10
11
-
12
- http.callback { f.resume(http) }
13
- http.errback { f.resume(http) }
14
-
15
- return Fiber.yield
16
- end
17
-
18
- EventMachine.run do
19
- Fiber.new{
20
-
21
- puts "Setting up HTTP request #1"
22
- data = async_fetch('http://www.google.com/')
23
- puts "Fetched page #1: #{data.response_header.status}"
24
-
25
- puts "Setting up HTTP request #2"
26
- data = async_fetch('http://www.yahoo.com/')
27
- puts "Fetched page #2: #{data.response_header.status}"
28
-
29
- EventMachine.stop
30
- }.resume
31
- end
32
-
33
- puts "Done"
34
-
35
- # Setting up HTTP request #1
36
- # Fetched page #1: 302
37
- # Setting up HTTP request #2
38
- # Fetched page #2: 200
1
+ require 'eventmachine'
2
+ require 'em-http'
3
+ require 'fiber'
4
+
5
+ # Using Fibers in Ruby 1.9 to simulate blocking IO / IO scheduling
6
+ # while using the async EventMachine API's
7
+
8
+ def async_fetch(url)
9
+ f = Fiber.current
10
+ http = EventMachine::HttpRequest.new(url).get :timeout => 10
11
+
12
+ http.callback { f.resume(http) }
13
+ http.errback { f.resume(http) }
14
+
15
+ return Fiber.yield
16
+ end
17
+
18
+ EventMachine.run do
19
+ Fiber.new{
20
+
21
+ puts "Setting up HTTP request #1"
22
+ data = async_fetch('http://www.google.com/')
23
+ puts "Fetched page #1: #{data.response_header.status}"
24
+
25
+ puts "Setting up HTTP request #2"
26
+ data = async_fetch('http://www.yahoo.com/')
27
+ puts "Fetched page #2: #{data.response_header.status}"
28
+
29
+ EventMachine.stop
30
+ }.resume
31
+ end
32
+
33
+ puts "Done"
34
+
35
+ # Setting up HTTP request #1
36
+ # Fetched page #1: 302
37
+ # Setting up HTTP request #2
38
+ # Fetched page #2: 200
39
39
  # Done