http 0.8.8 → 0.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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