http 0.6.4 → 0.7.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.

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +38 -93
  3. data/.travis.yml +5 -5
  4. data/.yardopts +2 -0
  5. data/CHANGES.md +21 -5
  6. data/Gemfile +12 -9
  7. data/Guardfile +3 -4
  8. data/LICENSE.txt +1 -1
  9. data/README.md +76 -53
  10. data/Rakefile +1 -1
  11. data/examples/parallel_requests_with_celluloid.rb +1 -1
  12. data/http.gemspec +6 -5
  13. data/lib/http.rb +0 -1
  14. data/lib/http/chainable.rb +54 -20
  15. data/lib/http/client.rb +14 -12
  16. data/lib/http/headers.rb +20 -17
  17. data/lib/http/mime_type/adapter.rb +1 -1
  18. data/lib/http/options.rb +1 -1
  19. data/lib/http/request.rb +23 -16
  20. data/lib/http/request/writer.rb +2 -7
  21. data/lib/http/response.rb +47 -76
  22. data/lib/http/response/body.rb +2 -3
  23. data/lib/http/response/status.rb +122 -0
  24. data/lib/http/response/status/reasons.rb +72 -0
  25. data/lib/http/version.rb +1 -1
  26. data/logo.png +0 -0
  27. data/spec/http/client_spec.rb +13 -47
  28. data/spec/http/content_type_spec.rb +15 -15
  29. data/spec/http/headers/mixin_spec.rb +1 -1
  30. data/spec/http/headers_spec.rb +42 -38
  31. data/spec/http/options/body_spec.rb +1 -1
  32. data/spec/http/options/form_spec.rb +1 -1
  33. data/spec/http/options/headers_spec.rb +2 -2
  34. data/spec/http/options/json_spec.rb +1 -1
  35. data/spec/http/options/merge_spec.rb +1 -1
  36. data/spec/http/options/new_spec.rb +2 -2
  37. data/spec/http/options/proxy_spec.rb +1 -1
  38. data/spec/http/options_spec.rb +1 -1
  39. data/spec/http/redirector_spec.rb +1 -1
  40. data/spec/http/request/writer_spec.rb +72 -24
  41. data/spec/http/request_spec.rb +31 -35
  42. data/spec/http/response/body_spec.rb +1 -1
  43. data/spec/http/response/status_spec.rb +139 -0
  44. data/spec/http/response_spec.rb +7 -7
  45. data/spec/http_spec.rb +41 -37
  46. data/spec/spec_helper.rb +2 -10
  47. data/spec/support/example_server.rb +14 -86
  48. data/spec/support/example_server/servlet.rb +102 -0
  49. metadata +46 -21
  50. data/lib/http/authorization_header.rb +0 -37
  51. data/lib/http/authorization_header/basic_auth.rb +0 -24
  52. data/lib/http/authorization_header/bearer_token.rb +0 -28
  53. data/lib/http/backports.rb +0 -2
  54. data/lib/http/backports/base64.rb +0 -6
  55. data/lib/http/backports/uri.rb +0 -131
  56. data/spec/http/authorization_header/basic_auth_spec.rb +0 -29
  57. data/spec/http/authorization_header/bearer_token_spec.rb +0 -36
  58. data/spec/http/authorization_header_spec.rb +0 -41
  59. data/spec/http/backports/base64_spec.rb +0 -13
  60. data/spec/http/backports/uri_spec.rb +0 -9
  61. data/spec/support/black_hole.rb +0 -5
  62. data/spec/support/create_certs.rb +0 -57
  63. data/spec/support/dummy_server.rb +0 -52
  64. data/spec/support/dummy_server/servlet.rb +0 -30
  65. data/spec/support/servers/config.rb +0 -13
  66. data/spec/support/servers/runner.rb +0 -17
@@ -1,47 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::ContentType do
3
+ RSpec.describe HTTP::ContentType do
4
4
  describe '.parse' do
5
5
  context 'with text/plain' do
6
6
  subject { described_class.parse 'text/plain' }
7
- its(:mime_type) { should eq 'text/plain' }
8
- its(:charset) { should be_nil }
7
+ its(:mime_type) { is_expected.to eq 'text/plain' }
8
+ its(:charset) { is_expected.to be_nil }
9
9
  end
