http 0.8.8 → 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e198bd8fdb5940123725f1f6cd3aaa0b610f631
4
- data.tar.gz: c0d829c1d9dbc36b708f0acce73fc537e82b2f66
3
+ metadata.gz: 3e43eef7590b892ac207ac122a1ac58e61a402ba
4
+ data.tar.gz: 622380eacbab0139f5c6d1420d0df6c8c190b6d3
5
5
  SHA512:
6
- metadata.gz: 448f0114af4fbe70411fb4969792263b7e58111ac197f0581e93d1b48628dc4d64b81fc0b6de0f961d64995fad0e4d4d58bdedc798efb151360df1ebf13e0c64
7
- data.tar.gz: 9320d337488c30d9904fa0e7fd27c1f13a90c5ddce253b43cb5c03d72fdfdaa197e19cb8b48d5a5ce0426bcd486612baa19410d3deedafc7bf369e48f8d47d10
6
+ metadata.gz: 4ccc0e229a0e15aa63c30d012213258a9802a04f1ec0a1dbea67d73b2647d7380b951151d7492b43b10730e6c3dd905f64bfda4621a706747e65a976a7b37cd1
7
+ data.tar.gz: 1e2af51ecfcb07a33f2b6d94b93bc313b9018e2799e6ccc3f3265e7e2c8fde80bf97f7ff6e8c8309d8e693a08e72ae21f15b1cdb4442adc43608daba11d947b4
data/CHANGES.md CHANGED
@@ -3,6 +3,12 @@
3
3
  * _the future is unwritten_
4
4
 
5
5
 
6
+ ## 0.8.9 (2015-05-11)
7
+
8
+ * Add cookies support. (@ixti)
9
+ * Enforce stringified body encoding. See #219. (@Connorhd)
10
+
11
+
6
12
  ## 0.8.8 (2015-05-09)
7
13
 
8
14
  * Fix CONNECT header for proxies. See #217. (@Connorhd)
data/http.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |gem|
25
25
 
26
26
  gem.add_runtime_dependency "http_parser.rb", "~> 0.6.0"
27
27
  gem.add_runtime_dependency "http-form_data", "~> 1.0.1"
28
+ gem.add_runtime_dependency "http-cookie", "~> 1.0"
28
29
  gem.add_runtime_dependency "addressable", "~> 2.3"
29
30
 
30
31
  gem.add_development_dependency "bundler", "~> 1.0"
@@ -187,6 +187,11 @@ module HTTP
187
187
  # @see #headers
188
188
  alias_method :with_headers, :headers
189
189
 
190
+ # Make a request with the given cookies
191
+ def cookies(cookies)
192
+ branch default_options.with_cookies(cookies)
193
+ end
194
+
190
195
  # Accept the given MIME type(s)
191
196
  # @param type
192
197
  def accept(type)
data/lib/http/client.rb CHANGED
@@ -5,6 +5,7 @@ require "uri"
5
5
 
6
6
  require "http/form_data"
7
7
  require "http/options"
8
+ require "http/headers"
8
9
  require "http/connection"
9
10
  require "http/redirector"
10
11
  require "http/uri"
@@ -31,9 +32,9 @@ module HTTP
31
32
  def request(verb, uri, opts = {})
32
33
  opts = @default_options.merge(opts)
33
34
  uri = make_request_uri(uri, opts)
34
- headers = opts.headers
35
- proxy = opts.proxy
35
+ headers = opts.headers.merge(Headers::SET_COOKIE => opts.cookies.values)
36
36
  body = make_request_body(opts, headers)
37
+ proxy = opts.proxy
37
38
 
38
39
  # Tell the server to keep the conn open
39
40
  if default_options.persistent?
data/lib/http/headers.rb CHANGED
@@ -16,6 +16,9 @@ module HTTP
16
16
  # @see http://tools.ietf.org/html/rfc7230#section-3.2
