httpkit 0.6.0.pre.3

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. data/.gitignore +7 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +19 -0
  6. data/Gemfile.devtools +67 -0
  7. data/Procfile +1 -0
  8. data/README.md +66 -0
  9. data/Rakefile +5 -0
  10. data/UNLICENSE +24 -0
  11. data/config/devtools.yml +2 -0
  12. data/config/flay.yml +3 -0
  13. data/config/flog.yml +2 -0
  14. data/config/mutant.yml +3 -0
  15. data/config/reek.yml +114 -0
  16. data/config/rubocop.yml +56 -0
  17. data/config/yardstick.yml +2 -0
  18. data/examples/echo_server.rb +36 -0
  19. data/examples/getting_started.rb +34 -0
  20. data/httpkit.gemspec +27 -0
  21. data/lib/httpkit/body.rb +67 -0
  22. data/lib/httpkit/client/keep_alive.rb +10 -0
  23. data/lib/httpkit/client/timeouts.rb +14 -0
  24. data/lib/httpkit/client.rb +94 -0
  25. data/lib/httpkit/connection/eventmachine.rb +72 -0
  26. data/lib/httpkit/connection/status.rb +28 -0
  27. data/lib/httpkit/promise.rb +19 -0
  28. data/lib/httpkit/request.rb +19 -0
  29. data/lib/httpkit/response.rb +110 -0
  30. data/lib/httpkit/serializer/encoding.rb +43 -0
  31. data/lib/httpkit/serializer.rb +75 -0
  32. data/lib/httpkit/server/keep_alive.rb +58 -0
  33. data/lib/httpkit/server/timeouts.rb +13 -0
  34. data/lib/httpkit/server.rb +62 -0
  35. data/lib/httpkit/support/handler_manager.rb +25 -0
  36. data/lib/httpkit/support/message.rb +66 -0
  37. data/lib/httpkit/version.rb +5 -0
  38. data/lib/httpkit.rb +49 -0
  39. data/spec/integration/error_handling_spec.rb +76 -0
  40. data/spec/integration/keep_alive_spec.rb +101 -0
  41. data/spec/integration/smoke_spec.rb +21 -0
  42. data/spec/integration/streaming_spec.rb +57 -0
  43. data/spec/integration/timeouts_spec.rb +82 -0
  44. data/spec/shared/integration/server_client_pair.rb +29 -0
  45. data/spec/spec_helper.rb +45 -0
  46. data/spec/support/handler.rb +48 -0
  47. data/spec/support/helper.rb +70 -0
  48. data/spec/unit/client_spec.rb +230 -0
  49. data/spec/unit/connection/eventmachine_spec.rb +211 -0
  50. data/spec/unit/connection/status_spec.rb +83 -0
  51. data/spec/unit/httpkit_spec.rb +41 -0
  52. data/spec/unit/promise_spec.rb +56 -0
  53. data/spec/unit/request_spec.rb +35 -0
  54. data/spec/unit/response_spec.rb +108 -0
  55. data/spec/unit/server/keep_alive_spec.rb +69 -0
  56. data/spec/unit/server_spec.rb +128 -0
  57. data/spec/unit/support/handler_manager_spec.rb +21 -0
  58. data/spec/unit/support/message_spec.rb +115 -0
  59. metadata +190 -0