10
10
 
11
11
  context 'with tEXT/plaIN' do
12
12
  subject { described_class.parse 'tEXT/plaIN' }
13
- its(:mime_type) { should eq 'text/plain' }
14
- its(:charset) { should be_nil }
13
+ its(:mime_type) { is_expected.to eq 'text/plain' }
14
+ its(:charset) { is_expected.to be_nil }
15
15
  end
16
16
 
17
17
  context 'with text/plain; charset=utf-8' do
18
18
  subject { described_class.parse 'text/plain; charset=utf-8' }
19
- its(:mime_type) { should eq 'text/plain' }
20
- its(:charset) { should eq 'utf-8' }
19
+ its(:mime_type) { is_expected.to eq 'text/plain' }
20
+ its(:charset) { is_expected.to eq 'utf-8' }
21
21
  end
22
22
 
23
23
  context 'with text/plain; charset="utf-8"' do
24
24
  subject { described_class.parse 'text/plain; charset="utf-8"' }
25
- its(:mime_type) { should eq 'text/plain' }
26
- its(:charset) { should eq 'utf-8' }
25
+ its(:mime_type) { is_expected.to eq 'text/plain' }
26
+ its(:charset) { is_expected.to eq 'utf-8' }
27
27
  end
28
28
 
29
29
  context 'with text/plain; charSET=utf-8' do
30
30
  subject { described_class.parse 'text/plain; charSET=utf-8' }
31
- its(:mime_type) { should eq 'text/plain' }
32
- its(:charset) { should eq 'utf-8' }
31
+ its(:mime_type) { is_expected.to eq 'text/plain' }
32
+ its(:charset) { is_expected.to eq 'utf-8' }
33
33
  end
34
34
 
35
35
  context 'with text/plain; foo=bar; charset=utf-8' do
36
36
  subject { described_class.parse 'text/plain; foo=bar; charset=utf-8' }
37
- its(:mime_type) { should eq 'text/plain' }
38
- its(:charset) { should eq 'utf-8' }
37
+ its(:mime_type) { is_expected.to eq 'text/plain' }
38
+ its(:charset) { is_expected.to eq 'utf-8' }
39
39
  end
40
40
 
41
41
  context 'with text/plain;charset=utf-8;foo=bar' do
42
42
  subject { described_class.parse 'text/plain;charset=utf-8;foo=bar' }
43
- its(:mime_type) { should eq 'text/plain' }
44
- its(:charset) { should eq 'utf-8' }
43
+ its(:mime_type) { is_expected.to eq 'text/plain' }
44
+ its(:charset) { is_expected.to eq 'utf-8' }
45
45
  end
46
46
  end
47
47
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Headers::Mixin do
3
+ RSpec.describe HTTP::Headers::Mixin do
4
4
  let :dummy_class do
5
5
  Class.new do
6
6
  include HTTP::Headers::Mixin
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Headers do
3
+ RSpec.describe HTTP::Headers do
4
4
  subject(:headers) { described_class.new }
5
5
 
6
6
  it 'is Enumerable' do
@@ -26,8 +26,8 @@ describe HTTP::Headers do
26
26
 
27
27
  it 'allows set multiple values' do
28
28
  headers.set :set_cookie, 'hoo=ray'
29
- headers.set :set_cookie, %w[hoo=ray woo=hoo]
30
- expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo]
29
+ headers.set :set_cookie, %w(hoo=ray woo=hoo)
30
+ expect(headers['Set-Cookie']).to eq %w(hoo=ray woo=hoo)
31
31
  end
32
32
  end
33
33
 
@@ -50,8 +50,8 @@ describe HTTP::Headers do
50
50
 
51
51
  it 'allows set multiple values' do
52
52
  headers[:set_cookie] = 'hoo=ray'
53
- headers[:set_cookie] = %w[hoo=ray woo=hoo]
54
- expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo]
53
+ headers[:set_cookie] = %w(hoo=ray woo=hoo)
54
+ expect(headers['Set-Cookie']).to eq %w(hoo=ray woo=hoo)
55
55
  end
56
56
  end
57
57
 
@@ -83,13 +83,13 @@ describe HTTP::Headers do
83
83
  it 'appends new value if header exists' do