17
17
  HEADER_NAME_RE = /^[A-Za-z0-9!#\$%&'*+\-.^_`|~]+$/
18
18
 
19
+ # Cookies header name
20
+ SET_COOKIE = "Set-Cookie".freeze
21
+
19
22
  # Class constructor.
20
23
  def initialize
21
24
  @pile = []
data/lib/http/options.rb CHANGED
@@ -42,23 +42,23 @@ module HTTP
42
42
  end
43
43
 
44
44
  def initialize(options = {})
45
- defaults = {:response => :auto,
46
- :proxy => {},
47
- :timeout_class => self.class.default_timeout_class,
48
- :timeout_options => {},
49
- :socket_class => self.class.default_socket_class,
50
- :ssl_socket_class => self.class.default_ssl_socket_class,
51
- :ssl => {},
52
- :cache => self.class.default_cache,
53
- :keep_alive_timeout => 5,
54
- :headers => {}}
45
+ defaults = {
46
+ :response => :auto,
47
+ :proxy => {},
48
+ :timeout_class => self.class.default_timeout_class,
49
+ :timeout_options => {},
50
+ :socket_class => self.class.default_socket_class,
51
+ :ssl_socket_class => self.class.default_ssl_socket_class,
52
+ :ssl => {},
53
+ :cache => self.class.default_cache,
54
+ :keep_alive_timeout => 5,
55
+ :headers => {},
56
+ :cookies => {}
57
+ }
55
58
 
56
59
  opts_w_defaults = defaults.merge(options)
57
60
  opts_w_defaults[:headers] = HTTP::Headers.coerce(opts_w_defaults[:headers])
58
-
59
- opts_w_defaults.each do |(opt_name, opt_val)|
60
- self[opt_name] = opt_val
61
- end
61
+ opts_w_defaults.each { |(k, v)| self[k] = v }
62
62
  end
63
63
 
64
64
  def_option :headers do |headers|
@@ -145,3 +145,6 @@ module HTTP
145
145
  end
146
146
  end
147
147
  end
148
+
149
+ # require cookies options
150
+ require "http/options/cookies"
@@ -0,0 +1,20 @@
1
+ module HTTP
2
+ class Options
3
+ # Default path of cookies
4
+ DEFAULT_COOKIE_PATH = "/".freeze
5
+
6
+ def_option :cookies do |cookies|
7
+ cookies.each_with_object self.cookies.dup do |(k, v), jar|
8
+ cookie = case
9
+ when k.is_a?(Cookie) then k
10
+ when k.is_a?(Hash) then Cookie.new k
11
+ when v.is_a?(Hash) then Cookie.new(k.to_s, v)
12
+ else Cookie.new(k.to_s, v.to_s)
13
+ end
14
+
15
+ cookie.path ||= DEFAULT_COOKIE_PATH
16
+ jar[cookie.name] = cookie.set_cookie_value
17
+ end
18
+ end
19
+ end
20
+ end
data/lib/http/response.rb CHANGED
@@ -5,6 +5,8 @@ require "http/content_type"
5
5
  require "http/mime_type"
6
6
  require "http/response/caching"
7
7
  require "http/response/status"
8
+ require "http/uri"
9
+ require "http/cookie_jar"
8
10
  require "time"
9
11
 
10
12
  module HTTP
@@ -32,7 +34,7 @@ module HTTP
32
34
  def initialize(status, version, headers, body, uri = nil) # rubocop:disable ParameterLists
33
35
  @version = version
34
36
  @body = body
35
- @uri = uri
37
+ @uri = uri && HTTP::URI.parse(uri)
36
38
  @status = HTTP::Response::Status.new status
37
39
  @headers = HTTP::Headers.coerce(headers || {})
38
40
  end
@@ -93,6 +95,12 @@ module HTTP
93
95
  @charset ||= content_type.charset
94
96
  end
95
97
 
98
+ def cookies
99
+ @cookies ||= headers.each_with_object CookieJar.new do |(k, v), jar|
100
+ jar.parse(v, uri) if k == Headers::SET_COOKIE
101
+ end
102
+ end
103
+
96
104
  # Parse response body with corresponding MIME type adapter.
97
105
  #
98
106
  # @param [#to_s] as Parse as given MIME type
@@ -36,9 +36,9 @@ module HTTP
36
36
 
37
37
  begin
38
38
  @streaming = false
39
- @contents = ""
39
+ @contents = "".force_encoding(Encoding::UTF_8)
40
40
  while (chunk = @client.readpartial)
41
- @contents << chunk
41
+ @contents << chunk.force_encoding(Encoding::ASCII_8BIT)
42
42
  end
43
43
  rescue
44
44
  @contents = nil
data/lib/http/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = "0.8.8"
2
+ VERSION = "0.8.9"
3
3
  end
@@ -55,6 +55,7 @@ RSpec.describe HTTP::Options, "merge" do
55
55
  :socket_class => described_class.default_socket_class,
56
56
  :ssl_socket_class => described_class.default_ssl_socket_class,
57
57
  :ssl_context => nil,
58
- :cache => described_class.default_cache)
58
+ :cache => described_class.default_cache,
59
+ :cookies => {})
59
60
  end
