httpkit 0.6.0.pre.3 → 0.6.0.pre.5

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.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/.rspec +0 -1
  3. data/.travis.yml +5 -4
  4. data/Gemfile +0 -2
  5. data/Gemfile.devtools +27 -22
  6. data/README.md +11 -13
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +11 -5
  10. data/config/rubocop.yml +47 -5
  11. data/examples/echo_server.rb +2 -2
  12. data/examples/getting_started.rb +16 -10
  13. data/httpkit.gemspec +5 -4
  14. data/lib/httpkit.rb +15 -5
  15. data/lib/httpkit/body.rb +44 -33
  16. data/lib/httpkit/client.rb +52 -23
  17. data/lib/httpkit/client/body_handler.rb +21 -0
  18. data/lib/httpkit/client/{keep_alive.rb → keep_alive_handler.rb} +1 -1
  19. data/lib/httpkit/client/mandatory_handler.rb +29 -0
  20. data/lib/httpkit/client/{timeouts.rb → timeouts_handler.rb} +1 -1
  21. data/lib/httpkit/connection/eventmachine.rb +4 -4
  22. data/lib/httpkit/request.rb +46 -10
  23. data/lib/httpkit/response.rb +37 -5
  24. data/lib/httpkit/serializer.rb +33 -25
  25. data/lib/httpkit/server.rb +14 -19
  26. data/lib/httpkit/server/body_handler.rb +25 -0
  27. data/lib/httpkit/server/{keep_alive.rb → keep_alive_handler.rb} +22 -13
  28. data/lib/httpkit/server/mandatory_handler.rb +23 -0
  29. data/lib/httpkit/server/{timeouts.rb → timeouts_handler.rb} +1 -1
  30. data/lib/httpkit/support/handler_manager.rb +8 -5
  31. data/lib/httpkit/support/message.rb +28 -15
  32. data/lib/httpkit/version.rb +1 -1
  33. data/spec/integration/keep_alive_spec.rb +6 -7
  34. data/spec/integration/smoke_spec.rb +4 -4
  35. data/spec/integration/streaming_spec.rb +2 -3
  36. data/spec/integration/timeouts_spec.rb +6 -6
  37. data/spec/shared/integration/server_client_pair.rb +1 -1
  38. data/spec/spec_helper.rb +3 -2
  39. data/spec/support/handler.rb +1 -1
  40. data/spec/support/helper.rb +6 -4
  41. data/spec/unit/body_spec.rb +6 -0
  42. data/spec/unit/client/keep_alive_handler_spec.rb +6 -0
  43. data/spec/unit/client/mandatory_handler_spec.rb +31 -0
  44. data/spec/unit/client/timeouts_handler_spec.rb +6 -0
  45. data/spec/unit/client_spec.rb +83 -34
  46. data/spec/unit/connection/eventmachine_spec.rb +12 -13
  47. data/spec/unit/httpkit_spec.rb +65 -24
  48. data/spec/unit/promise_spec.rb +1 -1
  49. data/spec/unit/request_spec.rb +2 -10
  50. data/spec/unit/response_spec.rb +7 -15
  51. data/spec/unit/serializer_spec.rb +83 -0
  52. data/spec/unit/server/{keep_alive_spec.rb → keep_alive_handler_spec.rb} +5 -2
  53. data/spec/unit/server/mandatory_handler_spec.rb +30 -0
  54. data/spec/unit/server/timeouts_handler_spec.rb +6 -0
  55. data/spec/unit/server_spec.rb +26 -32
  56. data/spec/unit/support/handler_manager_spec.rb +38 -7
  57. data/spec/unit/support/message_spec.rb +45 -20
  58. metadata +57 -36
  59. data/lib/httpkit/serializer/encoding.rb +0 -43
@@ -50,7 +50,7 @@ describe HTTPkit::Promise do
50
50
 
51
51
  it 'suspends the fiber until the promise state changes' do
52
52
  expect(@fulfilled).to be(true)
53
- expect(@rejected).to be(true)
53
+ expect(@rejected).to be(true)
54
54
  end
55
55
  end
56
56
  end
@@ -13,7 +13,7 @@ describe HTTPkit::Request do
13
13
  its(:uri) { should eq('/a?b=c') }
14
14
  its(:headers) { should eq('Key' => 'value') }