84
84
  headers.add :set_cookie, 'hoo=ray'
85
85
  headers.add :set_cookie, 'woo=hoo'
86
- expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo]
86
+ expect(headers['Set-Cookie']).to eq %w(hoo=ray woo=hoo)
87
87
  end
88
88
 
89
89
  it 'allows append multiple values' do
90
90
  headers.add :set_cookie, 'hoo=ray'
91
- headers.add :set_cookie, %w[woo=hoo yup=pie]
92
- expect(headers['Set-Cookie']).to eq %w[hoo=ray woo=hoo yup=pie]
91
+ headers.add :set_cookie, %w(woo=hoo yup=pie)
92
+ expect(headers['Set-Cookie']).to eq %w(hoo=ray woo=hoo yup=pie)
93
93
  end
94
94
  end
95
95
 
@@ -97,11 +97,11 @@ describe HTTP::Headers do
97
97
  before { headers.set 'Content-Type', 'application/json' }
98
98
 
99
99
  it 'returns array of associated values' do
100
- expect(headers.get 'Content-Type').to eq %w[application/json]
100
+ expect(headers.get 'Content-Type').to eq %w(application/json)
101
101
  end
102
102
 
103
103
  it 'normalizes header name' do
104
- expect(headers.get :content_type).to eq %w[application/json]
104
+ expect(headers.get :content_type).to eq %w(application/json)
105
105
  end
106
106
 
107
107
  context 'when header does not exists' do
@@ -141,7 +141,7 @@ describe HTTP::Headers do
141
141
  end
142
142
 
143
143
  it 'returns array of associated values' do
144
- expect(headers[:set_cookie]).to eq %w[hoo=ray woo=hoo]
144
+ expect(headers[:set_cookie]).to eq %w(hoo=ray woo=hoo)
145
145
  end
146
146
  end
147
147
  end
@@ -154,11 +154,11 @@ describe HTTP::Headers do
154
154
  end
155
155
 
156
156
  it 'returns a Hash' do
157
- expect(headers.to_h).to be_a Hash
157
+ expect(headers.to_h).to be_a ::Hash
158
158
  end
159
159
 
160
160
  it 'returns Hash with normalized keys' do
161
- expect(headers.to_h.keys).to match_array %w[Content-Type Set-Cookie]
161
+ expect(headers.to_h.keys).to match_array %w(Content-Type Set-Cookie)
162
162
  end
163
163
 
164
164
  context 'for a header with single value' do
@@ -169,7 +169,7 @@ describe HTTP::Headers do
169
169
 
170
170
  context 'for a header with multiple values' do
171
171
  it 'provides an array of values' do
172
- expect(headers.to_h['Set-Cookie']).to eq %w[hoo=ray woo=hoo]
172
+ expect(headers.to_h['Set-Cookie']).to eq %w(hoo=ray woo=hoo)
173
173
  end
174
174
  end
175
175
  end
@@ -187,18 +187,18 @@ describe HTTP::Headers do
187
187
 
188
188
  it 'returns Array of key/value pairs with normalized keys' do
189
189
  expect(headers.to_a).to eq [
190
- %w[Content-Type application/json],
191
- %w[Set-Cookie hoo=ray],
192
- %w[Set-Cookie woo=hoo]
190
+ %w(Content-Type application/json),
191
+ %w(Set-Cookie hoo=ray),
192
+ %w(Set-Cookie woo=hoo)
193
193
  ]
194
194
  end
195
195
  end
196
196
 
197
197
  describe '#inspect' do
198
- before { headers.set :set_cookie, %w[hoo=ray woo=hoo] }
198
+ before { headers.set :set_cookie, %w(hoo=ray woo=hoo) }
199
199
  subject { headers.inspect }
200
200
 
201
- it { should eq '#<HTTP::Headers {"Set-Cookie"=>["hoo=ray", "woo=hoo"]}>' }
201
+ it { is_expected.to eq '#<HTTP::Headers {"Set-Cookie"=>["hoo=ray", "woo=hoo"]}>' }
202
202
  end
203
203
 
204
204
  describe '#keys' do
@@ -209,7 +209,7 @@ describe HTTP::Headers do
209
209
  end