60
61
  end
@@ -1,6 +1,8 @@
1
1
  RSpec.describe HTTP::Response do
2
2
  let(:body) { "Hello world!" }
3
- subject(:response) { HTTP::Response.new 200, "1.1", {}, body }
3
+ let(:uri) { "http://example.com/" }
4
+ let(:headers) { {} }
5
+ subject(:response) { HTTP::Response.new 200, "1.1", headers, body, uri }
4
6
 
5
7
  it "includes HTTP::Headers::Mixin" do
6
8
  expect(described_class).to include HTTP::Headers::Mixin
@@ -9,15 +11,15 @@ RSpec.describe HTTP::Response do
9
11
  describe "to_a" do
10
12
  let(:body) { "Hello world" }
11
13
  let(:content_type) { "text/plain" }
12
- subject { HTTP::Response.new(200, "1.1", {"Content-Type" => content_type}, body) }
14
+ let(:headers) { {"Content-Type" => content_type} }
13
15
 
14
16
  it "returns a Rack-like array" do
15
- expect(subject.to_a).to eq([200, {"Content-Type" => content_type}, body])
17
+ expect(subject.to_a).to eq([200, headers, body])
16
18
  end
17
19
  end
18
20
 
19
21
  describe "mime_type" do
20
- subject { HTTP::Response.new(200, "1.1", headers, "").mime_type }
22
+ subject { response.mime_type }
21
23
 
22
24
  context "without Content-Type header" do
23
25
  let(:headers) { {} }
@@ -36,7 +38,7 @@ RSpec.describe HTTP::Response do
36
38
  end
37
39
 
38
40
  describe "charset" do
39
- subject { HTTP::Response.new(200, "1.1", headers, "").charset }
41
+ subject { response.charset }
40
42
 
41
43
  context "without Content-Type header" do
42
44
  let(:headers) { {} }
@@ -57,7 +59,6 @@ RSpec.describe HTTP::Response do
57
59
  describe "#parse" do
58
60
  let(:headers) { {"Content-Type" => content_type} }
59
61
  let(:body) { '{"foo":"bar"}' }
60
- let(:response) { HTTP::Response.new 200, "1.1", headers, body }
61
62
 
62
63
  context "with known content type" do
63
64
  let(:content_type) { "application/json" }
@@ -86,8 +87,7 @@ RSpec.describe HTTP::Response do
86
87
  end
87
88
 
88
89
  describe "#flush" do
89
- let(:body) { double :to_s => "" }
90
- let(:response) { HTTP::Response.new 200, "1.1", {}, body }
90
+ let(:body) { double :to_s => "" }
91
91
 
92
92
  it "returns response self-reference" do
93
93
  expect(response.flush).to be response