15
15
 
16
- specify { expect(subject.body.read).to eq('hello') }
16
+ specify { expect(subject.body.to_s).to eq('hello') }
17
17
 
18
18
  describe 'defaults' do
19
19
  subject { HTTPkit::Request.new(:get, '/') }
@@ -21,15 +21,7 @@ describe HTTPkit::Request do
21
21
  its(:headers) { should eq({}) }
22
22
  its(:http_version) { should eq(1.1) }
23
23
 
24
- specify { expect(subject.body.read).to be_empty }
24
+ specify { expect(subject.body.to_s).to be_empty }
25
25
  end
26
26
  end
27
-
28
- describe '#http_version=' do
29
- subject { HTTPkit::Request.new(:get, '/') }
30
-
31
- before { subject.http_version = 1.0 }
32
-
33
- its(:http_version) { should eq(1.0) }
34
- end
35
27
  end
@@ -11,7 +11,7 @@ describe HTTPkit::Response do
11
11
  its(:status) { should be(200) }
12
12
  its(:headers) { should eq('Key' => 'value') }
13
13
 
14
- specify { expect(subject.body.read).to eq('hello') }
14
+ specify { expect(subject.body.to_s).to eq('hello') }
15
15
 
16
16
  its(:status_name) { should eq('OK') }
17
17
 
@@ -21,7 +21,7 @@ describe HTTPkit::Response do
21
21
  its(:headers) { should eq({}) }
22
22
  its(:http_version) { should eq(1.1) }
23
23
 
24
- specify { expect(subject.body.read).to be_empty }
24
+ specify { expect(subject.body.to_s).to be_empty }
25
25
  end
26
26
 
27
27
  describe 'unknown status' do
@@ -32,20 +32,12 @@ describe HTTPkit::Response do
32
32
  end
33
33
  end
34
34
 
35
- describe '#http_version=' do
36
- subject { HTTPkit::Response.new(200) }
37
-
38
- before { subject.http_version = 1.0 }
39
-
40
- its(:http_version) { should eq(1.0) }
41
- end
42
-
43
35
  describe 'with 1xx status' do
44
36
  subject { HTTPkit::Response.new(100) }
45
37
 
46
38
  its(:status_class) { should be(1) }
47
39
 
48
- it { should be_informational }
40
+ it { should be_informational }
49
41
  it { should_not be_successful }
50
42
  it { should_not be_redirection }
51
43
  it { should_not be_client_error }
@@ -64,7 +56,7 @@ describe HTTPkit::Response do
64
56
  its(:status_class) { should be(2) }
65
57
 
66
58
  it { should_not be_informational }
67
- it { should be_successful }
59
+ it { should be_successful }
68
60
  it { should_not be_redirection }
69
61
  it { should_not be_client_error }
70
62
  it { should_not be_server_error }
@@ -77,7 +69,7 @@ describe HTTPkit::Response do
77
69
 
78
70
  it { should_not be_informational }
79
71
  it { should_not be_successful }
80
- it { should be_redirection }
72
+ it { should be_redirection }
81
73
  it { should_not be_client_error }
82
74
  it { should_not be_server_error }
83
75
  end
@@ -90,7 +82,7 @@ describe HTTPkit::Response do
90
82
  it { should_not be_informational }
91
83
  it { should_not be_successful }
92
84
  it { should_not be_redirection }
93
- it { should be_client_error }
85
+ it { should be_client_error }
94
86
  it { should_not be_server_error }
95
87
  end
96
88
 
@@ -103,6 +95,6 @@ describe HTTPkit::Response do
103
95
  it { should_not be_successful }
104
96
  it { should_not be_redirection }
105
97
  it { should_not be_client_error }
106
- it { should be_server_error }
98
+ it { should be_server_error }
107
99
  end
108
100
  end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Serializer do
6
+ shared_context :serializer do
7
+ let(:yielded_chunks) { [] }
8
+ let(:writer) { proc { |chunk| yielded_chunks << chunk } }
9
+
10
+ subject! { described_class.new(message, writer).serialize }
11
+
12
+ it 'serializes' do
13
+ expect(yielded_chunks).to eq(chunks)
14
+ end
15
+ end
16
+
17
+ describe 'with simple request' do
18
+ let(:message) do
19
+ HTTPkit::Request.new(:get, '/asd?k=v', { 'Key' => 'value' }, 'hello')
20
+ end
21
+
22
+ let(:chunks) do
23
+ ["GET /asd?k=v HTTP/1.1\r\n",
24
+ "Key: value\r\n\r\n",
25
+ 'hello']
26
+ end
27
+
28
+ include_context :serializer
29
+ end
30
+
31
+ describe 'with simple response' do
32
+ let(:message) do
33
+ HTTPkit::Response.new(200, { 'Key' => 'value' }, 'hello')
34
+ end
35
+
36
+ let(:chunks) do
37
+ ["HTTP/1.1 200 OK\r\n",
38
+ "Key: value\r\n\r\n",
39
+ 'hello']
40
+ end
41
+
42
+ include_context :serializer
43
+ end
44
+
45
+ describe 'with empty body' do
46
+ let(:message) do
47
+ HTTPkit::Response.new(200, 'Key' => 'value')
48
+ end
49
+
50
+ let(:chunks) do
51
+ ["HTTP/1.1 200 OK\r\n",
52
+ "Key: value\r\n\r\n",
53
+ '']
54
+ end
55
+
56
+ include_context :serializer
57
+ end
58
+
59
+ describe 'with unbounded body', reactor: true do
60
+ let(:message) do
61
+ HTTPkit::Response.new(200, {}, HTTPkit::Body.new)
62
+ end
63
+
64
+ # With a smaller body it's more difficult to test the base 16 conversion.
65
+ let(:hello) { 'hello' * 204 }
66
+
67
+ let(:chunks) do
68
+ ["HTTP/1.1 200 OK\r\n",
69
+ "\r\n",
70
+ "3fc\r\n#{hello}\r\n",
71
+ "0\r\n\r\n"]
72
+ end
73
+
74
+ before do
75
+ EM.next_tick do
76
+ message.body.write(hello)
77
+ message.close
78
+ end
79
+ end
80
+
81
+ include_context :serializer
82
+ end
83
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HTTPkit::Server::KeepAlive do
5
+ describe HTTPkit::Server::KeepAliveHandler do
6
6
  let(:config) { double('config') }
7
7
  let(:server) { double('server') }
8
8
  let(:connection) { double('connection') }
@@ -18,7 +18,10 @@ describe HTTPkit::Server::KeepAlive do
18
18
  before { object.setup(config, server, connection) }
19
19
 
20
20
  describe '#close_connection?' do
21
- before { object.serve(request, served) }
21
+ before do
22
+ allow(request).to receive(:sequence).with(server) { 1 }
23
+ object.serve(request, served)
24
+ end
22
25
 
23
26
  let(:subject) { object.send(:close_connection?, request) }
24
27
 
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Server::MandatoryHandler do
6
+ describe '#respond' do
7
+ let(:handler) { described_class.new }
8
+ let(:response) { HTTPkit::Response.new(200, headers) }
9
+ let(:headers) { {} }
10
+
11
+ subject! do
12
+ handler.respond(nil, response) { |_, res| @response = res }
13
+ end
14
+
15
+ # XXX: remove time-dependence
16
+ it 'sets Server and Date headers' do
17
+ expect(@response.headers['Server']).to eq("httpkit/#{HTTPkit::VERSION}")
18
+ expect(@response.headers['Date']).to eq(Time.now.httpdate)
19
+ end
20
+
21
+ describe 'with Server or Date header set to anything' do
22
+ let(:headers) { { 'Server' => nil, 'Date' => nil } }
23
+
24
+ it 'does not override' do
25
+ expect(@response.headers['Server']).to be(nil)
26
+ expect(@response.headers['Date']).to be(nil)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Server::TimeoutsHandler do
6
+ end
@@ -40,6 +40,18 @@ describe HTTPkit::Server do
40
40
 
41
41
  it 'sets up handlers' do
42
42
  expect(handler).to have_received(:setup).with(config, server, connection)
43
+ expect(config[:handlers].first).to be(handler)
44
+ end
45
+
46
+ describe 'without handlers' do
47
+ let(:config) { {} }
48
+
49
+ it 'adds the mandatory and body handlers' do
50
+ expect(config[:handlers][0])
51
+ .to be_a(HTTPkit::Server::MandatoryHandler)
52
+ expect(config[:handlers][1])
53
+ .to be_a(HTTPkit::Server::BodyHandler)
54
+ end
43
55
  end
44
56
  end
45
57
 
@@ -48,7 +60,7 @@ describe HTTPkit::Server do
48
60
  let(:response) { open_response }
49
61
 
50
62
  before do
51
- allow(server).to receive(:respond)
63
+ allow(server).to receive(:respond)
52
64
  allow(handler).to receive(:serve) { |_, served|
53
65
  @served = served
54
66
  @fiber = Fiber.current
@@ -64,7 +76,7 @@ describe HTTPkit::Server do
64
76
  end
65
77
 
66
78
  it 'notifies the handlers' do
67
- expect(handler).to have_received(:serve)
79
+ expect(handler).to have_received(:serve)
68
80
  .with(request, kind_of(HTTPkit::Promise))
69
81
  expect(@fiber).not_to be(Fiber.current)
70
82
  end
@@ -75,44 +87,24 @@ describe HTTPkit::Server do
75
87
  let(:request) { open_request }
76
88
  let(:response) { open_response(200, headers) }
77
89
 
90
+ before { allow(server).to receive(:finish) }
91
+
78
92
  subject! { server.respond(request, response) }
79
93
 
80
94
  it 'writes response to underlying connection' do
81
- expect(connection).to have_received(:serialize).with(response)
95
+ expect(connection)
96
+ .to have_received(:serialize).with(kind_of(response.class))
82
97
  end
83
98
 
84
99
  it 'notifies the handlers' do
85
- expect(handler).to have_received(:respond).with(request, response)
100
+ expect(handler)
101
+ .to have_received(:respond).with(kind_of(request.class),
102
+ kind_of(response.class))
86
103
  end
87
104
 
88
- it 'sets Server and Date headers' do
89
- expect(headers['Server']).to eq("httpkit/#{HTTPkit::VERSION}")
90
- expect(headers['Date']).to eq(Time.now.httpdate)
91
- end
92
-
93
- describe 'with Server or Date header set to anything' do
94
- let(:headers) { { 'Server' => nil, 'Date' => nil } }
95
-
96
- it 'does not override' do
97
- expect(headers['Server']).to be(nil)
98
- expect(headers['Date']).to be(nil)
99
- end
100
- end
101
-
102
- describe 'wiring', reactor: true do
103
- let(:request) { closed_request }
104
- let(:response) { open_response }
105
-
106
- before do
107
- allow(server).to receive(:finish)
108
-
109
- response.close
110
- tick
111
- end
112
-
113
- it 'wires up #finish' do
114
- expect(server).to have_received(:finish).with(request)
115
- end
105
+ it 'wires up #finish' do
106
+ expect(server)
107
+ .to have_received(:finish).with(kind_of(request.class))
116
108
  end
117
109
  end
118
110
 
@@ -125,4 +117,6 @@ describe HTTPkit::Server do
125
117
  expect(handler).to have_received(:finish).with(request)
126
118
  end
127
119
  end
120
+
121
+ describe '#setup_connection'
128
122
  end
@@ -4,18 +4,49 @@ require 'spec_helper'
4
4
 
5
5
  describe HTTPkit::Support::HandlerManager do
6
6
  let(:handler) { double('handler', message: nil) }
7
- let(:manager) { described_class.new([handler]) }
7
+ let(:handler2) { double('handler2', message: nil) }
8
+ let(:manager) { described_class.new([handler, handler2]) }
8
9
 
9
- describe '#notify' do
10
+ describe '#invoke' do
10
11
  let(:args) { [double, double] }
12
+ let(:args2) { [double, double] }
11
13
 
12
- subject! do
13
- manager.notify(:message, *args)
14
- manager.notify(:nope)
14
+ describe 'with arguments' do
15
+ subject! do
16
+ manager.invoke(:nonexisting)
17
+ manager.invoke(:message, *args)
18
+ end
19
+
20
+ it 'sends message to the handlers' do
21
+ expect(handler).to have_received(:message).with(*args)
22
+ expect(handler2).to have_received(:message).with(*args)
23
+ end
24
+
25
+ it 'returns the arguments' do
26
+ expect(subject).to eq(args)
27
+ end
15
28
  end
16
29
 
17
- it 'notifies the handlers' do
18
- expect(handler).to have_received(:message).with(*args)
30
+ describe 'with yielding handler' do
31
+ let(:non_array) { double }
32
+
33
+ before do
34
+ allow(handler).to receive(:message).and_yield(*args2)
35
+ allow(handler2).to receive(:message).and_yield(non_array)
36
+ end
37
+
38
+ subject! do
39
+ manager.invoke(:message, *args)
40
+ end
41
+
42
+ it 'updates arguments for next handler' do
43
+ expect(handler).to have_received(:message).with(*args)
44
+ expect(handler2).to have_received(:message).with(*args2)
45
+ end
46
+
47
+ it 'returns the updated arguments' do
48
+ expect(subject).to eq([non_array])
49
+ end
19
50
  end
20
51
  end
21
52
  end
@@ -63,15 +63,34 @@ describe HTTPkit::Support::Message do
63
63
  end
64
64
  end
65
65
 
66
- describe '#add_extra_headers' do
67
- subject! { message.add_extra_headers(foo: '456', bar: '789') }
66
+ describe '.build' do
67
+ before do
68
+ allow(message).to receive(:body_present?) { true }
69
+ allow(message).to receive(:body_included?) { true }
70
+ end
71
+
72
+ shared_context :message do
73
+ describe 'without body present' do
74
+ before do
75
+ allow(message).to receive(:body_present?) { false }
76
+ end
68
77
 
69
- it 'adds the headers that do not exist yet' do
70
- expect(message.headers).to eq(foo: '456', bar: '123')
78
+ it 'closes the message' do
79
+ expect(subject).to be_closed
80
+ end
81
+ end
82
+
83
+ describe 'without body included' do
84
+ before do
85
+ allow(message).to receive(:body_included?) { false }
86
+ end
87
+
88
+ it 'closes the message' do
89
+ expect(subject).to be_closed
90
+ end
91
+ end
71
92
  end
72
- end
73
93
 
74
- describe '.build' do
75
94
  before do
76
95
  allow(HTTPkit::Body).to receive(:new) { body }
77
96
  end
@@ -81,17 +100,20 @@ describe HTTPkit::Support::Message do
81
100
  Struct.new(:http_method, :request_url, :headers, :http_version)
82
101
  .new('GET', '/', { 'Key' => 'value' }, [1, 1])
83
102
  end
84
- let(:args) { [:get, '/', { 'Key' => 'value' }, body] }
85
- let(:request) { double }
103
+ let(:args) { [:get, '/', { 'Key' => 'value' }, body, 1.1] }
104
+
105
+ before do
106
+ allow(HTTPkit::Request)
107
+ .to receive(:new).with(*args).and_return(message)
108
+ end
86
109
 
87
110
  subject { HTTPkit::Support::Message.build(parser) }
88
111
 
89
- it 'returns a Request object' do
90
- expect(HTTPkit::Request)
91
- .to receive(:new).with(*args).and_return(request)
92
- expect(request).to receive(:http_version=).with(1.1)
93
- expect(subject).to be(request)
112
+ it 'returns the Request object' do
113
+ expect(subject).to be(message)
94
114
  end
115
+
116
+ include_context :message
95
117
  end
96
118
 
97
119
  describe 'given a parser holding a response' do
@@ -99,17 +121,20 @@ describe HTTPkit::Support::Message do
99
121
  Struct.new(:http_method, :status_code, :headers, :http_version)
100
122
  .new(nil, 200, { 'Key' => 'value' }, [1, 0])
101
123
  end
102
- let(:args) { [200, { 'Key' => 'value' }, body] }
103
- let(:response) { double }
124
+ let(:args) { [200, { 'Key' => 'value' }, body, 1.0] }
104
125
 
105
126
  subject { HTTPkit::Support::Message.build(parser) }
106
127
 
107
- it 'returns a Response object' do
108
- expect(HTTPkit::Response)
109
- .to receive(:new).with(*args).and_return(response)
110
- expect(response).to receive(:http_version=).with(1.0)
111
- expect(subject).to be(response)
128
+ before do
129
+ allow(HTTPkit::Response)
130
+ .to receive(:new).with(*args).and_return(message)
131
+ end
132
+
133
+ it 'returns the Response object' do
134
+ expect(subject).to be(message)
112
135
  end
136
+
137
+ include_context :message
113
138
  end
114
139
  end
115
140
  end