http 0.5.0.pre → 0.5.0.pre2
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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/CHANGES.md +7 -6
- data/README.md +18 -31
- data/Rakefile +2 -2
- data/examples/celluloid.rb +2 -2
- data/http.gemspec +1 -1
- data/lib/http.rb +1 -14
- data/lib/http/chainable.rb +4 -4
- data/lib/http/client.rb +11 -10
- data/lib/http/header.rb +11 -0
- data/lib/http/mime_type.rb +1 -1
- data/lib/http/mime_types/json.rb +1 -1
- data/lib/http/options.rb +7 -6
- data/lib/http/request.rb +11 -3
- data/lib/http/response.rb +6 -3
- data/lib/http/response_parser.rb +2 -2
- data/lib/http/version.rb +1 -1
- data/spec/http/options/body_spec.rb +5 -5
- data/spec/http/options/callbacks_spec.rb +18 -18
- data/spec/http/options/form_spec.rb +5 -5
- data/spec/http/options/headers_spec.rb +9 -9
- data/spec/http/options/merge_spec.rb +11 -11
- data/spec/http/options/new_spec.rb +14 -14
- data/spec/http/options/proxy_spec.rb +6 -6
- data/spec/http/options/response_spec.rb +7 -7
- data/spec/http/options_spec.rb +5 -5
- data/spec/http/request_spec.rb +19 -0
- data/spec/http/request_stream_spec.rb +6 -7
- data/spec/http/response_spec.rb +12 -12
- data/spec/http_spec.rb +39 -39
- data/spec/spec_helper.rb +6 -0
- metadata +7 -7
- data/lib/http/compat/curb.rb +0 -87
- data/spec/http/compat/curb_spec.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bb4624a4979a20cd635f9c0484b2ff370d45b99
|
4
|
+
data.tar.gz: d097dd00a89069bd2bd9d19f1ecc6f1a35d4ebb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9f23c4ad1b21d5645eacde6f1aef34e830c2c1aea078b791b5ad6d1ac862a386a68794bb80898d27637a07d011192372b2c37495e02589d317a75f87c41453e
|
7
|
+
data.tar.gz: 48d4f1ffe07776e24161ac57ea8dad15c822dd1437436f6ef8f0b9f68011dfb1152f84ca1e30ebb50dc1cbf851a7ce28863b59652ffb282437dee4443e1e6ae7
|
data/.rspec
CHANGED
data/CHANGES.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
0.5.0.
|
2
|
-
|
1
|
+
0.5.0.pre2
|
2
|
+
----------
|
3
3
|
* Add query string support
|
4
|
-
* New response delegator allows
|
5
|
-
*
|
4
|
+
* New response delegator allows HTTP.get(uri).response
|
5
|
+
* HTTP::Chainable#stream provides a shorter alias for
|
6
6
|
with_response(:object)
|
7
|
-
* Better string inspect for
|
7
|
+
* Better string inspect for HTTP::Response
|
8
|
+
* Curb compatibility layer removed
|
8
9
|
|
9
10
|
0.4.0
|
10
11
|
-----
|
@@ -18,7 +19,7 @@
|
|
18
19
|
* New implementation based on tmm1's http_parser.rb instead of Net::HTTP
|
19
20
|
* Support for following redirects
|
20
21
|
* Support for request body through {:body => ...} option
|
21
|
-
*
|
22
|
+
* HTTP#with_response (through Chainable)
|
22
23
|
|
23
24
|
0.2.0
|
24
25
|
-----
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
The
|
1
|
+
The HTTP Gem*
|
2
2
|
==============
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/http.png)](http://rubygems.org/gems/http)
|
4
4
|
[![Build Status](https://secure.travis-ci.org/tarcieri/http.png?branch=master)](http://travis-ci.org/tarcieri/http)
|
@@ -9,7 +9,7 @@ The Http Gem*
|
|
9
9
|
that if we all refer to it as "The HTTP Gem". Entering that phrase into Google
|
10
10
|
actually pulls it up as #4 for me!
|
11
11
|
|
12
|
-
The
|
12
|
+
The HTTP Gem is an easy-to-use client library for making requests from Ruby. It uses
|
13
13
|
a simple method chaining system for building requests, similar to libraries
|
14
14
|
like JQuery or Python's [Requests](http://docs.python-requests.org/en/latest/).
|
15
15
|
|
@@ -40,39 +40,39 @@ Making Requests
|
|
40
40
|
Let's start with getting things:
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
>>
|
43
|
+
>> HTTP.get("http://www.google.com")
|
44
44
|
=> "<html><head><meta http-equiv=\"content-type\" content=..."
|
45
45
|
```
|
46
46
|
|
47
|
-
That's it! The result is the response body as a string. To obtain an
|
47
|
+
That's it! The result is the response body as a string. To obtain an HTTP::Response object
|
48
48
|
instead of the response body, chain `.response` on the end of the request:
|
49
49
|
|
50
50
|
```ruby
|
51
|
-
>>
|
51
|
+
>> HTTP.get("http://www.google.com").response
|
52
52
|
=> #<HTTP/1.0 200 OK @headers={"Content-Type"=>"text/html; charset=UTF-8", "Date"=>"Fri, ...>
|
53
53
|
```
|
54
54
|
|
55
55
|
Making POST requests is simple too. Want to POST a form?
|
56
56
|
|
57
57
|
```ruby
|
58
|
-
|
58
|
+
HTTP.post "http://example.com/resource", :form => {:foo => "42"}
|
59
59
|
```
|
60
60
|
Making GET requests with query string parameters is as simple.
|
61
61
|
|
62
62
|
```ruby
|
63
|
-
|
63
|
+
HTTP.get "http://example.com/resource", :params => {:foo => "bar"}
|
64
64
|
```
|
65
65
|
|
66
66
|
Want to POST with a specific body, JSON for instance?
|
67
67
|
|
68
68
|
```ruby
|
69
|
-
|
69
|
+
HTTP.post "http://example.com/resource", :body => JSON.dump(:foo => '42')
|
70
70
|
```
|
71
71
|
|
72
72
|
Or have it serialize JSON for you:
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
|
75
|
+
HTTP.post "http://example.com/resource", :json => {:foo => '42'}
|
76
76
|
```
|
77
77
|
|
78
78
|
It's easy!
|
@@ -80,12 +80,12 @@ It's easy!
|
|
80
80
|
Adding Headers
|
81
81
|
--------------
|
82
82
|
|
83
|
-
The
|
83
|
+
The HTTP library uses the concept of chaining to simplify requests. Let's say
|
84
84
|
you want to get the latest commit of this library from Github in JSON format.
|
85
85
|
One way we could do this is by tacking a filename on the end of the URL:
|
86
86
|
|
87
87
|
```ruby
|
88
|
-
|
88
|
+
HTTP.get "https://github.com/tarcieri/http/commit/HEAD.json"
|
89
89
|
```
|
90
90
|
|
91
91
|
The Github API happens to support this approach, but really this is a bit of a
|
@@ -95,22 +95,22 @@ the full, raw power of HTTP, we can perform content negotiation the way HTTP
|
|
95
95
|
intends us to, by using the Accept header:
|
96
96
|
|
97
97
|
```ruby
|
98
|
-
|
98
|
+
HTTP.with_headers(:accept => 'application/json').
|
99
99
|
get("https://github.com/tarcieri/http/commit/HEAD")
|
100
100
|
```
|
101
101
|
|
102
102
|
This requests JSON from Github. Github is smart enough to understand our
|
103
103
|
request and returns a response with Content-Type: application/json. If you
|
104
104
|
happen to have a library loaded which defines the JSON constant and implements
|
105
|
-
JSON.parse, the
|
105
|
+
JSON.parse, the HTTP library will attempt to parse the JSON response.
|
106
106
|
|
107
107
|
Shorter aliases exists for HTTP.with_headers:
|
108
108
|
|
109
109
|
```ruby
|
110
|
-
|
110
|
+
HTTP.with(:accept => 'application/json').
|
111
111
|
get("https://github.com/tarcieri/http/commit/HEAD")
|
112
112
|
|
113
|
-
|
113
|
+
HTTP[:accept => 'application/json'].
|
114
114
|
get("https://github.com/tarcieri/http/commit/HEAD")
|
115
115
|
```
|
116
116
|
|
@@ -122,29 +122,16 @@ right? But usually it's not, and so we end up adding ".json" onto the ends of
|
|
122
122
|
our URLs because the existing mechanisms make it too hard. It should be easy:
|
123
123
|
|
124
124
|
```ruby
|
125
|
-
|
125
|
+
HTTP.accept(:json).get("https://github.com/tarcieri/http/commit/HEAD")
|
126
126
|
```
|
127
127
|
|
128
128
|
This adds the appropriate Accept header for retrieving a JSON response for the
|
129
129
|
given resource.
|
130
130
|
|
131
|
-
|
132
|
-
------------------
|
133
|
-
|
134
|
-
The Http gem provides partial compatibility with the Curb::Easy API. This is
|
135
|
-
great if you're transitioning to JRuby and need a drop-in API-compatible
|
136
|
-
replacement for Curb.
|
137
|
-
|
138
|
-
To use the Curb compatibility, do:
|
139
|
-
|
140
|
-
```ruby
|
141
|
-
require 'http/compat/curb'
|
142
|
-
```
|
143
|
-
|
144
|
-
Contributing to Http
|
131
|
+
Contributing to HTTP
|
145
132
|
--------------------
|
146
133
|
|
147
|
-
* Fork
|
134
|
+
* Fork HTTP on github
|
148
135
|
* Make your changes and send me a pull request
|
149
136
|
* If I like them I'll merge them
|
150
137
|
* If I've accepted a patch, feel free to ask for a commit bit!
|
data/Rakefile
CHANGED
data/examples/celluloid.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Example of using the
|
3
|
+
# Example of using the HTTP Gem with Celluloid::IO
|
4
4
|
# Make sure to 'gem install celluloid-io' before running
|
5
5
|
#
|
6
6
|
# Run as: bundle exec examples/celluloid.rb
|
@@ -9,4 +9,4 @@
|
|
9
9
|
require 'celluloid/io'
|
10
10
|
require 'http'
|
11
11
|
|
12
|
-
puts
|
12
|
+
puts HTTP.get("https://www.google.com/", :socket_class => Celluloid::IO::TCPSocket, :ssl_socket_class => Celluloid::IO::SSLSocket)
|
data/http.gemspec
CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.add_runtime_dependency 'http_parser.rb'
|
19
19
|
|
20
20
|
gem.add_development_dependency 'rake'
|
21
|
-
gem.add_development_dependency 'rspec'
|
21
|
+
gem.add_development_dependency 'rspec', '>= 2.11'
|
22
22
|
gem.add_development_dependency 'json'
|
23
23
|
end
|
data/lib/http.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
require 'uri'
|
2
1
|
require 'http/parser'
|
3
|
-
require 'http/version'
|
4
2
|
|
5
3
|
require 'http/chainable'
|
6
4
|
require 'http/client'
|
@@ -16,20 +14,9 @@ require 'http/uri_backport' if RUBY_VERSION < "1.9.0"
|
|
16
14
|
module HTTP
|
17
15
|
extend Chainable
|
18
16
|
|
19
|
-
# The method given was not understood
|
20
|
-
class UnsupportedMethodError < ArgumentError; end
|
21
|
-
|
22
|
-
# Matches HTTP header names when in "Canonical-Http-Format"
|
23
|
-
CANONICAL_HEADER = /^[A-Z][a-z]*(-[A-Z][a-z]*)*$/
|
24
|
-
|
25
17
|
class << self
|
26
|
-
#
|
18
|
+
# HTTP[:accept => 'text/html'].get(...)
|
27
19
|
alias_method :[], :with_headers
|
28
|
-
|
29
|
-
# Transform to canonical HTTP header capitalization
|
30
|
-
def canonicalize_header(header)
|
31
|
-
header.to_s.split(/[\-_]/).map(&:capitalize).join('-')
|
32
|
-
end
|
33
20
|
end
|
34
21
|
end
|
35
22
|
|
data/lib/http/chainable.rb
CHANGED
@@ -94,18 +94,18 @@ module HTTP
|
|
94
94
|
if type.is_a? String
|
95
95
|
with :accept => type
|
96
96
|
else
|
97
|
-
mime_type =
|
97
|
+
mime_type = HTTP::MimeType[type]
|
98
98
|
raise ArgumentError, "unknown MIME type: #{type}" unless mime_type
|
99
99
|
with :accept => mime_type.type
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
103
|
def default_options
|
104
|
-
@default_options ||= Options.new
|
104
|
+
@default_options ||= HTTP::Options.new
|
105
105
|
end
|
106
106
|
|
107
107
|
def default_options=(opts)
|
108
|
-
@default_options = Options.new(opts)
|
108
|
+
@default_options = HTTP::Options.new(opts)
|
109
109
|
end
|
110
110
|
|
111
111
|
def default_headers
|
@@ -131,7 +131,7 @@ module HTTP
|
|
131
131
|
private
|
132
132
|
|
133
133
|
def branch(options)
|
134
|
-
Client.new(options)
|
134
|
+
HTTP::Client.new(options)
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|
data/lib/http/client.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'http/options'
|
1
2
|
require 'uri'
|
2
3
|
|
3
4
|
module HTTP
|
@@ -10,7 +11,7 @@ module HTTP
|
|
10
11
|
attr_reader :default_options
|
11
12
|
|
12
13
|
def initialize(default_options = {})
|
13
|
-
@default_options = Options.new(default_options)
|
14
|
+
@default_options = HTTP::Options.new(default_options)
|
14
15
|
end
|
15
16
|
|
16
17
|
def body(opts, headers)
|
@@ -35,18 +36,18 @@ module HTTP
|
|
35
36
|
uri="#{uri}?#{URI.encode_www_form(opts.params)}"
|
36
37
|
end
|
37
38
|
|
38
|
-
request = Request.new method, uri, headers, proxy, method_body
|
39
|
+
request = HTTP::Request.new method, uri, headers, proxy, method_body
|
39
40
|
if opts.follow
|
40
41
|
code = 302
|
41
42
|
while code == 302 or code == 301
|
42
43
|
# if the uri isn't fully formed complete it
|
43
|
-
if not uri.match
|
44
|
+
if not uri.match(/\./)
|
44
45
|
uri = "#{method}://#{host}#{uri}"
|
45
46
|
end
|
46
47
|
host = URI.parse(uri).host
|
47
48
|
opts.headers["Host"] = host
|
48
49
|
method_body = body(opts, headers)
|
49
|
-
request = Request.new method, uri, headers, proxy, method_body
|
50
|
+
request = HTTP::Request.new method, uri, headers, proxy, method_body
|
50
51
|
response = perform request, opts
|
51
52
|
code = response.code
|
52
53
|
uri = response.headers["Location"]
|
@@ -61,8 +62,8 @@ module HTTP
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def perform(request, options)
|
64
|
-
parser =
|
65
|
-
uri
|
65
|
+
parser = HTTP::Response::Parser.new
|
66
|
+
uri = request.uri
|
66
67
|
socket = options[:socket_class].open(uri.host, uri.port) # TODO: proxy support
|
67
68
|
|
68
69
|
if uri.is_a?(URI::HTTPS)
|
@@ -83,7 +84,7 @@ module HTTP
|
|
83
84
|
raise IOError, "problem making HTTP request: #{ex}"
|
84
85
|
end
|
85
86
|
|
86
|
-
response =
|
87
|
+
response = HTTP::Response.new(parser.status_code, parser.http_version, parser.headers) do
|
87
88
|
if !parser.finished? || (@body_remaining && @body_remaining > 0)
|
88
89
|
chunk = parser.chunk || begin
|
89
90
|
parser << socket.readpartial(BUFFER_SIZE)
|
@@ -107,14 +108,14 @@ module HTTP
|
|
107
108
|
if method == :head
|
108
109
|
response
|
109
110
|
else
|
110
|
-
|
111
|
+
HTTP::Response::BodyDelegator.new(response, response.parse_body)
|
111
112
|
end
|
112
113
|
when :object
|
113
114
|
response
|
114
115
|
when :parsed_body
|
115
|
-
|
116
|
+
HTTP::Response::BodyDelegator.new(response, response.parse_body)
|
116
117
|
when :body
|
117
|
-
|
118
|
+
HTTP::Response::BodyDelegator.new(response)
|
118
119
|
else raise ArgumentError, "invalid response type: #{option}"
|
119
120
|
end
|
120
121
|
end
|
data/lib/http/header.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module HTTP
|
2
|
+
module Header
|
3
|
+
# Matches HTTP header names when in "Canonical-Http-Format"
|
4
|
+
CANONICAL_HEADER = /^[A-Z][a-z]*(-[A-Z][a-z]*)*$/
|
5
|
+
|
6
|
+
# Transform to canonical HTTP header capitalization
|
7
|
+
def canonicalize_header(header)
|
8
|
+
header.to_s.split(/[\-_]/).map(&:capitalize).join('-')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/http/mime_type.rb
CHANGED
data/lib/http/mime_types/json.rb
CHANGED
data/lib/http/options.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'http/version'
|
2
2
|
require 'openssl'
|
3
|
+
require 'socket'
|
3
4
|
|
4
5
|
module HTTP
|
5
6
|
class Options
|
@@ -7,7 +8,7 @@ module HTTP
|
|
7
8
|
# How to format the response [:object, :body, :parse_body]
|
8
9
|
attr_accessor :response
|
9
10
|
|
10
|
-
#
|
11
|
+
# HTTP headers to include in the request
|
11
12
|
attr_accessor :headers
|
12
13
|
|
13
14
|
# Query string params to add to the url
|
@@ -19,7 +20,7 @@ module HTTP
|
|
19
20
|
# Explicit request body of the request
|
20
21
|
attr_accessor :body
|
21
22
|
|
22
|
-
#
|
23
|
+
# HTTP proxy to route request
|
23
24
|
attr_accessor :proxy
|
24
25
|
|
25
26
|
# Before callbacks
|
@@ -43,7 +44,7 @@ module HTTP
|
|
43
44
|
attr_accessor :default_socket_class, :default_ssl_socket_class
|
44
45
|
|
45
46
|
def new(options = {})
|
46
|
-
return options if options.is_a?(
|
47
|
+
return options if options.is_a?(self)
|
47
48
|
super
|
48
49
|
end
|
49
50
|
end
|
@@ -62,7 +63,7 @@ module HTTP
|
|
62
63
|
@ssl_socket_class = options[:ssl_socket_class] || self.class.default_ssl_socket_class
|
63
64
|
@ssl_context = options[:ssl_context]
|
64
65
|
|
65
|
-
@headers["User-Agent"] ||= "
|
66
|
+
@headers["User-Agent"] ||= "RubyHTTPGem/#{HTTP::VERSION}"
|
66
67
|
end
|
67
68
|
|
68
69
|
def with_response(response)
|
@@ -146,7 +147,7 @@ module HTTP
|
|
146
147
|
end
|
147
148
|
end
|
148
149
|
|
149
|
-
|
150
|
+
self.class.new(merged)
|
150
151
|
end
|
151
152
|
|
152
153
|
def to_hash
|
data/lib/http/request.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
require 'http/header'
|
1
2
|
require 'http/request_stream'
|
3
|
+
require 'uri'
|
2
4
|
|
3
5
|
module HTTP
|
4
6
|
class Request
|
7
|
+
include HTTP::Header
|
8
|
+
|
9
|
+
# The method given was not understood
|
10
|
+
class UnsupportedMethodError < ArgumentError; end
|
11
|
+
|
5
12
|
# RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
|
6
13
|
METHODS = [:options, :get, :head, :post, :put, :delete, :trace, :connect]
|
7
14
|
|
@@ -39,16 +46,17 @@ module HTTP
|
|
39
46
|
headers.each do |name, value|
|
40
47
|
name = name.to_s
|
41
48
|
key = name[CANONICAL_HEADER]
|
42
|
-
key ||=
|
49
|
+
key ||= canonicalize_header(name)
|
43
50
|
@headers[key] = value
|
44
51
|
end
|
52
|
+
@headers["Host"] ||= @uri.host
|
45
53
|
|
46
54
|
@proxy, @body, @version = proxy, body, version
|
47
55
|
end
|
48
56
|
|
49
57
|
# Obtain the given header
|
50
58
|
def [](header)
|
51
|
-
@headers[
|
59
|
+
@headers[canonicalize_header(header)]
|
52
60
|
end
|
53
61
|
|
54
62
|
# Stream the request to a socket
|
@@ -56,7 +64,7 @@ module HTTP
|
|
56
64
|
path = uri.query ? "#{uri.path}?#{uri.query}" : uri.path
|
57
65
|
path = "/" if path.empty?
|
58
66
|
request_header = "#{method.to_s.upcase} #{path} HTTP/#{version}"
|
59
|
-
rs =
|
67
|
+
rs = HTTP::RequestStream.new socket, body, @headers, request_header
|
60
68
|
rs.stream
|
61
69
|
end
|
62
70
|
end
|