hatetepe 0.6.0.pre → 0.6.0.pre.1
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/README.md +6 -4
- data/bin/hatetepe +4 -8
- data/config/flay.yml +2 -2
- data/config/reek.yml +15 -11
- data/lib/hatetepe.rb +1 -1
- data/lib/hatetepe/body.rb +62 -0
- data/lib/hatetepe/client.rb +34 -34
- data/lib/hatetepe/client/keep_alive.rb +4 -49
- data/lib/hatetepe/client/timeouts.rb +3 -3
- data/lib/hatetepe/connection/eventmachine.rb +7 -8
- data/lib/hatetepe/promise.rb +7 -2
- data/lib/hatetepe/request.rb +8 -10
- data/lib/hatetepe/response.rb +5 -7
- data/lib/hatetepe/serializer.rb +2 -3
- data/lib/hatetepe/serializer/encoding.rb +8 -16
- data/lib/hatetepe/server.rb +15 -10
- data/lib/hatetepe/server/keep_alive.rb +26 -31
- data/lib/hatetepe/server/timeouts.rb +3 -3
- data/lib/hatetepe/support/message.rb +25 -3
- data/lib/hatetepe/version.rb +1 -1
- data/spec/integration/keep_alive_spec.rb +18 -24
- data/spec/integration/smoke_spec.rb +2 -2
- data/spec/integration/streaming_spec.rb +9 -13
- data/spec/support/handler.rb +12 -16
- data/spec/support/helper.rb +8 -8
- data/spec/unit/client_spec.rb +25 -24
- data/spec/unit/connection/eventmachine_spec.rb +9 -8
- data/spec/unit/request_spec.rb +6 -6
- data/spec/unit/response_spec.rb +3 -3
- data/spec/unit/server/keep_alive_spec.rb +67 -0
- data/spec/unit/server_spec.rb +13 -9
- data/spec/unit/support/message_spec.rb +5 -2
- metadata +5 -5
- data/lib/hatetepe/support/keep_alive.rb +0 -14
- data/spec/unit/support/keep_alive_spec.rb +0 -52
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
# Hatetepe
|
1
|
+
# Hatetepe, the HTTP toolkit [](https://travis-ci.org/lgierth/hatetepe) [](https://codeclimate.com/github/lgierth/hatetepe)
|
2
2
|
|
3
|
-
|
3
|
+
General purpose toolkit for HTTP clients and servers.
|
4
|
+
|
5
|
+
Note: The `master` branch contains the latest development effort. Look at the
|
6
|
+
`0.5.x` branch for stable releases.
|
4
7
|
|
5
8
|
## Installation
|
6
9
|
|
@@ -27,9 +30,8 @@ TODO: Write usage instructions here
|
|
27
30
|
- Unit tests
|
28
31
|
- Method/Status semantics (GET/HEAD/204/etc.)
|
29
32
|
- Host header
|
33
|
+
- Date header
|
30
34
|
- Documentation
|
31
|
-
- Replace into hatetepe-dev
|
32
|
-
- Deprecate hatetepe-0.5
|
33
35
|
- Future
|
34
36
|
- SSL support
|
35
37
|
- Webmachine adapter
|
data/bin/hatetepe
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
|
-
require 'ap'
|
5
4
|
require 'hatetepe'
|
6
5
|
|
7
6
|
class RequestHandler
|
8
7
|
def initialize(config, server, connection)
|
9
8
|
end
|
10
9
|
|
11
|
-
def serve(request)
|
12
|
-
request.
|
13
|
-
|
14
|
-
|
15
|
-
request.served.fulfill(response)
|
16
|
-
response.finished.fulfill
|
17
|
-
end
|
10
|
+
def serve(request, served)
|
11
|
+
puts "#{request.http_method.upcase} #{request.uri}"
|
12
|
+
response = build_response
|
13
|
+
served.fulfill(response)
|
18
14
|
end
|
19
15
|
|
20
16
|
def build_response
|
data/config/flay.yml
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
---
|
2
|
-
threshold:
|
3
|
-
total_score:
|
2
|
+
threshold: 8
|
3
|
+
total_score: 147
|
data/config/reek.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
---
|
2
2
|
Attribute:
|
3
|
-
enabled:
|
3
|
+
enabled: false
|
4
4
|
exclude: []
|
5
5
|
BooleanParameter:
|
6
6
|
enabled: true
|
@@ -19,13 +19,13 @@ DataClump:
|
|
19
19
|
DuplicateMethodCall:
|
20
20
|
enabled: true
|
21
21
|
exclude: []
|
22
|
-
max_calls:
|
22
|
+
max_calls: 2
|
23
23
|
allow_calls: []
|
24
24
|
FeatureEnvy:
|
25
|
-
enabled:
|
25
|
+
enabled: false
|
26
26
|
exclude: []
|
27
27
|
IrresponsibleModule:
|
28
|
-
enabled:
|
28
|
+
enabled: false
|
29
29
|
exclude: []
|
30
30
|
LongParameterList:
|
31
31
|
enabled: true
|
@@ -33,7 +33,7 @@ LongParameterList:
|
|
33
33
|
max_params: 2
|
34
34
|
overrides:
|
35
35
|
initialize:
|
36
|
-
max_params:
|
36
|
+
max_params: 4
|
37
37
|
LongYieldList:
|
38
38
|
enabled: true
|
39
39
|
exclude: []
|
@@ -41,7 +41,7 @@ LongYieldList:
|
|
41
41
|
NestedIterators:
|
42
42
|
enabled: true
|
43
43
|
exclude: []
|
44
|
-
max_allowed_nesting:
|
44
|
+
max_allowed_nesting: 2
|
45
45
|
ignore_iterators: []
|
46
46
|
NilCheck:
|
47
47
|
enabled: true
|
@@ -53,7 +53,7 @@ RepeatedConditional:
|
|
53
53
|
TooManyInstanceVariables:
|
54
54
|
enabled: true
|
55
55
|
exclude: []
|
56
|
-
max_instance_variables:
|
56
|
+
max_instance_variables: 4
|
57
57
|
TooManyMethods:
|
58
58
|
enabled: true
|
59
59
|
exclude: []
|
@@ -62,7 +62,7 @@ TooManyStatements:
|
|
62
62
|
enabled: true
|
63
63
|
exclude:
|
64
64
|
- each
|
65
|
-
max_statements:
|
65
|
+
max_statements: 5
|
66
66
|
UncommunicativeMethodName:
|
67
67
|
enabled: true
|
68
68
|
exclude: []
|
@@ -85,7 +85,8 @@ UncommunicativeParameterName:
|
|
85
85
|
- !ruby/regexp /^.$/
|
86
86
|
- !ruby/regexp /[0-9]$/
|
87
87
|
- !ruby/regexp /[A-Z]/
|
88
|
-
accept:
|
88
|
+
accept:
|
89
|
+
- _
|
89
90
|
UncommunicativeVariableName:
|
90
91
|
enabled: true
|
91
92
|
exclude: []
|
@@ -93,11 +94,14 @@ UncommunicativeVariableName:
|
|
93
94
|
- !ruby/regexp /^.$/
|
94
95
|
- !ruby/regexp /[0-9]$/
|
95
96
|
- !ruby/regexp /[A-Z]/
|
96
|
-
accept:
|
97
|
+
accept:
|
98
|
+
- a
|
99
|
+
- e
|
100
|
+
- _
|
97
101
|
UnusedParameters:
|
98
102
|
enabled: true
|
99
103
|
exclude: []
|
100
104
|
UtilityFunction:
|
101
|
-
enabled:
|
105
|
+
enabled: false
|
102
106
|
exclude: []
|
103
107
|
max_helper_calls: 0
|
data/lib/hatetepe.rb
CHANGED
@@ -9,10 +9,10 @@ require 'hatetepe/version'
|
|
9
9
|
|
10
10
|
require 'hatetepe/errors'
|
11
11
|
require 'hatetepe/support/handlers'
|
12
|
-
require 'hatetepe/support/keep_alive'
|
13
12
|
require 'hatetepe/support/message'
|
14
13
|
|
15
14
|
require 'hatetepe/promise'
|
15
|
+
require 'hatetepe/body'
|
16
16
|
require 'hatetepe/request'
|
17
17
|
require 'hatetepe/response'
|
18
18
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Hatetepe
|
4
|
+
class Body
|
5
|
+
include Promise::Attribute
|
6
|
+
promise :closed
|
7
|
+
|
8
|
+
def self.build(arg)
|
9
|
+
if arg.is_a?(Body)
|
10
|
+
arg
|
11
|
+
else
|
12
|
+
body = new(arg.to_str)
|
13
|
+
body.closed.fulfill
|
14
|
+
body
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(string = '')
|
19
|
+
@io = StringIO.new(string)
|
20
|
+
|
21
|
+
closed.on_progress { |str| @io.write(str) }
|
22
|
+
end
|
23
|
+
|
24
|
+
# don't optimize the sync call, we don't wanna search in @io.string
|
25
|
+
# because search time increases with its size.
|
26
|
+
def gets(*args)
|
27
|
+
closed.sync
|
28
|
+
@io.gets(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def read(length = nil, buffer = nil)
|
32
|
+
closed.sync unless optimized_read?(length)
|
33
|
+
@io.read(length, buffer)
|
34
|
+
end
|
35
|
+
|
36
|
+
def rewind
|
37
|
+
closed.sync
|
38
|
+
@io.rewind
|
39
|
+
end
|
40
|
+
|
41
|
+
def each(&block)
|
42
|
+
yield_string(&block)
|
43
|
+
closed.on_progress(&block)
|
44
|
+
closed.sync
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
closed.sync
|
49
|
+
@io.string
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def optimized_read?(length)
|
55
|
+
length && length < (@io.length - pos)
|
56
|
+
end
|
57
|
+
|
58
|
+
def yield_string(&block)
|
59
|
+
block.call(@io.string) unless @io.string.empty?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/hatetepe/client.rb
CHANGED
@@ -13,67 +13,67 @@ module Hatetepe
|
|
13
13
|
|
14
14
|
setup_connection
|
15
15
|
setup_handlers
|
16
|
-
notify_handlers(:
|
16
|
+
notify_handlers(:setup)
|
17
17
|
end
|
18
18
|
|
19
19
|
def request(http_method, uri)
|
20
20
|
request = Request.new(http_method, uri)
|
21
|
-
request.
|
22
|
-
perform(request)
|
23
|
-
request.served.sync
|
21
|
+
perform(request).sync
|
24
22
|
end
|
25
23
|
|
26
24
|
def perform(request)
|
27
|
-
|
25
|
+
served = Promise.new
|
26
|
+
@requests << [request, served]
|
28
27
|
|
29
|
-
|
30
|
-
|
31
|
-
@connection.serialize(request)
|
32
|
-
end
|
33
|
-
fiber.resume
|
34
|
-
end
|
35
|
-
|
36
|
-
def close
|
37
|
-
@connection.close
|
28
|
+
Fiber.new { perform!(request) }.resume
|
29
|
+
served
|
38
30
|
end
|
39
31
|
|
40
32
|
def receive(response)
|
41
|
-
|
42
|
-
|
43
|
-
|
33
|
+
request, served = correlate
|
34
|
+
|
35
|
+
served.fulfill(response)
|
36
|
+
response.closed { finish(request) }
|
44
37
|
|
45
|
-
setup_cleanup(request, response)
|
46
38
|
notify_handlers(:receive, request, response)
|
47
39
|
end
|
48
40
|
|
41
|
+
def finish(request)
|
42
|
+
@requests.delete_if { |(req, _)| req == request }
|
43
|
+
notify_handlers(:finish, request)
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@connection.close
|
48
|
+
end
|
49
|
+
|
49
50
|
def teardown(reason)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
request.served.reject(reason)
|
51
|
+
@requests.each do |(_, served)|
|
52
|
+
served.reject(reason)
|
53
|
+
if (response = served.value)
|
54
|
+
response.reject_closed(reason)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
private
|
60
60
|
|
61
|
+
def perform!(request)
|
62
|
+
notify_handlers(:perform, request)
|
63
|
+
@connection.serialize(request)
|
64
|
+
end
|
65
|
+
|
66
|
+
def correlate
|
67
|
+
tuple = @requests.detect { |(_, served)| served.pending? }
|
68
|
+
raise ClientError, 'Unable to correlate with request' unless tuple
|
69
|
+
tuple
|
70
|
+
end
|
71
|
+
|
61
72
|
def setup_connection
|
62
73
|
@connection =
|
63
74
|
EM.connect(@config[:address], @config[:port], Connection::EventMachine)
|
64
75
|
@connection.parse(method(:receive))
|
65
76
|
@connection.closed.then(method(:teardown))
|
66
77
|
end
|
67
|
-
|
68
|
-
def correlate(response)
|
69
|
-
@requests
|
70
|
-
.detect { |request| request.served.pending? }
|
71
|
-
.tap { |request| request.served.fulfill(response) if request }
|
72
|
-
end
|
73
|
-
|
74
|
-
def setup_cleanup(request, response)
|
75
|
-
callback = proc { @requests.delete(request) }
|
76
|
-
response.finished.then(callback, callback)
|
77
|
-
end
|
78
78
|
end
|
79
79
|
end
|
@@ -2,58 +2,13 @@
|
|
2
2
|
|
3
3
|
module Hatetepe
|
4
4
|
class Client::KeepAlive
|
5
|
-
|
6
|
-
|
7
|
-
include Support::KeepAlive
|
8
|
-
|
9
|
-
def initialize(config, client, connection)
|
10
|
-
@config, @client = config, client
|
11
|
-
@connection = connection
|
12
|
-
@close = nil
|
13
|
-
@requests = []
|
5
|
+
def initialize(*_)
|
6
|
+
@previous = nil
|
14
7
|
end
|
15
8
|
|
16
9
|
def perform(request)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if @close.nil?
|
21
|
-
await_connection_header(request)
|
22
|
-
elsif !@close
|
23
|
-
await_previous_response(previous_request) if previous_request
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def receive(request, response)
|
28
|
-
@requests.delete(request)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def current_request
|
34
|
-
@requests.first
|
35
|
-
end
|
36
|
-
|
37
|
-
def await_connection_header(request)
|
38
|
-
if current_request == request
|
39
|
-
# first response has the relevant Connection header
|
40
|
-
assume_connection_header
|
41
|
-
else
|
42
|
-
# subsequent requests wait for first response
|
43
|
-
current_request.served.sync
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def assume_connection_header
|
48
|
-
current_request.served.then do |response|
|
49
|
-
@close = close_connection?(response.http_version,
|
50
|
-
response.headers[CONNECTION])
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def await_previous_response(request)
|
55
|
-
response = request.served.sync
|
56
|
-
response.finished.sync
|
10
|
+
@previous, previous = request, @previous
|
11
|
+
previous.closed! if previous
|
57
12
|
end
|
58
13
|
end
|
59
14
|
end
|
@@ -3,15 +3,15 @@
|
|
3
3
|
module Hatetepe
|
4
4
|
# @see EM.heartbeat_interval
|
5
5
|
class Client::Timeouts
|
6
|
-
def initialize(config,
|
7
|
-
@config
|
6
|
+
def initialize(config, _, connection)
|
7
|
+
@config = config
|
8
8
|
@connection = connection
|
9
9
|
|
10
10
|
@config[:timeout] ||= 2.0
|
11
11
|
@config[:connect_timeout] ||= 2.0
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def setup
|
15
15
|
@connection.comm_inactivity_timeout = @config[:timeout]
|
16
16
|
@connection.pending_connect_timeout = @config[:connect_timeout]
|
17
17
|
end
|
@@ -6,9 +6,9 @@ module Hatetepe
|
|
6
6
|
include Promise::Attribute
|
7
7
|
promise :closed
|
8
8
|
|
9
|
-
def initialize(callback =
|
9
|
+
def initialize(callback = proc {})
|
10
10
|
@parser = HTTP::Parser.new(self)
|
11
|
-
callback.call(self)
|
11
|
+
callback.call(self)
|
12
12
|
end
|
13
13
|
|
14
14
|
def parse(block)
|
@@ -21,16 +21,16 @@ module Hatetepe
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def receive_data(data)
|
24
|
-
# ap data
|
24
|
+
# ap [__id__, :receive, data]
|
25
25
|
@parser << data
|
26
26
|
# rescue => error
|
27
27
|
# $stderr.puts(error.to_s)
|
28
|
-
# @message.
|
28
|
+
# @message.reject_close(error) if @message
|
29
29
|
# close_connection
|
30
30
|
end
|
31
31
|
|
32
32
|
# def send_data(data)
|
33
|
-
# ap data
|
33
|
+
# ap [__id__, :send, data]
|
34
34
|
# super
|
35
35
|
# end
|
36
36
|
|
@@ -49,12 +49,11 @@ module Hatetepe
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def on_body(chunk)
|
52
|
-
@message.body
|
53
|
-
@message.finished.progress(chunk)
|
52
|
+
@message.body.closed.progress(chunk)
|
54
53
|
end
|
55
54
|
|
56
55
|
def on_message_complete
|
57
|
-
@message.
|
56
|
+
@message.close
|
58
57
|
end
|
59
58
|
end
|
60
59
|
end
|