hatetepe 0.6.0.pre.1 → 0.6.0.pre.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/lgierth/hatetepe.png?branch=master)](https://travis-ci.org/lgierth/hatetepe) [![Code Climate](https://codeclimate.com/github/lgierth/hatetepe.png)](https://codeclimate.com/github/lgierth/hatetepe) [![Coverage Status](https://coveralls.io/repos/lgierth/hatetepe/badge.png?branch=master)](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
|