@@ -0,0 +1,108 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Response do
6
+ describe '#initialize' do
7
+ subject do
8
+ HTTPkit::Response.new(200, { 'Key' => 'value' }, 'hello').freeze
9
+ end
10
+
11
+ its(:status) { should be(200) }
12
+ its(:headers) { should eq('Key' => 'value') }
13
+
14
+ specify { expect(subject.body.read).to eq('hello') }
15
+
16
+ its(:status_name) { should eq('OK') }
17
+
18
+ describe 'defaults' do
19
+ subject { HTTPkit::Response.new(200) }
20
+
21
+ its(:headers) { should eq({}) }
22
+ its(:http_version) { should eq(1.1) }
23
+
24
+ specify { expect(subject.body.read).to be_empty }
25
+ end
26
+
27
+ describe 'unknown status' do
28
+ subject { HTTPkit::Response.new(-1) }
29
+
30
+ its(:status) { should be(-1) }
31
+ its(:status_name) { should eq('Unknown Status') }
32
+ end
33
+ end
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
+ describe 'with 1xx status' do
44
+ subject { HTTPkit::Response.new(100) }
45
+
46
+ its(:status_class) { should be(1) }
47
+
48
+ it { should be_informational }
49
+ it { should_not be_successful }
50
+ it { should_not be_redirection }
51
+ it { should_not be_client_error }
52
+ it { should_not be_server_error }
53
+ end
54
+
55
+ describe 'with 199 status' do
56
+ subject { HTTPkit::Response.new(199) }
57
+
58
+ its(:status_class) { should be(1) }
59
+ end
60
+
61
+ describe 'with 2xx status' do
62
+ subject { HTTPkit::Response.new(200) }
63
+
64
+ its(:status_class) { should be(2) }
65
+
66
+ it { should_not be_informational }
67
+ it { should be_successful }
68
+ it { should_not be_redirection }
69
+ it { should_not be_client_error }
70
+ it { should_not be_server_error }
71
+ end
72
+
73
+ describe 'with 3xx status' do
74
+ subject { HTTPkit::Response.new(300) }
75
+
76
+ its(:status_class) { should be(3) }
77
+
78
+ it { should_not be_informational }
79
+ it { should_not be_successful }
80
+ it { should be_redirection }
81
+ it { should_not be_client_error }
82
+ it { should_not be_server_error }
83
+ end
84
+
85
+ describe 'with 4xx status' do
86
+ subject { HTTPkit::Response.new(400) }
87
+
88
+ its(:status_class) { should be(4) }
89
+
90
+ it { should_not be_informational }
91
+ it { should_not be_successful }
92
+ it { should_not be_redirection }
93
+ it { should be_client_error }
94
+ it { should_not be_server_error }
95
+ end
96
+
97
+ describe 'with 5xx status' do
98
+ subject { HTTPkit::Response.new(500) }
99
+
100
+ its(:status_class) { should be(5) }
101
+
102
+ it { should_not be_informational }
103
+ it { should_not be_successful }
104
+ it { should_not be_redirection }
105
+ it { should_not be_client_error }
106
+ it { should be_server_error }
107
+ end
108
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Server::KeepAlive do
6
+ let(:config) { double('config') }
7
+ let(:server) { double('server') }
8
+ let(:connection) { double('connection') }
9
+
10
+ let(:object) { described_class.new }
11
+ let(:request) do
12
+ double('request', http_version: http_version,
13
+ headers: { 'Connection' => header })
14
+ end
15
+ let(:served) { double('served', value: response) }
16
+ let(:response) { double('response', headers: { 'Connection' => header }) }
17
+
18
+ before { object.setup(config, server, connection) }
19
+
20
+ describe '#close_connection?' do
21
+ before { object.serve(request, served) }
22
+
23
+ let(:subject) { object.send(:close_connection?, request) }
24
+
25
+ describe 'with HTTP/1.0 request' do
26
+ let(:http_version) { 1.0 }
27
+
28
+ describe 'and no header' do
29
+ let(:header) { nil }
30
+
31
+ it { should be(true) }
32
+ end
33
+
34
+ describe 'and Connection: close' do
35
+ let(:header) { 'close' }
36
+
37
+ it { should be(true) }
38
+ end
39
+
40
+ describe 'and Connection: keep-alive' do
41
+ let(:header) { 'keep-alive' }
42
+
43
+ it { should be(false) }
44
+ end
45
+ end
46
+
47
+ describe 'with HTTP/1.1 request' do
48
+ let(:http_version) { 1.1 }
49
+
50
+ describe 'and no header' do
51
+ let(:header) { nil }
52
+
53
+ it { should be(false) }
54
+ end
55
+
56
+ describe 'and Connection: close' do
57
+ let(:header) { 'close' }
58
+
59
+ it { should be(true) }
60
+ end
61
+
62
+ describe 'and Connection: keep-alive' do
63
+ let(:header) { 'keep-alive' }
64
+
65
+ it { should be(false) }
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Server do
6
+ let(:server) { described_class.new(config, connection) }
7
+
8
+ let(:config) do
9
+ { address: localhost, port: random_port, handlers: [handler] }
10
+ end
11
+ let(:connection) do
12
+ double('connection', :'on_message=' => nil,
13
+ closed: double('closed', then: nil),
14
+ serialize: nil,
15
+ close: nil)
16
+ end
17
+ let(:handler) do
18
+ double('handler', setup: nil, respond: nil, finish: nil)
19
+ end
20
+
21
+ describe '.start' do
22
+ subject { described_class.start(config) }
23
+
24
+ it 'binds an EventMachine-backed server instance' do
25
+ expect(HTTPkit::Connection::EventMachine)
26
+ .to receive(:start_server).with(config, described_class)
27
+ subject
28
+ end
29
+ end
30
+
31
+ describe '#initialize' do
32
+ subject! { server }
33
+
34
+ its(:config) { should be(config) }
35
+
36
+ it 'sets up connection' do
37
+ expect(connection).to have_received(:on_message=)
38
+ .with(server.method(:serve))
39
+ end
40
+
41
+ it 'sets up handlers' do
42
+ expect(handler).to have_received(:setup).with(config, server, connection)
43
+ end
44
+ end
45
+
46
+ describe '#serve', reactor: true do
47
+ let(:request) { open_request }
48
+ let(:response) { open_response }
49
+
50
+ before do
51
+ allow(server).to receive(:respond)
52
+ allow(handler).to receive(:serve) { |_, served|
53
+ @served = served
54
+ @fiber = Fiber.current
55
+ }
56
+ end
57
+
58
+ subject! { server.serve(request) }
59
+
60
+ it 'sets up correlation' do
61
+ @served.fulfill(response)
62
+ tick
63
+ expect(server).to have_received(:respond).with(request, response)
64
+ end
65
+
66
+ it 'notifies the handlers' do
67
+ expect(handler).to have_received(:serve)
68
+ .with(request, kind_of(HTTPkit::Promise))
69
+ expect(@fiber).not_to be(Fiber.current)
70
+ end
71
+ end
72
+
73
+ describe '#respond' do
74
+ let(:headers) { {} }
75
+ let(:request) { open_request }
76
+ let(:response) { open_response(200, headers) }
77
+
78
+ subject! { server.respond(request, response) }
79
+
80
+ it 'writes response to underlying connection' do
81
+ expect(connection).to have_received(:serialize).with(response)
82
+ end
83
+
84
+ it 'notifies the handlers' do
85
+ expect(handler).to have_received(:respond).with(request, response)
86
+ end
87
+
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
116
+ end
117
+ end
118
+
119
+ describe '#finish' do
120
+ let(:request) { open_request }
121
+
122
+ subject! { server.finish(request) }
123
+
124
+ it 'notifies the handlers' do
125
+ expect(handler).to have_received(:finish).with(request)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Support::HandlerManager do
6
+ let(:handler) { double('handler', message: nil) }
7
+ let(:manager) { described_class.new([handler]) }
8
+
9
+ describe '#notify' do
10
+ let(:args) { [double, double] }
11
+
12
+ subject! do
13
+ manager.notify(:message, *args)
14
+ manager.notify(:nope)
15
+ end
16
+
17
+ it 'notifies the handlers' do
18
+ expect(handler).to have_received(:message).with(*args)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Support::Message do
6
+ let(:message) do
7
+ double('message', headers: { bar: '123' }, body: body)
8
+ .extend(described_class)
9
+ end
10
+
11
+ let(:body) do
12
+ double('body', closed: double('closed', pending?: pending,
13
+ sync: double,
14
+ then: nil,
15
+ fulfill: nil,
16
+ reject: nil))
17
+ end
18
+
19
+ let(:pending) { false }
20
+
21
+ describe '#closed?' do
22
+ subject { message.closed? }
23
+
24
+ it { should be(true) }
25
+
26
+ describe do
27
+ let(:pending) { true }
28
+
29
+ it { should be(false) }
30
+ end
31
+ end
32
+
33
+ describe '#closed!' do
34
+ subject { message.closed! }
35
+
36
+ it { should be(body.closed.sync) }
37
+ end
38
+
39
+ describe '#closed' do
40
+ subject { message.closed { throw :block } }
41
+
42
+ it 'forwards' do
43
+ expect(body.closed).to receive(:then) { |&block|
44
+ expect(block).to throw_symbol(:block)
45
+ }
46
+ subject
47
+ end
48
+ end
49
+
50
+ describe '#close' do
51
+ subject! { message.close }
52
+
53
+ it 'forwards' do
54
+ expect(body.closed).to have_received(:fulfill)
55
+ end
56
+ end
57
+
58
+ describe '#reject_closed' do
59
+ subject! { message.reject_closed(StandardError) }
60
+
61
+ it 'forwards' do
62
+ expect(body.closed).to have_received(:reject).with(StandardError)
63
+ end
64
+ end
65
+
66
+ describe '#add_extra_headers' do
67
+ subject! { message.add_extra_headers(foo: '456', bar: '789') }
68
+
69
+ it 'adds the headers that do not exist yet' do
70
+ expect(message.headers).to eq(foo: '456', bar: '123')
71
+ end
72
+ end
73
+
74
+ describe '.build' do
75
+ before do
76
+ allow(HTTPkit::Body).to receive(:new) { body }
77
+ end
78
+
79
+ describe 'given a parser holding a request' do
80
+ let(:parser) do
81
+ Struct.new(:http_method, :request_url, :headers, :http_version)
82
+ .new('GET', '/', { 'Key' => 'value' }, [1, 1])
83
+ end
84
+ let(:args) { [:get, '/', { 'Key' => 'value' }, body] }
85
+ let(:request) { double }
86
+
87
+ subject { HTTPkit::Support::Message.build(parser) }
88
+
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)
94
+ end
95
+ end
96
+
97
+ describe 'given a parser holding a response' do
98
+ let(:parser) do
99
+ Struct.new(:http_method, :status_code, :headers, :http_version)
100
+ .new(nil, 200, { 'Key' => 'value' }, [1, 0])
101
+ end
102
+ let(:args) { [200, { 'Key' => 'value' }, body] }
103
+ let(:response) { double }
104
+
105
+ subject { HTTPkit::Support::Message.build(parser) }
106
+
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)
112
+ end
113
+ end
114
+ end
115
+ end
metadata ADDED
@@ -0,0 +1,190 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: httpkit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0.pre.3
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Lars Gierth
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: http_parser.rb
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: promise.rb
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.6'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: HTTPkit is a Ruby toolkit for building HTTP clients and servers, as well
79
+ as compositions of them.
80
+ email:
81
+ - lars.gierth@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - .rspec
88
+ - .travis.yml
89
+ - .yardopts
90
+ - Gemfile
91
+ - Gemfile.devtools
92
+ - Procfile
93
+ - README.md
94
+ - Rakefile
95
+ - UNLICENSE
96
+ - config/devtools.yml
97
+ - config/flay.yml
98
+ - config/flog.yml
99
+ - config/mutant.yml
100
+ - config/reek.yml
101
+ - config/rubocop.yml
102
+ - config/yardstick.yml
103
+ - examples/echo_server.rb
104
+ - examples/getting_started.rb
105
+ - httpkit.gemspec
106
+ - lib/httpkit.rb
107
+ - lib/httpkit/body.rb
108
+ - lib/httpkit/client.rb
109
+ - lib/httpkit/client/keep_alive.rb
110
+ - lib/httpkit/client/timeouts.rb
111
+ - lib/httpkit/connection/eventmachine.rb
112
+ - lib/httpkit/connection/status.rb
113
+ - lib/httpkit/promise.rb
114
+ - lib/httpkit/request.rb
115
+ - lib/httpkit/response.rb
116
+ - lib/httpkit/serializer.rb
117
+ - lib/httpkit/serializer/encoding.rb
118
+ - lib/httpkit/server.rb
119
+ - lib/httpkit/server/keep_alive.rb
120
+ - lib/httpkit/server/timeouts.rb
121
+ - lib/httpkit/support/handler_manager.rb
122
+ - lib/httpkit/support/message.rb
123
+ - lib/httpkit/version.rb
124
+ - spec/integration/error_handling_spec.rb
125
+ - spec/integration/keep_alive_spec.rb
126
+ - spec/integration/smoke_spec.rb
127
+ - spec/integration/streaming_spec.rb
128
+ - spec/integration/timeouts_spec.rb
129
+ - spec/shared/integration/server_client_pair.rb
130
+ - spec/spec_helper.rb
131
+ - spec/support/handler.rb
132
+ - spec/support/helper.rb
133
+ - spec/unit/client_spec.rb
134
+ - spec/unit/connection/eventmachine_spec.rb
135
+ - spec/unit/connection/status_spec.rb
136
+ - spec/unit/httpkit_spec.rb
137
+ - spec/unit/promise_spec.rb
138
+ - spec/unit/request_spec.rb
139
+ - spec/unit/response_spec.rb
140
+ - spec/unit/server/keep_alive_spec.rb
141
+ - spec/unit/server_spec.rb
142
+ - spec/unit/support/handler_manager_spec.rb
143
+ - spec/unit/support/message_spec.rb
144
+ homepage: https://github.com/lgierth/httpkit
145
+ licenses:
146
+ - Public Domain
147
+ post_install_message:
148
+ rdoc_options: []
149
+ require_paths:
150
+ - lib
151
+ required_ruby_version: !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ! '>='
155
+ - !ruby/object:Gem::Version
156
+ version: '0'
157
+ required_rubygems_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ! '>'
161
+ - !ruby/object:Gem::Version
162
+ version: 1.3.1
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 1.8.23
166
+ signing_key:
167
+ specification_version: 3
168
+ summary: The HTTP toolkit for Ruby
169
+ test_files:
170
+ - spec/integration/error_handling_spec.rb
171
+ - spec/integration/keep_alive_spec.rb
172
+ - spec/integration/smoke_spec.rb
173
+ - spec/integration/streaming_spec.rb
174
+ - spec/integration/timeouts_spec.rb
175
+ - spec/shared/integration/server_client_pair.rb
176
+ - spec/spec_helper.rb
177
+ - spec/support/handler.rb
178
+ - spec/support/helper.rb
179
+ - spec/unit/client_spec.rb
180
+ - spec/unit/connection/eventmachine_spec.rb
181
+ - spec/unit/connection/status_spec.rb
182
+ - spec/unit/httpkit_spec.rb
183
+ - spec/unit/promise_spec.rb
184
+ - spec/unit/request_spec.rb
185
+ - spec/unit/response_spec.rb
186
+ - spec/unit/server/keep_alive_spec.rb
187
+ - spec/unit/server_spec.rb
188
+ - spec/unit/support/handler_manager_spec.rb
189
+ - spec/unit/support/message_spec.rb
190
+ has_rdoc: