hatetepe 0.6.0.pre.1 → 0.6.0.pre.2
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.
- data/.travis.yml +7 -1
- data/.yardopts +2 -1
- data/Gemfile +6 -0
- data/Gemfile.devtools +23 -11
- data/Procfile +1 -0
- data/README.md +34 -25
- data/config/devtools.yml +1 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +5 -1
- data/config/rubocop.yml +2 -8
- data/examples/echo_server.rb +41 -0
- data/examples/getting_started.rb +34 -0
- data/hatetepe.gemspec +1 -1
- data/lib/hatetepe/body.rb +5 -0
- data/lib/hatetepe/client/keep_alive.rb +0 -4
- data/lib/hatetepe/client/timeouts.rb +3 -8
- data/lib/hatetepe/client.rb +20 -9
- data/lib/hatetepe/connection/eventmachine.rb +5 -2
- data/lib/hatetepe/promise.rb +5 -31
- data/lib/hatetepe/response.rb +24 -0
- data/lib/hatetepe/serializer/encoding.rb +4 -11
- data/lib/hatetepe/serializer.rb +19 -4
- data/lib/hatetepe/server/keep_alive.rb +1 -1
- data/lib/hatetepe/server/timeouts.rb +2 -6
- data/lib/hatetepe/server.rb +17 -7
- data/lib/hatetepe/support/handlers.rb +1 -3
- data/lib/hatetepe/support/message.rb +5 -1
- data/lib/hatetepe/version.rb +1 -1
- data/lib/hatetepe.rb +17 -0
- data/spec/integration/keep_alive_spec.rb +1 -1
- data/spec/spec_helper.rb +11 -10
- data/spec/support/handler.rb +0 -3
- data/spec/support/helper.rb +7 -8
- data/spec/unit/client_spec.rb +68 -8
- data/spec/unit/connection/eventmachine_spec.rb +3 -2
- data/spec/unit/server/keep_alive_spec.rb +3 -1
- data/spec/unit/server_spec.rb +47 -13
- metadata +10 -11
- data/bin/hatetepe +0 -33
- data/spec/integration/error_handling_spec.rb +0 -7
data/.travis.yml
CHANGED
data/.yardopts
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
- LICENSE
|
1
|
+
- LICENSE.txt
|
2
|
+
- examples/*
|
data/Gemfile
CHANGED
@@ -9,5 +9,11 @@ gem 'fuubar', git: 'https://github.com/lgierth/fuubar.git',
|
|
9
9
|
ref: 'static-percentage'
|
10
10
|
gem 'awesome_print'
|
11
11
|
|
12
|
+
platform :rbx do
|
13
|
+
gem 'rubysl-fiber', '~> 2.0'
|
14
|
+
gem 'rubysl-weakref', '~> 2.0'
|
15
|
+
gem 'rubinius', '~> 2.0'
|
16
|
+
end
|
17
|
+
|
12
18
|
# Added by devtools
|
13
19
|
eval_gemfile 'Gemfile.devtools'
|
data/Gemfile.devtools
CHANGED
@@ -4,6 +4,10 @@ group :development do
|
|
4
4
|
gem 'rake', '~> 10.1.0'
|
5
5
|
gem 'rspec', '~> 2.14.1'
|
6
6
|
gem 'yard', '~> 0.8.7'
|
7
|
+
|
8
|
+
platform :rbx do
|
9
|
+
gem 'rubysl-singleton', '~> 2.0.0'
|
10
|
+
end
|
7
11
|
end
|
8
12
|
|
9
13
|
group :yard do
|
@@ -11,14 +15,13 @@ group :yard do
|
|
11
15
|
end
|
12
16
|
|
13
17
|
group :guard do
|
14
|
-
gem 'guard', '~>
|
15
|
-
gem 'guard-bundler', '~>
|
16
|
-
gem 'guard-rspec', '~>
|
17
|
-
gem 'guard-rubocop', '~> 0.
|
18
|
-
gem 'guard-mutant', '~> 0.0.1'
|
18
|
+
gem 'guard', '~> 2.2.4'
|
19
|
+
gem 'guard-bundler', '~> 2.0.0'
|
20
|
+
gem 'guard-rspec', '~> 4.0.4'
|
21
|
+
gem 'guard-rubocop', '~> 1.0.0'
|
19
22
|
|
20
23
|
# file system change event handling
|
21
|
-
gem 'listen', '~>
|
24
|
+
gem 'listen', '~> 2.2.0'
|
22
25
|
gem 'rb-fchange', '~> 0.0.6', require: false
|
23
26
|
gem 'rb-fsevent', '~> 0.9.3', require: false
|
24
27
|
gem 'rb-inotify', '~> 0.9.0', require: false
|
@@ -30,18 +33,27 @@ group :guard do
|
|
30
33
|
end
|
31
34
|
|
32
35
|
group :metrics do
|
33
|
-
gem 'coveralls', '~> 0.
|
36
|
+
gem 'coveralls', '~> 0.7.0'
|
34
37
|
gem 'flay', '~> 2.4.0'
|
35
|
-
gem 'flog', '~> 4.
|
38
|
+
gem 'flog', '~> 4.2.0'
|
36
39
|
gem 'reek', '~> 1.3.2'
|
37
|
-
gem 'rubocop', '~> 0.
|
38
|
-
gem 'simplecov', '~> 0.
|
40
|
+
gem 'rubocop', '~> 0.15.0'
|
41
|
+
gem 'simplecov', '~> 0.8.2'
|
39
42
|
gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
|
40
43
|
|
41
44
|
platforms :ruby_19, :ruby_20 do
|
42
|
-
gem 'mutant', git: 'https://github.com/mbj/mutant.git'
|
45
|
+
gem 'mutant', '~> 0.3.0.rc3', git: 'https://github.com/mbj/mutant.git'
|
46
|
+
gem 'unparser', '~> 0.1.5', git: 'https://github.com/mbj/unparser.git'
|
43
47
|
gem 'yard-spellcheck', '~> 0.1.5'
|
44
48
|
end
|
49
|
+
|
50
|
+
platform :rbx do
|
51
|
+
gem 'json', '~> 1.8.1'
|
52
|
+
gem 'racc', '~> 1.4.10'
|
53
|
+
gem 'rubysl-logger', '~> 2.0.0'
|
54
|
+
gem 'rubysl-open-uri', '~> 2.0.0'
|
55
|
+
gem 'rubysl-prettyprint', '~> 2.0.2'
|
56
|
+
end
|
45
57
|
end
|
46
58
|
|
47
59
|
group :benchmarks do
|
data/Procfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
web: env PORT=$PORT ADDRESS=0.0.0.0 bundle exec ruby examples/echo_server.rb
|
data/README.md
CHANGED
@@ -1,9 +1,19 @@
|
|
1
|
-
#
|
1
|
+
# The HTTP toolkit [](https://travis-ci.org/lgierth/hatetepe) [](https://codeclimate.com/github/lgierth/hatetepe) [](https://coveralls.io/r/lgierth/hatetepe?branch=master)
|
2
2
|
|
3
|
-
|
3
|
+
Hatetepe is a Ruby toolkit for building HTTP clients and servers,
|
4
|
+
as well as compositions of them.
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
- \#1 feature: readable, high-quality, extendable code with 61.11% mutation coverage (wip)
|
7
|
+
- \#2 feature: sophisticated request and response streaming
|
8
|
+
- \#3 feature: compatible with Rack, Faraday, and Webmachine for Ruby (todo)
|
9
|
+
- \#4 feature: concurrenct or non-concurrent
|
10
|
+
- Non-concurrent using one-off EventMachine reactor (clients only)
|
11
|
+
- Evented using EventMachine
|
12
|
+
- Synchronously evented using EventMachine and Fibers
|
13
|
+
- Threaded using Celluloid (todo)
|
14
|
+
|
15
|
+
*Note:* The `master` branch contains the latest development effort. Look at the
|
16
|
+
`0.5.x` branch for stable, but very old releases.
|
7
17
|
|
8
18
|
## Installation
|
9
19
|
|
@@ -21,30 +31,29 @@ Or install it yourself as:
|
|
21
31
|
|
22
32
|
## Usage
|
23
33
|
|
24
|
-
|
34
|
+
Code examples
|
35
|
+
|
36
|
+
- [Getting started ](http://rubydoc.info/github/lgierth/hatetepe/master/file/examples/getting_started.rb)
|
37
|
+
- [HTTP echo server](http://rubydoc.info/github/lgierth/hatetepe/master/file/examples/echo_server.rb)
|
38
|
+
|
39
|
+
API Reference
|
40
|
+
|
41
|
+
- [Hatetepe::Client ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Client)
|
42
|
+
- [Hatetepe::Server ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Server)
|
43
|
+
- [Hatetepe::Response ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Request)
|
44
|
+
- [Hatetepe::Request ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Response)
|
45
|
+
- [Hatetepe::Body ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Body)
|
46
|
+
- [Hatetepe::Promise ](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Promise)
|
47
|
+
- [Hatetepe::Serializer](http://rubydoc.info/github/lgierth/hatetepe/master/Hatetepe/Serializer)
|
25
48
|
|
26
49
|
## To do
|
27
50
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
- Documentation
|
35
|
-
- Future
|
36
|
-
- SSL support
|
37
|
-
- Webmachine adapter
|
38
|
-
- Request/Response pass-through
|
39
|
-
- Graceful shutdown
|
40
|
-
- Celluloid::IO backend
|
41
|
-
- Circuit breaker
|
42
|
-
- Nice to have
|
43
|
-
- Rack handler
|
44
|
-
- Faraday adapter
|
45
|
-
- Following redirects
|
46
|
-
- Proxy support
|
47
|
-
- Client handling multipart responses
|
51
|
+
Here: https://trello.com/b/OoxEq1ze/hatetepe
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
Hatetepe is licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
56
|
+
See LICENSE.txt for details.
|
48
57
|
|
49
58
|
## Contributing
|
50
59
|
|
data/config/devtools.yml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
---
|
2
|
-
unit_test_timeout: 0.
|
2
|
+
unit_test_timeout: 0.0
|
data/config/flay.yml
CHANGED
data/config/flog.yml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
---
|
2
|
-
threshold:
|
2
|
+
threshold: 10.0
|
data/config/reek.yml
CHANGED
@@ -34,6 +34,8 @@ LongParameterList:
|
|
34
34
|
overrides:
|
35
35
|
initialize:
|
36
36
|
max_params: 4
|
37
|
+
setup:
|
38
|
+
max_params: 3
|
37
39
|
LongYieldList:
|
38
40
|
enabled: true
|
39
41
|
exclude: []
|
@@ -57,7 +59,7 @@ TooManyInstanceVariables:
|
|
57
59
|
TooManyMethods:
|
58
60
|
enabled: true
|
59
61
|
exclude: []
|
60
|
-
max_methods:
|
62
|
+
max_methods: 11
|
61
63
|
TooManyStatements:
|
62
64
|
enabled: true
|
63
65
|
exclude:
|
@@ -95,6 +97,8 @@ UncommunicativeVariableName:
|
|
95
97
|
- !ruby/regexp /[0-9]$/
|
96
98
|
- !ruby/regexp /[A-Z]/
|
97
99
|
accept:
|
100
|
+
- k
|
101
|
+
- v
|
98
102
|
- a
|
99
103
|
- e
|
100
104
|
- _
|
data/config/rubocop.yml
CHANGED
@@ -24,14 +24,8 @@ CollectionMethods:
|
|
24
24
|
find: 'detect'
|
25
25
|
find_all: 'select'
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
# because I think when scanning code it makes it easier to identify the
|
30
|
-
# sections of code and visually separate them. When the keyword is at the same
|
31
|
-
# level I think it sort of blends in with the def keywords and makes it harder
|
32
|
-
# to scan the code and see where the sections are.
|
33
|
-
AccessControl:
|
34
|
-
Enabled: false
|
27
|
+
AccessModifierIndentation:
|
28
|
+
EnforcedStyle: indent
|
35
29
|
|
36
30
|
# Limit line length
|
37
31
|
LineLength:
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hatetepe'
|
4
|
+
|
5
|
+
class EchoServer
|
6
|
+
def serve(request, served)
|
7
|
+
response = streaming_response
|
8
|
+
served.fulfill(response)
|
9
|
+
|
10
|
+
serialize(request, response)
|
11
|
+
request.closed { response.close }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def streaming_response
|
17
|
+
Hatetepe::Response.new(200, { 'Content-Type' => 'text/plain' },
|
18
|
+
Hatetepe::Body.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize(request, response)
|
22
|
+
writer = response.body.closed.method(:progress)
|
23
|
+
serializer = Hatetepe::Serializer.new(request, writer)
|
24
|
+
serializer.serialize
|
25
|
+
end
|
26
|
+
|
27
|
+
def writer(response)
|
28
|
+
proc { |data| response.body.closed.progress(data) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Hatetepe.run do
|
33
|
+
Hatetepe::Server.start(address: ENV.fetch('ADDRESS', '127.0.0.1'),
|
34
|
+
port: ENV.fetch('PORT', 3000).to_i,
|
35
|
+
handlers: [Hatetepe::Server::KeepAlive, EchoServer])
|
36
|
+
|
37
|
+
terminated = Hatetepe::Promise.new
|
38
|
+
Signal.trap(:INT) { terminated.fulfill }
|
39
|
+
Signal.trap(:TERM) { terminated.fulfill }
|
40
|
+
terminated.sync
|
41
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'hatetepe'
|
4
|
+
|
5
|
+
class HelloServer
|
6
|
+
def serve(request, served)
|
7
|
+
p request.http_method # => :get
|
8
|
+
p request.uri # => "/"
|
9
|
+
p request.headers # => {"Host"=>"127.0.0.1:3000",
|
10
|
+
# "Content-Length"=>"0"}
|
11
|
+
p request.body.to_s # => ""
|
12
|
+
|
13
|
+
served.fulfill(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
def response
|
17
|
+
Hatetepe::Response.new(200, { 'Content-Type' => 'text/plain' }, 'hello')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Hatetepe.run do
|
22
|
+
Hatetepe::Server.start(address: '127.0.0.1', port: 3000,
|
23
|
+
handlers: [HelloServer])
|
24
|
+
|
25
|
+
client = Hatetepe::Client.new(address: '127.0.0.1', port: 3000)
|
26
|
+
|
27
|
+
response = client.request(:get, '/')
|
28
|
+
|
29
|
+
p response.status # => 200
|
30
|
+
p response.status_name # => "OK"
|
31
|
+
p response.headers # => {"Content-Type"=>"text/plain",
|
32
|
+
# "Content-Length"=>"5"}
|
33
|
+
p response.body.to_s # => "hello"
|
34
|
+
end
|
data/hatetepe.gemspec
CHANGED
data/lib/hatetepe/body.rb
CHANGED
@@ -15,6 +15,7 @@ module Hatetepe
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
# TODO: eliminate string param
|
18
19
|
def initialize(string = '')
|
19
20
|
@io = StringIO.new(string)
|
20
21
|
|
@@ -49,6 +50,10 @@ module Hatetepe
|
|
49
50
|
@io.string
|
50
51
|
end
|
51
52
|
|
53
|
+
def string
|
54
|
+
@io.string
|
55
|
+
end
|
56
|
+
|
52
57
|
private
|
53
58
|
|
54
59
|
def optimized_read?(length)
|
@@ -3,17 +3,12 @@
|
|
3
3
|
module Hatetepe
|
4
4
|
# @see EM.heartbeat_interval
|
5
5
|
class Client::Timeouts
|
6
|
-
def
|
6
|
+
def setup(config, _, connection)
|
7
7
|
@config = config
|
8
8
|
@connection = connection
|
9
9
|
|
10
|
-
@config[:timeout] ||= 2.0
|
11
|
-
@config[:connect_timeout] ||= 2.0
|
12
|
-
end
|
13
|
-
|
14
|
-
def setup
|
15
|
-
@connection.comm_inactivity_timeout = @config[:timeout]
|
16
|
-
@connection.pending_connect_timeout = @config[:connect_timeout]
|
10
|
+
@connection.comm_inactivity_timeout = @config[:timeout] ||= 2.0
|
11
|
+
@connection.pending_connect_timeout = @config[:connect_timeout] ||= 2.0
|
17
12
|
end
|
18
13
|
end
|
19
14
|
end
|
data/lib/hatetepe/client.rb
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
module Hatetepe
|
4
4
|
class Client
|
5
|
+
USER_AGENT = 'User-Agent'.freeze
|
6
|
+
USER_AGENT_VALUE = "hatetepe/#{Hatetepe::VERSION}".freeze
|
7
|
+
HOST = 'Host'.freeze
|
8
|
+
HOST_VALUE = '%s:%d'.freeze
|
9
|
+
|
5
10
|
include Support::Handlers
|
6
11
|
include Connection::Status
|
7
12
|
|
@@ -13,11 +18,11 @@ module Hatetepe
|
|
13
18
|
|
14
19
|
setup_connection
|
15
20
|
setup_handlers
|
16
|
-
notify_handlers(:setup)
|
21
|
+
notify_handlers(:setup, @config, self, @connection)
|
17
22
|
end
|
18
23
|
|
19
|
-
def request(
|
20
|
-
request = Request.new(
|
24
|
+
def request(*args)
|
25
|
+
request = Request.new(*args)
|
21
26
|
perform(request).sync
|
22
27
|
end
|
23
28
|
|
@@ -25,7 +30,9 @@ module Hatetepe
|
|
25
30
|
served = Promise.new
|
26
31
|
@requests << [request, served]
|
27
32
|
|
33
|
+
add_extra_headers(request)
|
28
34
|
Fiber.new { perform!(request) }.resume
|
35
|
+
|
29
36
|
served
|
30
37
|
end
|
31
38
|
|
@@ -33,13 +40,12 @@ module Hatetepe
|
|
33
40
|
request, served = correlate
|
34
41
|
|
35
42
|
served.fulfill(response)
|
36
|
-
response.closed { finish(request) }
|
37
|
-
|
38
43
|
notify_handlers(:receive, request, response)
|
44
|
+
response.closed { finish(request) }
|
39
45
|
end
|
40
46
|
|
41
47
|
def finish(request)
|
42
|
-
@requests.delete_if { |(req
|
48
|
+
@requests.delete_if { |(req)| req == request }
|
43
49
|
notify_handlers(:finish, request)
|
44
50
|
end
|
45
51
|
|
@@ -48,7 +54,7 @@ module Hatetepe
|
|
48
54
|
end
|
49
55
|
|
50
56
|
def teardown(reason)
|
51
|
-
@requests.each do |
|
57
|
+
@requests.each do |_, served|
|
52
58
|
served.reject(reason)
|
53
59
|
if (response = served.value)
|
54
60
|
response.reject_closed(reason)
|
@@ -58,14 +64,19 @@ module Hatetepe
|
|
58
64
|
|
59
65
|
private
|
60
66
|
|
67
|
+
def add_extra_headers(request)
|
68
|
+
host = sprintf(HOST_VALUE, config[:address], config[:port])
|
69
|
+
request.add_extra_headers(USER_AGENT => USER_AGENT_VALUE, HOST => host)
|
70
|
+
end
|
71
|
+
|
61
72
|
def perform!(request)
|
62
73
|
notify_handlers(:perform, request)
|
63
74
|
@connection.serialize(request)
|
64
75
|
end
|
65
76
|
|
66
77
|
def correlate
|
67
|
-
tuple = @requests.detect { |
|
68
|
-
|
78
|
+
tuple = @requests.detect { |_, served| served.pending? }
|
79
|
+
fail ClientError, 'Unable to correlate with request' unless tuple
|
69
80
|
tuple
|
70
81
|
end
|
71
82
|
|
@@ -17,11 +17,13 @@ module Hatetepe
|
|
17
17
|
|
18
18
|
def serialize(message)
|
19
19
|
serializer = Serializer.new(message, method(:send_data))
|
20
|
+
serializer.setup_body
|
20
21
|
serializer.serialize
|
21
22
|
end
|
22
23
|
|
23
24
|
def receive_data(data)
|
24
|
-
#
|
25
|
+
# p [__id__, :receive, data]
|
26
|
+
# p data
|
25
27
|
@parser << data
|
26
28
|
# rescue => error
|
27
29
|
# $stderr.puts(error.to_s)
|
@@ -30,7 +32,8 @@ module Hatetepe
|
|
30
32
|
end
|
31
33
|
|
32
34
|
# def send_data(data)
|
33
|
-
#
|
35
|
+
# # p [__id__, :send, data]
|
36
|
+
# p data
|
34
37
|
# super
|
35
38
|
# end
|
36
39
|
|
data/lib/hatetepe/promise.rb
CHANGED
@@ -4,48 +4,22 @@ module Hatetepe
|
|
4
4
|
class Promise < ::Promise
|
5
5
|
include ::Promise::Progress
|
6
6
|
|
7
|
-
|
8
|
-
super(value)
|
9
|
-
end
|
10
|
-
|
11
|
-
def reject(reason = nil)
|
12
|
-
super(reason)
|
13
|
-
end
|
14
|
-
|
15
|
-
def sync
|
16
|
-
if fulfilled?
|
17
|
-
return value
|
18
|
-
elsif rejected?
|
19
|
-
return reason
|
20
|
-
end
|
7
|
+
private
|
21
8
|
|
22
|
-
|
9
|
+
def defer
|
10
|
+
EM.next_tick { yield }
|
23
11
|
end
|
24
12
|
|
25
|
-
def
|
13
|
+
def wait
|
26
14
|
fiber = Fiber.current
|
27
15
|
resume = proc do |arg|
|
28
|
-
|
29
|
-
# fiber.resume(arg)
|
16
|
+
defer { fiber.resume(arg) }
|
30
17
|
end
|
31
18
|
|
32
19
|
self.then(resume, resume)
|
33
20
|
Fiber.yield
|
34
21
|
end
|
35
22
|
|
36
|
-
private
|
37
|
-
|
38
|
-
def defer(callback, arg)
|
39
|
-
EM.next_tick { safe_dispatch(callback, arg) }
|
40
|
-
# safe_dispatch(callback, arg)
|
41
|
-
end
|
42
|
-
|
43
|
-
def safe_dispatch(callback, arg)
|
44
|
-
callback.dispatch(arg)
|
45
|
-
# rescue => error
|
46
|
-
# ...
|
47
|
-
end
|
48
|
-
|
49
23
|
module Attribute
|
50
24
|
def self.included(klass)
|
51
25
|
klass.extend(ClassMethods)
|
data/lib/hatetepe/response.rb
CHANGED
@@ -16,6 +16,30 @@ module Hatetepe
|
|
16
16
|
STATUS_NAMES[status.to_i] || UNKNOWN_STATUS
|
17
17
|
end
|
18
18
|
|
19
|
+
def status_class
|
20
|
+
status / 100
|
21
|
+
end
|
22
|
+
|
23
|
+
def informational?
|
24
|
+
status_class == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def successful?
|
28
|
+
status_class == 2
|
29
|
+
end
|
30
|
+
|
31
|
+
def redirection?
|
32
|
+
status_class == 3
|
33
|
+
end
|
34
|
+
|
35
|
+
def client_error?
|
36
|
+
status_class == 4
|
37
|
+
end
|
38
|
+
|
39
|
+
def server_error?
|
40
|
+
status_class == 5
|
41
|
+
end
|
42
|
+
|
19
43
|
UNKNOWN_STATUS = 'Unknown Status'.freeze
|
20
44
|
|
21
45
|
STATUS_NAMES =
|
@@ -8,15 +8,6 @@ module Hatetepe
|
|
8
8
|
CRLF = "\r\n".freeze
|
9
9
|
CONTENT_LENGTH = 'Content-Length'.freeze
|
10
10
|
|
11
|
-
def setup_body
|
12
|
-
if body.closed.pending?
|
13
|
-
setup_chunked_encoding
|
14
|
-
setup_chunked_streaming
|
15
|
-
else
|
16
|
-
setup_identity_encoding
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
11
|
def setup_chunked_encoding
|
21
12
|
headers.delete(CONTENT_LENGTH)
|
22
13
|
headers[TRANSFER_ENCODING] = CHUNKED
|
@@ -33,7 +24,9 @@ module Hatetepe
|
|
33
24
|
end
|
34
25
|
|
35
26
|
def write_body
|
36
|
-
if headers.key?(
|
27
|
+
if headers.key?(TRANSFER_ENCODING)
|
28
|
+
write_chunk(body.string)
|
29
|
+
else
|
37
30
|
write(body.to_s)
|
38
31
|
end
|
39
32
|
end
|
@@ -43,7 +36,7 @@ module Hatetepe
|
|
43
36
|
end
|
44
37
|
|
45
38
|
def write_chunk!(chunk)
|
46
|
-
write(chunk.bytesize, CRLF, chunk, CRLF)
|
39
|
+
write(chunk.bytesize.to_s(16), CRLF, chunk, CRLF)
|
47
40
|
end
|
48
41
|
end
|
49
42
|
end
|
data/lib/hatetepe/serializer.rb
CHANGED
@@ -21,18 +21,25 @@ module Hatetepe
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def serialize
|
24
|
-
setup_body
|
25
|
-
|
26
24
|
write(banana_line)
|
27
25
|
write(header_block)
|
28
26
|
|
29
27
|
write_body
|
30
28
|
end
|
31
29
|
|
30
|
+
def setup_body
|
31
|
+
if body.closed.pending?
|
32
|
+
setup_chunked_encoding
|
33
|
+
setup_chunked_streaming
|
34
|
+
else
|
35
|
+
setup_identity_encoding
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
32
39
|
private
|
33
40
|
|
34
41
|
def write(*data)
|
35
|
-
|
42
|
+
@writer.call(data.join(''))
|
36
43
|
end
|
37
44
|
|
38
45
|
def banana_line
|
@@ -54,7 +61,15 @@ module Hatetepe
|
|
54
61
|
end
|
55
62
|
|
56
63
|
def header_block
|
57
|
-
headers.reduce('') { |a, e| a <<
|
64
|
+
headers.reduce('') { |a, e| a << header_line(*e) } + CRLF
|
65
|
+
end
|
66
|
+
|
67
|
+
def header_line(key, value)
|
68
|
+
if value.to_s.empty?
|
69
|
+
''
|
70
|
+
else
|
71
|
+
sprintf(HEADER, key, value)
|
72
|
+
end
|
58
73
|
end
|
59
74
|
end
|
60
75
|
end
|
@@ -3,15 +3,11 @@
|
|
3
3
|
module Hatetepe
|
4
4
|
# @see EM.heartbeat_interval
|
5
5
|
class Server::Timeouts
|
6
|
-
def
|
6
|
+
def setup(config, _, connection)
|
7
7
|
@config = config
|
8
8
|
@connection = connection
|
9
9
|
|
10
|
-
@config[:timeout] ||= 2.0
|
11
|
-
end
|
12
|
-
|
13
|
-
def setup
|
14
|
-
@connection.comm_inactivity_timeout = @config[:timeout]
|
10
|
+
@connection.comm_inactivity_timeout = @config[:timeout] ||= 2.0
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
data/lib/hatetepe/server.rb
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module Hatetepe
|
4
4
|
class Server
|
5
|
+
SERVER = 'Server'.freeze
|
6
|
+
SERVER_VALUE = "hatetepe/#{Hatetepe::VERSION}".freeze
|
7
|
+
DATE = 'Date'.freeze
|
8
|
+
|
5
9
|
def self.start(config)
|
6
10
|
callback = proc { |connection| new(config, connection) }
|
7
11
|
EM.start_server(config[:address], config[:port],
|
@@ -18,7 +22,7 @@ module Hatetepe
|
|
18
22
|
|
19
23
|
setup_connection(connection)
|
20
24
|
setup_handlers
|
21
|
-
notify_handlers(:setup)
|
25
|
+
notify_handlers(:setup, @config, self, @connection)
|
22
26
|
end
|
23
27
|
|
24
28
|
def serve(request)
|
@@ -30,8 +34,8 @@ module Hatetepe
|
|
30
34
|
|
31
35
|
def respond(request, response)
|
32
36
|
fiber = Fiber.new do
|
33
|
-
|
34
|
-
|
37
|
+
add_extra_headers(response)
|
38
|
+
respond!(request, response)
|
35
39
|
response.closed { finish(request) }
|
36
40
|
end
|
37
41
|
fiber.resume
|
@@ -47,13 +51,19 @@ module Hatetepe
|
|
47
51
|
|
48
52
|
private
|
49
53
|
|
54
|
+
def add_extra_headers(response)
|
55
|
+
date = Time.now.httpdate
|
56
|
+
response.add_extra_headers(SERVER => SERVER_VALUE, DATE => date)
|
57
|
+
end
|
58
|
+
|
59
|
+
def respond!(request, response)
|
60
|
+
notify_handlers(:respond, request, response)
|
61
|
+
@connection.serialize(response)
|
62
|
+
end
|
63
|
+
|
50
64
|
def setup_connection(connection)
|
51
65
|
@connection = connection
|
52
66
|
@connection.parse(method(:serve))
|
53
|
-
@connection.closed.then(method(:shutdown))
|
54
|
-
end
|
55
|
-
|
56
|
-
def shutdown(_)
|
57
67
|
end
|
58
68
|
end
|
59
69
|
end
|
@@ -4,9 +4,7 @@ module Hatetepe
|
|
4
4
|
module Support
|
5
5
|
module Handlers
|
6
6
|
def setup_handlers
|
7
|
-
@handlers = @config[:handlers].map
|
8
|
-
klass.new(@config, self, @connection)
|
9
|
-
end
|
7
|
+
@handlers = (@config[:handlers] || []).map(&:new)
|
10
8
|
end
|
11
9
|
|
12
10
|
def notify_handlers(hook, *args)
|
@@ -23,6 +23,10 @@ module Hatetepe
|
|
23
23
|
body.closed.reject(reason)
|
24
24
|
end
|
25
25
|
|
26
|
+
def add_extra_headers(extra)
|
27
|
+
extra.each { |k, v| headers.key?(k) || headers[k] = v }
|
28
|
+
end
|
29
|
+
|
26
30
|
def self.build(parser)
|
27
31
|
if parser.http_method
|
28
32
|
build_request(parser)
|
@@ -31,7 +35,7 @@ module Hatetepe
|
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
|
-
|
38
|
+
private
|
35
39
|
|
36
40
|
def self.build_request(parser)
|
37
41
|
request = Request.new(http_method_from(parser),
|
data/lib/hatetepe/version.rb
CHANGED
data/lib/hatetepe.rb
CHANGED
@@ -4,6 +4,7 @@ require 'eventmachine'
|
|
4
4
|
require 'fiber'
|
5
5
|
require 'promise'
|
6
6
|
require 'http/parser'
|
7
|
+
require 'time'
|
7
8
|
|
8
9
|
require 'hatetepe/version'
|
9
10
|
|
@@ -27,3 +28,19 @@ require 'hatetepe/client/timeouts'
|
|
27
28
|
require 'hatetepe/server'
|
28
29
|
require 'hatetepe/server/keep_alive'
|
29
30
|
require 'hatetepe/server/timeouts'
|
31
|
+
|
32
|
+
module Hatetepe
|
33
|
+
def self.run
|
34
|
+
EM.run do
|
35
|
+
Fiber.new do
|
36
|
+
yield
|
37
|
+
stop
|
38
|
+
end.resume
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.stop
|
43
|
+
EM.stop
|
44
|
+
EM.next_tick {}
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -28,20 +28,21 @@ RSpec.configure do |config|
|
|
28
28
|
config.include(SpecHelper)
|
29
29
|
|
30
30
|
config.around do |example|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
EM.next_tick {}
|
36
|
-
end
|
31
|
+
stop = proc do
|
32
|
+
EM.stop
|
33
|
+
EM.next_tick {}
|
34
|
+
end
|
37
35
|
|
36
|
+
EM.run do
|
38
37
|
EM.add_timer(0.5) do
|
39
|
-
|
40
|
-
|
41
|
-
raise 'Example timed out'
|
38
|
+
stop.call
|
39
|
+
fail 'Example timed out'
|
42
40
|
end
|
43
41
|
|
44
|
-
|
42
|
+
Fiber.new do
|
43
|
+
example.call
|
44
|
+
stop.call
|
45
|
+
end.resume
|
45
46
|
end
|
46
47
|
end
|
47
48
|
end
|
data/spec/support/handler.rb
CHANGED
data/spec/support/helper.rb
CHANGED
@@ -53,10 +53,7 @@ module SpecHelper
|
|
53
53
|
|
54
54
|
def server_client_pair(server_config, client_config, interceptor)
|
55
55
|
server = nil
|
56
|
-
inspect_server(server_config)
|
57
|
-
server = s
|
58
|
-
interceptor
|
59
|
-
end
|
56
|
+
inspect_server(server_config, interceptor) { |_, s, _| server = s }
|
60
57
|
|
61
58
|
config = { address: localhost, port: random_port }
|
62
59
|
Hatetepe::Server.start(config.merge(server_config))
|
@@ -66,9 +63,11 @@ module SpecHelper
|
|
66
63
|
[server, client]
|
67
64
|
end
|
68
65
|
|
69
|
-
def inspect_server(server_config, &block)
|
70
|
-
|
71
|
-
allow(
|
72
|
-
|
66
|
+
def inspect_server(server_config, interceptor, &block)
|
67
|
+
klass = double
|
68
|
+
allow(klass).to receive(:new) { interceptor }
|
69
|
+
allow(interceptor).to receive(:setup, &block)
|
70
|
+
|
71
|
+
server_config[:handlers].unshift(klass)
|
73
72
|
end
|
74
73
|
end
|
data/spec/unit/client_spec.rb
CHANGED
@@ -15,7 +15,9 @@ describe Hatetepe::Client do
|
|
15
15
|
close: nil)
|
16
16
|
end
|
17
17
|
let(:handler_class) { double('handler_class', new: handler) }
|
18
|
-
let(:handler)
|
18
|
+
let(:handler) do
|
19
|
+
double('handler', setup: nil, receive: nil, finish: nil)
|
20
|
+
end
|
19
21
|
|
20
22
|
before do
|
21
23
|
allow(EM).to receive(:connect) { connection }
|
@@ -37,9 +39,8 @@ describe Hatetepe::Client do
|
|
37
39
|
end
|
38
40
|
|
39
41
|
specify do
|
40
|
-
expect(
|
42
|
+
expect(handler).to have_received(:setup)
|
41
43
|
.with(config, subject, connection)
|
42
|
-
expect(handler).to have_received(:setup)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
@@ -66,7 +67,7 @@ describe Hatetepe::Client do
|
|
66
67
|
end
|
67
68
|
|
68
69
|
describe '#perform' do
|
69
|
-
let(:request) { double('request') }
|
70
|
+
let(:request) { double('request', add_extra_headers: nil) }
|
70
71
|
|
71
72
|
before do
|
72
73
|
@fibers = []
|
@@ -82,6 +83,10 @@ describe Hatetepe::Client do
|
|
82
83
|
|
83
84
|
expect(@fibers).not_to include(Fiber.current)
|
84
85
|
expect(@fibers.uniq).to be_one
|
86
|
+
|
87
|
+
expect(request).to have_received(:add_extra_headers)
|
88
|
+
.with('User-Agent' => "hatetepe/#{Hatetepe::VERSION}",
|
89
|
+
'Host' => "#{config[:address]}:#{config[:port]}")
|
85
90
|
end
|
86
91
|
end
|
87
92
|
|
@@ -94,19 +99,29 @@ describe Hatetepe::Client do
|
|
94
99
|
end
|
95
100
|
|
96
101
|
describe '#receive' do
|
97
|
-
let(:request)
|
98
|
-
let(:
|
102
|
+
let(:request) { open_request }
|
103
|
+
let(:other_request) { open_request }
|
104
|
+
let(:response) { open_response }
|
105
|
+
let(:other_response) { open_response }
|
99
106
|
|
100
107
|
describe 'with outstanding request' do
|
101
|
-
let!(:served)
|
108
|
+
let!(:served) { client.perform(request) }
|
109
|
+
let!(:other_served) { client.perform(other_request) }
|
102
110
|
|
103
|
-
subject!
|
111
|
+
subject! do
|
112
|
+
client.receive(response)
|
113
|
+
client.receive(other_response)
|
114
|
+
end
|
104
115
|
|
105
116
|
it 'correlates response with request, and notifies handlers' do
|
106
117
|
expect(served).to be_fulfilled
|
107
118
|
expect(served.value).to be(response)
|
119
|
+
expect(other_served).to be_fulfilled
|
120
|
+
expect(other_served.value).to be(other_response)
|
108
121
|
|
109
122
|
expect(handler).to have_received(:receive).with(request, response)
|
123
|
+
expect(handler)
|
124
|
+
.to have_received(:receive).with(other_request, other_response)
|
110
125
|
end
|
111
126
|
end
|
112
127
|
|
@@ -118,6 +133,27 @@ describe Hatetepe::Client do
|
|
118
133
|
end
|
119
134
|
end
|
120
135
|
|
136
|
+
describe 'wiring' do
|
137
|
+
let(:request) { open_request }
|
138
|
+
let(:response) { open_response }
|
139
|
+
|
140
|
+
before do
|
141
|
+
client.perform(request)
|
142
|
+
|
143
|
+
allow(client).to receive(:finish)
|
144
|
+
end
|
145
|
+
|
146
|
+
subject! do
|
147
|
+
client.receive(response)
|
148
|
+
response.close
|
149
|
+
tick
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'wires up #finish' do
|
153
|
+
client.should have_received(:finish).with(request)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
121
157
|
[:fulfill, :reject].each do |action|
|
122
158
|
describe "after #{action}ed response" do
|
123
159
|
let(:request) { WeakRef.new(closed_request) }
|
@@ -146,6 +182,30 @@ describe Hatetepe::Client do
|
|
146
182
|
end
|
147
183
|
end
|
148
184
|
|
185
|
+
describe '#finish' do
|
186
|
+
let(:request) { open_request }
|
187
|
+
let(:other_request) { open_request }
|
188
|
+
let(:response) { open_response }
|
189
|
+
|
190
|
+
before do
|
191
|
+
client.perform(request)
|
192
|
+
client.perform(other_request)
|
193
|
+
end
|
194
|
+
|
195
|
+
subject! do
|
196
|
+
client.finish(request)
|
197
|
+
client.receive(response)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'removes the request' do
|
201
|
+
expect(handler).to have_received(:receive).with(other_request, response)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'notifies the handlers' do
|
205
|
+
expect(handler).to have_received(:finish).with(request)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
149
209
|
describe '#teardown' do
|
150
210
|
let(:requests) { [closed_request, closed_request] }
|
151
211
|
let(:responses) { [open_response] }
|
@@ -6,7 +6,7 @@ describe Hatetepe::Connection::EventMachine do
|
|
6
6
|
let(:connection) { described_class.allocate }
|
7
7
|
let(:callback) { double('callback', call: nil) }
|
8
8
|
let(:parser) { double('parser', :<< => nil) }
|
9
|
-
let(:serializer) { double('serializer', serialize: nil) }
|
9
|
+
let(:serializer) { double('serializer', setup_body: nil, serialize: nil) }
|
10
10
|
let(:message) { open_request }
|
11
11
|
|
12
12
|
before do
|
@@ -51,7 +51,8 @@ describe Hatetepe::Connection::EventMachine do
|
|
51
51
|
|
52
52
|
it 'feeds a serializer' do
|
53
53
|
expect(Hatetepe::Serializer).to have_received(:new).with(message, writer)
|
54
|
-
expect(serializer).to
|
54
|
+
expect(serializer).to have_received(:setup_body)
|
55
|
+
expect(serializer).to have_received(:serialize)
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -7,7 +7,7 @@ describe Hatetepe::Server::KeepAlive do
|
|
7
7
|
let(:server) { double('server') }
|
8
8
|
let(:connection) { double('connection') }
|
9
9
|
|
10
|
-
let(:object) { described_class.new
|
10
|
+
let(:object) { described_class.new }
|
11
11
|
let(:request) do
|
12
12
|
double('request', http_version: http_version,
|
13
13
|
headers: { 'Connection' => header })
|
@@ -15,6 +15,8 @@ describe Hatetepe::Server::KeepAlive do
|
|
15
15
|
let(:served) { double('served', value: response) }
|
16
16
|
let(:response) { double('response', headers: { 'Connection' => header }) }
|
17
17
|
|
18
|
+
before { object.setup(config, server, connection) }
|
19
|
+
|
18
20
|
describe '#close_connection?' do
|
19
21
|
before { object.serve(request, served) }
|
20
22
|
|
data/spec/unit/server_spec.rb
CHANGED
@@ -15,7 +15,9 @@ describe Hatetepe::Server do
|
|
15
15
|
close: nil)
|
16
16
|
end
|
17
17
|
let(:handler_class) { double('handler_class', new: handler) }
|
18
|
-
let(:handler)
|
18
|
+
let(:handler) do
|
19
|
+
double('handler', setup: nil, respond: nil, finish: nil)
|
20
|
+
end
|
19
21
|
|
20
22
|
describe '.start' do
|
21
23
|
specify { pending }
|
@@ -27,16 +29,11 @@ describe Hatetepe::Server do
|
|
27
29
|
its(:config) { should be(config) }
|
28
30
|
|
29
31
|
it 'sets up connection' do
|
30
|
-
expect(connection).to
|
31
|
-
.with(server.method(:serve))
|
32
|
-
expect(connection.closed).to have_received(:then)
|
33
|
-
.with(server.method(:shutdown))
|
32
|
+
expect(connection).to have_received(:parse).with(server.method(:serve))
|
34
33
|
end
|
35
34
|
|
36
35
|
it 'sets up handlers' do
|
37
|
-
expect(
|
38
|
-
.with(config, server, connection)
|
39
|
-
expect(handler).to have_received(:setup)
|
36
|
+
expect(handler).to have_received(:setup).with(config, server, connection)
|
40
37
|
end
|
41
38
|
end
|
42
39
|
|
@@ -68,8 +65,9 @@ describe Hatetepe::Server do
|
|
68
65
|
end
|
69
66
|
|
70
67
|
describe '#respond' do
|
68
|
+
let(:headers) { {} }
|
71
69
|
let(:request) { open_request }
|
72
|
-
let(:response) { open_response }
|
70
|
+
let(:response) { open_response(200, headers) }
|
73
71
|
|
74
72
|
subject! { server.respond(request, response) }
|
75
73
|
|
@@ -80,6 +78,46 @@ describe Hatetepe::Server do
|
|
80
78
|
it 'notifies the handlers' do
|
81
79
|
expect(handler).to have_received(:respond).with(request, response)
|
82
80
|
end
|
81
|
+
|
82
|
+
it 'sets Server and Date headers' do
|
83
|
+
expect(headers['Server']).to eq("hatetepe/#{Hatetepe::VERSION}")
|
84
|
+
expect(headers['Date']).to eq(Time.now.httpdate)
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'with Server or Date header set to anything' do
|
88
|
+
let(:headers) { { 'Server' => nil, 'Date' => nil } }
|
89
|
+
|
90
|
+
it 'does not override' do
|
91
|
+
expect(headers['Server']).to be(nil)
|
92
|
+
expect(headers['Date']).to be(nil)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'wiring' do
|
97
|
+
let(:request) { open_request }
|
98
|
+
let(:response) { open_response }
|
99
|
+
|
100
|
+
before do
|
101
|
+
allow(server).to receive(:finish)
|
102
|
+
|
103
|
+
response.close
|
104
|
+
tick
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'wires up #finish' do
|
108
|
+
expect(server).to have_received(:finish).with(request)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#finish' do
|
114
|
+
let(:request) { open_request }
|
115
|
+
|
116
|
+
subject! { server.finish(request) }
|
117
|
+
|
118
|
+
it 'notifies the handlers' do
|
119
|
+
expect(handler).to have_received(:finish).with(request)
|
120
|
+
end
|
83
121
|
end
|
84
122
|
|
85
123
|
describe '#close' do
|
@@ -89,8 +127,4 @@ describe Hatetepe::Server do
|
|
89
127
|
expect(connection).to have_received(:close)
|
90
128
|
end
|
91
129
|
end
|
92
|
-
|
93
|
-
describe '#teardown' do
|
94
|
-
specify { pending }
|
95
|
-
end
|
96
130
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hatetepe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.0.pre.
|
4
|
+
version: 0.6.0.pre.2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -48,17 +48,17 @@ dependencies:
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: 0.3.0
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.3.0
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rspec
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,8 +78,7 @@ dependencies:
|
|
78
78
|
description: The HTTP toolkit
|
79
79
|
email:
|
80
80
|
- lars.gierth@gmail.com
|
81
|
-
executables:
|
82
|
-
- hatetepe
|
81
|
+
executables: []
|
83
82
|
extensions: []
|
84
83
|
extra_rdoc_files: []
|
85
84
|
files:
|
@@ -90,9 +89,9 @@ files:
|
|
90
89
|
- Gemfile
|
91
90
|
- Gemfile.devtools
|
92
91
|
- LICENSE.txt
|
92
|
+
- Procfile
|
93
93
|
- README.md
|
94
94
|
- Rakefile
|
95
|
-
- bin/hatetepe
|
96
95
|
- config/devtools.yml
|
97
96
|
- config/flay.yml
|
98
97
|
- config/flog.yml
|
@@ -100,6 +99,8 @@ files:
|
|
100
99
|
- config/reek.yml
|
101
100
|
- config/rubocop.yml
|
102
101
|
- config/yardstick.yml
|
102
|
+
- examples/echo_server.rb
|
103
|
+
- examples/getting_started.rb
|
103
104
|
- hatetepe.gemspec
|
104
105
|
- lib/hatetepe.rb
|
105
106
|
- lib/hatetepe/body.rb
|
@@ -120,7 +121,6 @@ files:
|
|
120
121
|
- lib/hatetepe/support/handlers.rb
|
121
122
|
- lib/hatetepe/support/message.rb
|
122
123
|
- lib/hatetepe/version.rb
|
123
|
-
- spec/integration/error_handling_spec.rb
|
124
124
|
- spec/integration/keep_alive_spec.rb
|
125
125
|
- spec/integration/smoke_spec.rb
|
126
126
|
- spec/integration/streaming_spec.rb
|
@@ -162,7 +162,6 @@ signing_key:
|
|
162
162
|
specification_version: 3
|
163
163
|
summary: General purpose toolkit for HTTP clients and servers
|
164
164
|
test_files:
|
165
|
-
- spec/integration/error_handling_spec.rb
|
166
165
|
- spec/integration/keep_alive_spec.rb
|
167
166
|
- spec/integration/smoke_spec.rb
|
168
167
|
- spec/integration/streaming_spec.rb
|
data/bin/hatetepe
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: utf-8
|
3
|
-
|
4
|
-
require 'hatetepe'
|
5
|
-
|
6
|
-
class RequestHandler
|
7
|
-
def initialize(config, server, connection)
|
8
|
-
end
|
9
|
-
|
10
|
-
def serve(request, served)
|
11
|
-
puts "#{request.http_method.upcase} #{request.uri}"
|
12
|
-
response = build_response
|
13
|
-
served.fulfill(response)
|
14
|
-
end
|
15
|
-
|
16
|
-
def build_response
|
17
|
-
Hatetepe::Response.new(
|
18
|
-
200, { 'Content-Type' => 'text/plain' }, "hello, world\n")
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
address = ENV.fetch('ADDRESS', '127.0.0.1')
|
23
|
-
port = ENV.fetch('PORT', 3000)
|
24
|
-
|
25
|
-
$stdout.sync = true
|
26
|
-
|
27
|
-
EM.run do
|
28
|
-
puts "Listening on http://#{address}:#{port}"
|
29
|
-
Hatetepe::Server.start(address: address, port: port,
|
30
|
-
handlers: [Hatetepe::Server::KeepAlive,
|
31
|
-
Hatetepe::Server::Timeouts,
|
32
|
-
RequestHandler])
|
33
|
-
end
|