210
210
 
211
211
  it 'returns uniq keys only' do
212
- expect(headers.keys).to have_exactly(2).items
212
+ expect(headers.keys.size).to eq 2
213
213
  end
214
214
 
215
215
  it 'normalizes keys' do
@@ -230,9 +230,9 @@ describe HTTP::Headers do
230
230
 
231
231
  it 'yields headers in the same order they were added' do
232
232
  expect { |b| headers.each(&b) }.to yield_successive_args(
233
- %w[Set-Cookie hoo=ray],
234
- %w[Content-Type application/json],
235
- %w[Set-Cookie woo=hoo]
233
+ %w(Set-Cookie hoo=ray),
234
+ %w(Content-Type application/json),
235
+ %w(Set-Cookie woo=hoo)
236
236
  )
237
237
  end
238
238
  end
@@ -241,12 +241,12 @@ describe HTTP::Headers do
241
241
  subject { headers.empty? }
242
242
 
243
243
  context 'initially' do
244
- it { should be_true }
244
+ it { is_expected.to be true }
245
245
  end
246
246
 
247
247
  context 'when header exists' do
248
248
  before { headers.add :accept, 'text/plain' }
249
- it { should be_false }
249
+ it { is_expected.to be false }
250
250
  end
251
251
 
252
252
  context 'when last header was removed' do
@@ -255,7 +255,7 @@ describe HTTP::Headers do
255
255
  headers.delete :accept
256
256
  end
257
257
 
258
- it { should be_true }
258
+ it { is_expected.to be true }
259
259
  end
260
260
  end
261
261
 
@@ -284,7 +284,7 @@ describe HTTP::Headers do
284
284
 
285
285
  it 'allows comparison with Array of key/value pairs' do
286
286
  left.add :accept, 'text/plain'
287
- expect(left).to eq [%w[Accept text/plain]]
287
+ expect(left).to eq [%w(Accept text/plain)]
288
288
  end
289
289
 
290
290
  it 'sensitive to headers order' do
@@ -311,8 +311,8 @@ describe HTTP::Headers do
311
311
 
312
312
  subject(:dupped) { headers.dup }
313
313
 
314
- it { should be_a described_class }
315
- it { should_not be headers }
314
+ it { is_expected.to be_a described_class }
315
+ it { is_expected.not_to be headers }
316
316
 
317
317
  it 'has headers copied' do
318
318
  expect(dupped[:content_type]).to eq 'application/json'
@@ -335,7 +335,7 @@ describe HTTP::Headers do
335
335
  before do
336
336
  headers.set :host, 'example.com'
337
337
  headers.set :accept, 'application/json'
338
- headers.merge! :accept => 'plain/text', :cookie => %w[hoo=ray woo=hoo]
338
+ headers.merge! :accept => 'plain/text', :cookie => %w(hoo=ray woo=hoo)
339
339
  end
340
340
 
341
341
  it 'leaves headers not presented in other as is' do
@@ -347,7 +347,7 @@ describe HTTP::Headers do
347
347
  end
348
348
 
349
349
  it 'appends other headers, not presented in base' do
350
- expect(headers[:cookie]).to eq %w[hoo=ray woo=hoo]
350
+ expect(headers[:cookie]).to eq %w(hoo=ray woo=hoo)
351
351
  end
352
352
  end
353
353
 
@@ -358,11 +358,11 @@ describe HTTP::Headers do
358
358
  end
359
359
 
360
360
  subject(:merged) do
361
- headers.merge :accept => 'plain/text', :cookie => %w[hoo=ray woo=hoo]
361
+ headers.merge :accept => 'plain/text', :cookie => %w(hoo=ray woo=hoo)
362
362
  end
363
363
 
364
- it { should be_a described_class }
365
- it { should_not be headers }
364
+ it { is_expected.to be_a described_class }
365
+ it { is_expected.not_to be headers }
366
366
 
367
367
  it 'does not affects original headers' do
368
368
  expect(merged.to_h).to_not eq headers.to_h
@@ -377,7 +377,7 @@ describe HTTP::Headers do
377
377
  end
378
378
 
379
379
  it 'appends other headers, not presented in base' do