@@ -100,11 +100,10 @@ RSpec.describe HTTP::Response do
100
100
  end
101
101
 
102
102
  describe "#inspect" do
103
- it "returns human0friendly response representation" do
104
- headers = {:content_type => "text/plain"}
105
- body = double :to_s => "foobar"
106
- response = HTTP::Response.new(200, "1.1", headers, body)
103
+ let(:headers) { {:content_type => "text/plain"} }
104
+ let(:body) { double :to_s => "foobar" }
107
105
 
106
+ it "returns human-friendly response representation" do
108
107
  expect(response.inspect).
109
108
  to eq '#<HTTP::Response/1.1 200 OK {"Content-Type"=>"text/plain"}>'
110
109
  end
@@ -114,4 +113,25 @@ RSpec.describe HTTP::Response do
114
113
  subject { response.caching }
115
114
  it { is_expected.to be_a HTTP::Response::Caching }
116
115
  end
116
+
117
+ describe "#cookies" do
118
+ let(:cookies) { ["a=1", "b=2; domain=example.com", "c=3; domain=bad.org"] }
119
+ let(:headers) { {"Set-Cookie" => cookies} }
120
+
121
+ subject(:jar) { response.cookies }
122
+
123
+ it { is_expected.to be_an HTTP::CookieJar }
124
+
125
+ it "contains cookies without domain restriction" do
126
+ expect(jar.count { |c| "a" == c.name }).to eq 1
127
+ end
128
+
129
+ it "contains cookies limited to domain of request uri" do
130
+ expect(jar.count { |c| "b" == c.name }).to eq 1
131
+ end
132
+
133
+ it "does not contains cookies limited to non-requeted uri" do
134
+ expect(jar.count { |c| "c" == c.name }).to eq 0
135
+ end
136
+ end
117
137
  end
@@ -131,6 +131,20 @@ RSpec.describe HTTP do
131
131
  end
132
132
  end
133
133
 
134
+ context "loading binary data" do
135
+ it "is encoded as bytes" do
136
+ response = HTTP.get "#{dummy.endpoint}/bytes"
137
+ expect(response.to_s.encoding).to eq(Encoding::ASCII_8BIT)
138
+ end
139
+ end
140
+
141
+ context "loading text" do
142
+ it "is utf-8 encoded" do
143
+ response = HTTP.get dummy.endpoint
144
+ expect(response.to_s.encoding).to eq(Encoding::UTF_8)
145
+ end
146
+ end
147
+
134
148
  context "posting with an explicit body" do
135
149
  it "is easy" do
136
150
  response = HTTP.post "#{dummy.endpoint}/body", :body => "testing-body"
@@ -122,5 +122,11 @@ class DummyServer < WEBrick::HTTPServer
122
122
  res.status = 200
123
123
  res["Content-Type"] = "text/html"
124
124
  end
125
+
126
+ get "/bytes" do |_req, res|
127
+ bytes = [80, 75, 3, 4, 20, 0, 0, 0, 8, 0, 123, 104, 169, 70, 99, 243, 243]
128
+ res["Content-Type"] = "application/octet-stream"
129
+ res.body = bytes.pack("c*")
130
+ end
125
131
  end
126
132
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.8
4
+ version: 0.8.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-05-09 00:00:00.000000000 Z
14
+ date: 2015-05-11 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: http_parser.rb
@@ -41,6 +41,20 @@ dependencies:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
43
  version: 1.0.1
44
+ - !ruby/object:Gem::Dependency
45
+ name: http-cookie
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
44
58
  - !ruby/object:Gem::Dependency
45
59
  name: addressable
46
60
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +121,7 @@ files:
107
121
  - lib/http/mime_type/adapter.rb
108
122
  - lib/http/mime_type/json.rb
109
123
  - lib/http/options.rb
124
+ - lib/http/options/cookies.rb
110
125
  - lib/http/redirector.rb
111
126
  - lib/http/request.rb
112
127
  - lib/http/request/caching.rb