http 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of http might be problematic. Click here for more details.

@@ -1,5 +1,5 @@
1
1
  rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
- - rbx-2.0
4
+ - rbx
5
5
  - jruby
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ 0.1.0
2
+ -----
3
+ * Testing against WEBrick
4
+ * Curb compatibility (require 'http/compat/curb')
5
+
1
6
  0.0.1
2
7
  -----
3
8
  * Initial half-baked release
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  Http
2
2
  ====
3
+ [![Build Status](http://travis-ci.org/tarcieri/http.png)](http://travis-ci.org/tarcieri/http)
3
4
 
4
5
  Ruby has always been this extremely web-focused language, and yet despite the
5
6
  selection of HTTP libraries out there, I always find myself falling back on
@@ -17,19 +18,17 @@ Making Requests
17
18
 
18
19
  Let's start with getting things:
19
20
 
20
- Http.get "http://www.google.com"
21
+ ```ruby
22
+ Http.get "http://www.google.com"
23
+ ```
21
24
 
22
25
  That's it! The result is the response body.
23
26
 
24
- Don't like "Http"? No worries, this works as well:
25
-
26
- HTTP.get "http://www.google.com"
27
-
28
- After all, There Is More Than One Way To Do It!
29
-
30
27
  Making POST requests is simple too. Want to POST a form?
31
28
 
32
- Http.post "http://example.com/resource", :form => {:foo => "42"}
29
+ ```ruby
30
+ Http.post "http://example.com/resource", :form => {:foo => "42"}
31
+ ```
33
32
 
34
33
  It's easy!
35
34
 
@@ -40,7 +39,9 @@ The Http library uses the concept of chaining to simplify requests. Let's say
40
39
  you want to get the latest commit of this library from Github in JSON format.
41
40
  One way we could do this is by tacking a filename on the end of the URL:
42
41
 
43
- Http.get "https://github.com/tarcieri/http/commit/HEAD.json"
42
+ ```ruby
43
+ Http.get "https://github.com/tarcieri/http/commit/HEAD.json"
44
+ ```
44
45
 
45
46
  The Github API happens to support this approach, but really this is a bit of a
46
47
  hack that makes it easy for people typing URLs into the address bars of
@@ -48,8 +49,10 @@ browsers to perform the act of content negotiation. Since we have access to
48
49
  the full, raw power of HTTP, we can perform content negotiation the way HTTP
49
50
  intends us to, by using the Accept header:
50
51
 
51
- Http.with_headers(:accept => 'application/json').
52
- get("https://github.com/tarcieri/http/commit/HEAD")
52
+ ```ruby
53
+ Http.with_headers(:accept => 'application/json').
54
+ get("https://github.com/tarcieri/http/commit/HEAD")
55
+ ```
53
56
 
54
57
  This requests JSON from Github. Github is smart enough to understand our
55
58
  request and returns a response with Content-Type: application/json. If you
@@ -58,8 +61,10 @@ JSON.parse, the Http library will attempt to parse the JSON response.
58
61
 
59
62
  A shorter alias exists for HTTP.with_headers:
60
63
 
61
- Http.with(:accept => 'application/json').
62
- get("https://github.com/tarcieri/http/commit/HEAD")
64
+ ```ruby
65
+ Http.with(:accept => 'application/json').
66
+ get("https://github.com/tarcieri/http/commit/HEAD")
67
+ ```
63
68
 
64
69
  Content Negotiation
65
70
  -------------------
@@ -68,11 +73,26 @@ As important a concept as content negotiation is HTTP, it sure should be easy,
68
73
  right? But usually it's not, and so we end up adding ".json" onto the ends of
69
74
  our URLs because the existing mechanisms make it too hard. It should be easy:
70
75
 
71
- Http.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
76
+ ```ruby
77
+ Http.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
78
+ ```
72
79
 
73
80
  This adds the appropriate Accept header for retrieving a JSON response for the
74
81
  given resource.
75
82
 
83
+ Curb Compatibility
84
+ ------------------
85
+
86
+ The Http gem provides partial compatibility with the Curb::Easy API. This is
87
+ great if you're transitioning to JRuby and need a drop-in API-compatible
88
+ replacement for Curb.
89
+
90
+ To use the Curb compatibility, do:
91
+
92
+ ```ruby
93
+ require 'http/compat/curb'
94
+ ```
95
+
76
96
  Contributing to Http
77
97
  --------------------
78
98
 
@@ -5,7 +5,6 @@ require 'http/mime_type'
5
5
  require 'http/parameters'
6
6
  require 'http/response'
7
7
 
8
-
9
8
  # THIS IS ENTIRELY TEMPORARY, I ASSURE YOU
10
9
  require 'net/https'
11
10
  require 'uri'
@@ -14,7 +13,3 @@ require 'uri'
14
13
  module Http
15
14
  extend Chainable
16
15
  end
17
-
18
- # TIMTOWTDI!
19
- HTTP = Http
20
- HttpClient = Http::Client
@@ -7,54 +7,54 @@ module Http
7
7
  @uri = uri
8
8
  else
9
9
  # Why the FUCK can't Net::HTTP do this?
10
- @uri = URI(uri)
10
+ @uri = URI(uri.to_s)
11
11
  end
12
12
 
13
13
  @options = {:response => :object}.merge(options)
14
14
  end
15
15
 
16
16
  # Request a get sans response body
17
- def head(uri, options = {})
17
+ def head(options = {})
18
18
  request :head, options
19
19
  end
20
20
 
21
21
  # Get a resource
22
- def get(uri, options = {})
22
+ def get(options = {})
23
23
  request :get, options
24
24
  end
25
25
 
26
26
  # Post to a resource
27
- def post(uri, options = {})
27
+ def post(options = {})
28
28
  request :post, options
29
29
  end
30
30
 
31
31
  # Put to a resource
32
- def put(uri, options = {})
32
+ def put(options = {})
33
33
  request :put, options
34
34
  end
35
35
 
36
36
  # Delete a resource
37
- def delete(uri, options = {})
37
+ def delete(options = {})
38
38
  request :delete, options
39
39
  end
40
40
 
41
41
  # Echo the request back to the client
42
- def trace(uri, options = {})
42
+ def trace(options = {})
43
43
  request :trace, options
44
44
  end
45
45
 
46
46
  # Return the methods supported on the given URI
47
- def options(uri, options = {})
47
+ def options(options = {})
48
48
  request :options, options
49
49
  end
50
50
 
51
51
  # Convert to a transparent TCP/IP tunnel
52
- def connect(uri, options = {})
52
+ def connect(options = {})
53
53
  request :connect, options
54
54
  end
55
55
 
56
56
  # Apply partial modifications to a resource
57
- def patch(uri, options = {})
57
+ def patch(options = {})
58
58
  request :patch, options
59
59
  end
60
60
 
@@ -0,0 +1,86 @@
1
+ require 'http'
2
+
3
+ # Compatibility with the Curb gem
4
+ module Curl
5
+ module Err
6
+ class CurlError < RuntimeError; end
7
+ class ConnectionFailedError < CurlError; end
8
+ class HostResolutionError < CurlError; end
9
+ end
10
+
11
+ class Easy
12
+ attr_accessor :headers, :encoding
13
+ attr_reader :response_code, :body_str
14
+
15
+ def self.http_post(url, request_body = nil)
16
+ Easy.new(url).tap { |e| e.http_post(request_body) }
17
+ end
18
+
19
+ def self.http_get(url, request_body = nil)
20
+ Easy.new(url).tap { |e| e.http_get(request_body) }
21
+ end
22
+
23
+ def initialize(url = nil, method = nil, request_body = nil, headers = {})
24
+ @url = url
25
+ @method = method
26
+ @request_body = request_body
27
+ @headers = headers
28
+ @response_code = @body_str = nil
29
+ end
30
+
31
+ def perform
32
+ client = Http::Client.new @url, :headers => @headers
33
+ response = client.send @method
34
+ @response_code, @body_str = response.code, response.body
35
+ true
36
+ rescue SocketError => ex
37
+ if ex.message['getaddrinfo'] || ex.message['ame or service not known']
38
+ raise Err::HostResolutionError, ex.message
39
+ else
40
+ raise Err::ConnectionFailedError, ex.message
41
+ end
42
+ end
43
+
44
+ def http_get(request_body = nil)
45
+ @method, @request_body = :get, request_body
46
+ perform
47
+ end
48
+
49
+ def http_put(request_body = nil)
50
+ @method, @request_body = :put, request_body
51
+ perform
52
+ end
53
+
54
+ def http_post(request_body = nil)
55
+ @method, @request_body = :post, request_body
56
+ perform
57
+ end
58
+
59
+ def http_delete
60
+ @method = :delete
61
+ perform
62
+ end
63
+ end
64
+
65
+ class Multi
66
+ def initialize
67
+ @clients = []
68
+ @done = false
69
+ end
70
+
71
+ def add(client)
72
+ @clients << client
73
+ end
74
+
75
+
76
+ def perform
77
+ return if @done
78
+
79
+ @clients.map do |client|
80
+ Thread.new { client.perform }
81
+ end.each(&:join)
82
+
83
+ @done = true
84
+ end
85
+ end
86
+ end
@@ -1,3 +1,3 @@
1
1
  module Http
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ require 'http/compat/curb'
4
+
5
+ describe Curl do
6
+ let(:test_endpoint) { "http://127.0.0.1:#{TEST_SERVER_PORT}/" }
7
+
8
+ describe Curl::Easy do
9
+ it "gets resources" do
10
+ response = Curl::Easy.http_get test_endpoint
11
+ response.body_str.should match(/<!doctype html>/)
12
+ end
13
+
14
+ context :errors do
15
+ it "raises Curl::Err::HostResolutionError if asked to connect to a nonexistent domain" do
16
+ expect {
17
+ Curl::Easy.http_get "http://totallynonexistentdomain.com"
18
+ }.to raise_exception(Curl::Err::HostResolutionError)
19
+ end
20
+ end
21
+ end
22
+
23
+ describe Curl::Multi do
24
+ it "gets resources" do
25
+ requests = [test_endpoint]
26
+ responses = []
27
+
28
+ multi = Curl::Multi.new
29
+
30
+ requests.each do |url|
31
+ response = Curl::Easy.new url, :get
32
+ multi.add response
33
+ responses << response
34
+ end
35
+
36
+ multi.perform
37
+ responses.first.body_str.should match(/<!doctype html>/)
38
+ end
39
+ end
40
+ end
@@ -2,35 +2,32 @@ require 'spec_helper'
2
2
  require 'json'
3
3
 
4
4
  describe Http do
5
+ let(:test_endpoint) { "http://127.0.0.1:#{TEST_SERVER_PORT}/" }
6
+
5
7
  context "getting resources" do
6
8
  it "should be easy" do
7
- # Fuck it, we'll do it live! (Testing against WEBRick or something coming soon)
8
- response = Http.get "http://www.google.com"
9
+ response = Http.get test_endpoint
9
10
  response.should match(/<!doctype html>/)
10
11
  end
11
12
 
12
13
  context "with headers" do
13
14
  it "should be easy" do
14
- response = Http.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
15
-
16
- # Congratulations first committer, your prize is to break the build!
17
- response['commit']['author']['name'].should == "Tony Arcieri"
15
+ response = Http.accept(:json).get test_endpoint
16
+ response['json'].should be_true
18
17
  end
19
18
  end
20
19
  end
21
20
 
22
21
  context "posting to resources" do
23
22
  it "should be easy" do
24
- fragment = "<!doctype html><html><head><title>example</title></head></html>"
25
- response = Http.post "http://validator.w3.org/check", :form => {:fragment => fragment}
26
-
27
- response.should match(/HTML5/)
23
+ response = Http.post test_endpoint, :form => {:example => 'testing'}
24
+ response.should == "passed :)"
28
25
  end
29
26
  end
30
27
 
31
28
  context "head requests" do
32
29
  it "should be easy" do
33
- response = Http.head "http://www.google.com"
30
+ response = Http.head test_endpoint
34
31
  response.status.should == 200
35
32
  response['content-type'].should match(/html/)
36
33
  end
@@ -1,2 +1,3 @@
1
1
  $:.push File.expand_path("../lib")
2
- require 'http'
2
+ require 'http'
3
+ require 'support/mock_server'
@@ -0,0 +1,59 @@
1
+ require 'webrick'
2
+
3
+ TEST_SERVER_PORT = 65432
4
+
5
+ class MockService < WEBrick::HTTPServlet::AbstractServlet
6
+ class << self; attr_accessor :post_handler; end
7
+
8
+ def do_GET(request, response)
9
+ case request.path
10
+ when "/"
11
+ response.status = 200
12
+
13
+ case request['Accept']
14
+ when 'application/json'
15
+ response['Content-Type'] = 'application/json'
16
+ response.body = '{"json": true}'
17
+ else
18
+ response['Content-Type'] = 'text/html'
19
+ response.body = "<!doctype html>"
20
+ end
21
+ else
22
+ response.status = 404
23
+ end
24
+ end
25
+
26
+ def do_POST(request, response)
27
+ case request.path
28
+ when "/"
29
+ if request.query['example'] == 'testing'
30
+ response.status = 200
31
+ response.body = "passed :)"
32
+ else
33
+ response.status = 400
34
+ response.vody = "invalid! >:E"
35
+ end
36
+ else
37
+ response.status = 404
38
+ end
39
+ end
40
+
41
+ def do_HEAD(request, response)
42
+ case request.path
43
+ when "/"
44
+ response.status = 200
45
+ response['Content-Type'] = 'text/html'
46
+ else
47
+ response.status = 404
48
+ end
49
+ end
50
+ end
51
+
52
+ MockServer = WEBrick::HTTPServer.new(:Port => TEST_SERVER_PORT, :AccessLog => [])
53
+ MockServer.mount "/", MockService
54
+
55
+ Thread.new { MockServer.start }
56
+ trap("INT") { MockServer.shutdown; exit }
57
+
58
+ # hax: wait for webrick to start
59
+ sleep 0.1
metadata CHANGED
@@ -1,58 +1,78 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: http
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Tony Arcieri
9
14
  - Carl Lerche
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
- date: 2011-11-30 00:00:00.000000000 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
18
+
19
+ date: 2012-01-26 00:00:00 -08:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
16
23
  name: rake
17
- requirement: &70233139252940 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
18
26
  none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
23
34
  type: :development
24
- prerelease: false
25
- version_requirements: *70233139252940
26
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
27
37
  name: rspec
28
- requirement: &70233139252380 !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
29
40
  none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 23
45
+ segments:
46
+ - 2
47
+ - 6
48
+ - 0
33
49
  version: 2.6.0
34
50
  type: :development
35
- prerelease: false
36
- version_requirements: *70233139252380
37
- - !ruby/object:Gem::Dependency
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
38
53
  name: json
39
- requirement: &70233139251960 !ruby/object:Gem::Requirement
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
40
56
  none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: '0'
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
45
64
  type: :development
46
- prerelease: false
47
- version_requirements: *70233139251960
48
- description: HTTP so awesome it will lure Catherine Zeta Jones into your unicorn petting
49
- zoo
50
- email:
65
+ version_requirements: *id003
66
+ description: HTTP so awesome it will lure Catherine Zeta Jones into your unicorn petting zoo
67
+ email:
51
68
  - tony.arcieri@gmail.com
52
69
  executables: []
70
+
53
71
  extensions: []
72
+
54
73
  extra_rdoc_files: []
55
- files:
74
+
75
+ files:
56
76
  - .gitignore
57
77
  - .rspec
58
78
  - .travis.yml
@@ -65,6 +85,7 @@ files:
65
85
  - lib/http.rb
66
86
  - lib/http/chainable.rb
67
87
  - lib/http/client.rb
88
+ - lib/http/compat/curb.rb
68
89
  - lib/http/mime_type.rb
69
90
  - lib/http/mime_types/json.rb
70
91
  - lib/http/parameters.rb
@@ -73,33 +94,46 @@ files:
73
94
  - parser/common.rl
74
95
  - parser/http.rl
75
96
  - parser/multipart.rl
97
+ - spec/http/compat/curb_spec.rb
76
98
  - spec/http_spec.rb
77
99
  - spec/spec_helper.rb
100
+ - spec/support/mock_server.rb
101
+ has_rdoc: true
78
102
  homepage: https://github.com/tarcieri/http
79
103
  licenses: []
104
+
80
105
  post_install_message:
81
106
  rdoc_options: []
82
- require_paths:
107
+
108
+ require_paths:
83
109
  - lib
84
- required_ruby_version: !ruby/object:Gem::Requirement
110
+ required_ruby_version: !ruby/object:Gem::Requirement
85
111
  none: false
86
- requirements:
87
- - - ! '>='
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- required_rubygems_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
120
  none: false
92
- requirements:
93
- - - ! '>='
94
- - !ruby/object:Gem::Version
95
- version: '0'
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ hash: 3
125
+ segments:
126
+ - 0
127
+ version: "0"
96
128
  requirements: []
129
+
97
130
  rubyforge_project:
98
- rubygems_version: 1.8.10
131
+ rubygems_version: 1.5.2
99
132
  signing_key:
100
133
  specification_version: 3
101
134
  summary: Made entirely of Ruby (and Ragel and C and Java)
102
- test_files:
135
+ test_files:
136
+ - spec/http/compat/curb_spec.rb
103
137
  - spec/http_spec.rb
104
138
  - spec/spec_helper.rb
105
- has_rdoc:
139
+ - spec/support/mock_server.rb