380
- expect(merged[:cookie]).to eq %w[hoo=ray woo=hoo]
380
+ expect(merged[:cookie]).to eq %w(hoo=ray woo=hoo)
381
381
  end
382
382
  end
383
383
 
@@ -395,7 +395,7 @@ describe HTTP::Headers do
395
395
  end
396
396
 
397
397
  it 'accepts any object that respond to #to_a' do
398
- hashie = double :to_a => [%w[accept json]]
398
+ hashie = double :to_a => [%w(accept json)]
399
399
  expect(described_class.coerce(hashie)['accept']).to eq 'json'
400
400
  end
401
401
 
@@ -408,10 +408,14 @@ describe HTTP::Headers do
408
408
 
409
409
  it 'adds all headers' do
410
410
  expect(described_class.coerce(headers).to_a).to match_array([
411
- %w[Set-Cookie hoo=ray],
412
- %w[Set-Cookie woo=hoo]
411
+ %w(Set-Cookie hoo=ray),
412
+ %w(Set-Cookie woo=hoo)
413
413
  ])
414
414
  end
415
415
  end
416
+
417
+ it 'is aliased as .[]' do
418
+ expect(described_class.method :coerce).to eq described_class.method(:[])
419
+ end
416
420
  end
417
421
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'body' do
3
+ RSpec.describe HTTP::Options, 'body' do
4
4
 
5
5
  let(:opts) { HTTP::Options.new }
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'form' do
3
+ RSpec.describe HTTP::Options, 'form' do
4
4
 
5
5
  let(:opts) { HTTP::Options.new }
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'headers' do
3
+ RSpec.describe HTTP::Options, 'headers' do
4
4
 
5
5
  let(:opts) { HTTP::Options.new }
6
6
 
@@ -11,7 +11,7 @@ describe HTTP::Options, 'headers' do
11
11
  it 'may be specified with with_headers' do
12
12
  opts2 = opts.with_headers('accept' => 'json')
13
13
  expect(opts.headers).to be_empty
14
- expect(opts2.headers).to eq([%w[Accept json]])
14
+ expect(opts2.headers).to eq([%w(Accept json)])
15
15
  end
16
16
 
17
17
  it 'accepts any object that respond to :to_hash' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'json' do
3
+ RSpec.describe HTTP::Options, 'json' do
4
4
 
5
5
  let(:opts) { HTTP::Options.new }
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'merge' do
3
+ RSpec.describe HTTP::Options, 'merge' do
4
4
  let(:opts) { HTTP::Options.new }
5
5
 
6
6
  it 'supports a Hash' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'new' do
3
+ RSpec.describe HTTP::Options, 'new' do
4
4
  it 'supports a Options instance' do
5
5
  opts = HTTP::Options.new
6
6
  expect(HTTP::Options.new(opts)).to eq(opts)
@@ -14,7 +14,7 @@ describe HTTP::Options, 'new' do
14
14
 
15
15
  it 'coerces :headers correctly' do
16
16
  opts = HTTP::Options.new(:headers => {:accept => 'json'})
17
- expect(opts.headers).to eq([%w[Accept json]])
17
+ expect(opts.headers).to eq([%w(Accept json)])
18
18
  end
19
19
 
20
20
  it 'coerces :proxy correctly' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options, 'proxy' do
3
+ RSpec.describe HTTP::Options, 'proxy' do
4
4
 
5
5
  let(:opts) { HTTP::Options.new }
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Options do
3
+ RSpec.describe HTTP::Options do
4
4
  subject { described_class.new(:response => :body) }
5
5
 
6
6
  it 'behaves like a Hash for reading' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Redirector do
3
+ RSpec.describe HTTP::Redirector do
4
4
  def simple_response(status, body = '', headers = {})
5
5
  HTTP::Response.new(status, '1.1', headers, body)
6
6
  end
@@ -2,42 +2,90 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HTTP::Request::Writer do
5
+ RSpec.describe HTTP::Request::Writer do
6
+ let(:io) { StringIO.new }
7
+ let(:body) { '' }
8
+ let(:headers) { HTTP::Headers.new }
9
+ let(:headerstart) { 'GET /test HTTP/1.1' }
10
+
11
+ subject(:writer) { described_class.new(io, body, headers, headerstart) }
12
+
6
13
  describe '#initalize' do
7
- def construct(body)
8
- HTTP::Request::Writer.new(nil, body, [], '')
9
- end
14
+ context 'when body is nil' do
15
+ let(:body) { nil }
10
16
 
11
- it "doesn't throw on a nil body" do
12
- expect { construct nil }.not_to raise_error
17
+ it 'does not raise an error' do
18
+ expect { writer }.not_to raise_error
19
+ end
13
20
  end
14
21
 
15
- it "doesn't throw on a String body" do
16
- expect { construct 'string body' }.not_to raise_error
17
- end
22
+ context 'when body is a string' do
23
+ let(:body) { 'string body' }
18
24
 
19
- it "doesn't throw on an Enumerable body" do
20
- expect { construct %w[bees cows] }.not_to raise_error
25
+ it 'does not raise an error' do
26
+ expect { writer }.not_to raise_error
27
+ end
21
28
  end
22
29
 
23
- it "does throw on a body that isn't string, enumerable or nil" do
24
- expect { construct true }.to raise_error
30
+ context 'when body is an Enumerable' do
31
+ let(:body) { %w(bees cows) }
32
+
33
+ it 'does not raise an error' do
34
+ expect { writer }.not_to raise_error
35
+ end
25
36
  end
26
37
 
27
- it 'writes a chunked request from an Enumerable correctly' do
28
- io = StringIO.new
29
- writer = HTTP::Request::Writer.new(io, %w[bees cows], [], '')
30
- writer.send_request_body
31
- io.rewind
32
- expect(io.string).to eq "4\r\nbees\r\n4\r\ncows\r\n0\r\n\r\n"
38
+ context 'when body is not string, enumerable or nil' do
39
+ let(:body) { 123 }
40
+
41
+ it 'raises an error' do
42
+ expect { writer }.to raise_error
43
+ end
33
44
  end
34
45
  end
35
46
 
36
- describe '#add_body_type_headers' do
37
- it 'properly calculates length of unicode string' do
38
- writer = HTTP::Request::Writer.new(nil, 'Привет, мир!', {}, '')
39
- writer.add_body_type_headers
40
- expect(writer.join_headers).to match(/\r\nContent-Length: 21\r\n/)
47
+ describe '#stream' do
48
+ context 'when body is Enumerable' do
49
+ let(:body) { %w(bees cows) }
50
+ let(:headers) { HTTP::Headers.coerce 'Transfer-Encoding' => 'chunked' }
51
+
52
+ it 'writes a chunked request from an Enumerable correctly' do
53
+ writer.stream
54
+ expect(io.string).to end_with "\r\n4\r\nbees\r\n4\r\ncows\r\n0\r\n\r\n"
55
+ end
56
+
57
+ it 'writes Transfer-Encoding header only once' do
58
+ writer.stream
59
+ expect(io.string).to start_with "#{headerstart}\r\nTransfer-Encoding: chunked\r\n\r\n"
60
+ end
61
+
62
+ context 'when Transfer-Encoding not set' do
63
+ let(:headers) { HTTP::Headers.new }
64
+ specify { expect { writer.stream }.to raise_error }
65
+ end
66
+
67
+ context 'when Transfer-Encoding is not chunked' do
68
+ let(:headers) { HTTP::Headers.coerce 'Transfer-Encoding' => 'gzip' }
69
+ specify { expect { writer.stream }.to raise_error }
70
+ end
71
+ end
72
+
73
+ context 'when body is a unicode String' do
74
+ let(:body) { 'Привет, мир!' }
75
+
76
+ it 'properly calculates Content-Length if needed' do
77
+ writer.stream
78
+ expect(io.string).to start_with "#{headerstart}\r\nContent-Length: 21\r\n\r\n"
79
+ end
80
+
81
+ context 'when Content-Length explicitly set' do
82
+ let(:headers) { HTTP::Headers.coerce 'Content-Length' => 12 }
83
+
84
+ it 'keeps given value' do
85
+ writer.stream
86
+ expect(io.string).to start_with "#{headerstart}\r\nContent-Length: 12\r\n\r\n"
87
+ end
88
+ end
41
89
  end
42
90
  end
43
91
  end