httpkit 0.6.0.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.travis.yml +15 -0
- data/.yardopts +2 -0
- data/Gemfile +19 -0
- data/Gemfile.devtools +67 -0
- data/Procfile +1 -0
- data/README.md +66 -0
- data/Rakefile +5 -0
- data/UNLICENSE +24 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +3 -0
- data/config/reek.yml +114 -0
- data/config/rubocop.yml +56 -0
- data/config/yardstick.yml +2 -0
- data/examples/echo_server.rb +36 -0
- data/examples/getting_started.rb +34 -0
- data/httpkit.gemspec +27 -0
- data/lib/httpkit/body.rb +67 -0
- data/lib/httpkit/client/keep_alive.rb +10 -0
- data/lib/httpkit/client/timeouts.rb +14 -0
- data/lib/httpkit/client.rb +94 -0
- data/lib/httpkit/connection/eventmachine.rb +72 -0
- data/lib/httpkit/connection/status.rb +28 -0
- data/lib/httpkit/promise.rb +19 -0
- data/lib/httpkit/request.rb +19 -0
- data/lib/httpkit/response.rb +110 -0
- data/lib/httpkit/serializer/encoding.rb +43 -0
- data/lib/httpkit/serializer.rb +75 -0
- data/lib/httpkit/server/keep_alive.rb +58 -0
- data/lib/httpkit/server/timeouts.rb +13 -0
- data/lib/httpkit/server.rb +62 -0
- data/lib/httpkit/support/handler_manager.rb +25 -0
- data/lib/httpkit/support/message.rb +66 -0
- data/lib/httpkit/version.rb +5 -0
- data/lib/httpkit.rb +49 -0
- data/spec/integration/error_handling_spec.rb +76 -0
- data/spec/integration/keep_alive_spec.rb +101 -0
- data/spec/integration/smoke_spec.rb +21 -0
- data/spec/integration/streaming_spec.rb +57 -0
- data/spec/integration/timeouts_spec.rb +82 -0
- data/spec/shared/integration/server_client_pair.rb +29 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/support/handler.rb +48 -0
- data/spec/support/helper.rb +70 -0
- data/spec/unit/client_spec.rb +230 -0
- data/spec/unit/connection/eventmachine_spec.rb +211 -0
- data/spec/unit/connection/status_spec.rb +83 -0
- data/spec/unit/httpkit_spec.rb +41 -0
- data/spec/unit/promise_spec.rb +56 -0
- data/spec/unit/request_spec.rb +35 -0
- data/spec/unit/response_spec.rb +108 -0
- data/spec/unit/server/keep_alive_spec.rb +69 -0
- data/spec/unit/server_spec.rb +128 -0
- data/spec/unit/support/handler_manager_spec.rb +21 -0
- data/spec/unit/support/message_spec.rb +115 -0
- metadata +190 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- jruby
|
6
|
+
- rbx
|
7
|
+
- ruby-head
|
8
|
+
- jruby-head
|
9
|
+
matrix:
|
10
|
+
allow_failures:
|
11
|
+
- rvm: jruby
|
12
|
+
- rvm: ruby-head
|
13
|
+
- rvm: jruby-head
|
14
|
+
fast_finish: true
|
15
|
+
script: bundle exec rake -t ci:metrics spec:integration
|
data/.yardopts
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gemspec
|
6
|
+
|
7
|
+
gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
|
8
|
+
gem 'fuubar', git: 'https://github.com/lgierth/fuubar.git',
|
9
|
+
ref: 'static-percentage'
|
10
|
+
gem 'awesome_print'
|
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
|
+
|
18
|
+
# Added by devtools
|
19
|
+
eval_gemfile 'Gemfile.devtools'
|
data/Gemfile.devtools
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem 'rake', '~> 10.1.0'
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
6
|
+
gem 'yard', '~> 0.8.7'
|
7
|
+
|
8
|
+
platform :rbx do
|
9
|
+
gem 'rubysl-singleton', '~> 2.0.0'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
group :yard do
|
14
|
+
gem 'kramdown', '~> 1.2.0'
|
15
|
+
end
|
16
|
+
|
17
|
+
group :guard do
|
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'
|
22
|
+
|
23
|
+
# file system change event handling
|
24
|
+
gem 'listen', '~> 2.2.0'
|
25
|
+
gem 'rb-fchange', '~> 0.0.6', require: false
|
26
|
+
gem 'rb-fsevent', '~> 0.9.3', require: false
|
27
|
+
gem 'rb-inotify', '~> 0.9.0', require: false
|
28
|
+
|
29
|
+
# notification handling
|
30
|
+
gem 'libnotify', '~> 0.8.0', require: false
|
31
|
+
gem 'rb-notifu', '~> 0.0.4', require: false
|
32
|
+
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
33
|
+
end
|
34
|
+
|
35
|
+
group :metrics do
|
36
|
+
gem 'coveralls', '~> 0.7.0'
|
37
|
+
gem 'flay', '~> 2.4.0'
|
38
|
+
gem 'flog', '~> 4.2.0'
|
39
|
+
gem 'reek', '~> 1.3.2'
|
40
|
+
gem 'rubocop', '~> 0.15.0'
|
41
|
+
gem 'simplecov', '~> 0.8.2'
|
42
|
+
gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
|
43
|
+
|
44
|
+
platforms :ruby_19, :ruby_20 do
|
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'
|
47
|
+
gem 'yard-spellcheck', '~> 0.1.5'
|
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
|
57
|
+
end
|
58
|
+
|
59
|
+
group :benchmarks do
|
60
|
+
gem 'rbench', '~> 0.2.3'
|
61
|
+
end
|
62
|
+
|
63
|
+
platform :jruby do
|
64
|
+
group :jruby do
|
65
|
+
gem 'jruby-openssl', '~> 0.8.5'
|
66
|
+
end
|
67
|
+
end
|
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
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# The HTTP toolkit for Ruby [![Build Status](https://travis-ci.org/lgierth/httpkit.png?branch=master)](https://travis-ci.org/lgierth/httpkit) [![Code Climate](https://codeclimate.com/github/lgierth/httpkit.png)](https://codeclimate.com/github/lgierth/httpkit) [![Coverage Status](https://coveralls.io/repos/lgierth/httpkit/badge.png?branch=master)](https://coveralls.io/r/lgierth/httpkit?branch=master)
|
2
|
+
|
3
|
+
HTTPkit is a Ruby toolkit for building HTTP clients and servers,
|
4
|
+
as well as compositions of them.
|
5
|
+
|
6
|
+
- \#1 feature: readable, high-quality, extendable code with 66.81% 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. HTTPkit used to be called
|
17
|
+
Hatetepe.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
gem 'httpkit'
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install httpkit
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Code examples
|
36
|
+
|
37
|
+
- [Getting started ](http://rubydoc.info/github/lgierth/httpkit/master/file/examples/getting_started.rb)
|
38
|
+
- [HTTP echo server](http://rubydoc.info/github/lgierth/httpkit/master/file/examples/echo_server.rb)
|
39
|
+
|
40
|
+
API Reference
|
41
|
+
|
42
|
+
- [HTTPkit::Client ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Client)
|
43
|
+
- [HTTPkit::Server ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Server)
|
44
|
+
- [HTTPkit::Response ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Request)
|
45
|
+
- [HTTPkit::Request ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Response)
|
46
|
+
- [HTTPkit::Body ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Body)
|
47
|
+
- [HTTPkit::Promise ](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Promise)
|
48
|
+
- [HTTPkit::Serializer](http://rubydoc.info/github/lgierth/httpkit/master/HTTPkit/Serializer)
|
49
|
+
|
50
|
+
## To do
|
51
|
+
|
52
|
+
Here: https://trello.com/b/OoxEq1ze/httpkit
|
53
|
+
|
54
|
+
## License
|
55
|
+
|
56
|
+
HTTPkit is free and unencumbered public domain software. For more
|
57
|
+
information, see [unlicense.org](http://unlicense.org/) or the accompanying
|
58
|
+
UNLICENSE file.
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/config/devtools.yml
ADDED
data/config/flay.yml
ADDED
data/config/flog.yml
ADDED
data/config/mutant.yml
ADDED
data/config/reek.yml
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
---
|
2
|
+
Attribute:
|
3
|
+
enabled: false
|
4
|
+
exclude: []
|
5
|
+
BooleanParameter:
|
6
|
+
enabled: true
|
7
|
+
exclude: []
|
8
|
+
ClassVariable:
|
9
|
+
enabled: true
|
10
|
+
exclude: []
|
11
|
+
ControlParameter:
|
12
|
+
enabled: true
|
13
|
+
exclude:
|
14
|
+
- "HTTPkit::Connection::EventMachine#close"
|
15
|
+
- "HTTPkit::Connection::EventMachine#unbind"
|
16
|
+
DataClump:
|
17
|
+
enabled: true
|
18
|
+
exclude: []
|
19
|
+
max_copies: 2
|
20
|
+
min_clump_size: 2
|
21
|
+
DuplicateMethodCall:
|
22
|
+
enabled: true
|
23
|
+
exclude: []
|
24
|
+
max_calls: 2
|
25
|
+
allow_calls: []
|
26
|
+
FeatureEnvy:
|
27
|
+
enabled: false
|
28
|
+
exclude: []
|
29
|
+
IrresponsibleModule:
|
30
|
+
enabled: false
|
31
|
+
exclude: []
|
32
|
+
LongParameterList:
|
33
|
+
enabled: true
|
34
|
+
exclude: []
|
35
|
+
max_params: 2
|
36
|
+
overrides:
|
37
|
+
initialize:
|
38
|
+
max_params: 4
|
39
|
+
setup:
|
40
|
+
max_params: 3
|
41
|
+
LongYieldList:
|
42
|
+
enabled: true
|
43
|
+
exclude: []
|
44
|
+
max_params: 2
|
45
|
+
NestedIterators:
|
46
|
+
enabled: true
|
47
|
+
exclude: []
|
48
|
+
max_allowed_nesting: 2
|
49
|
+
ignore_iterators: []
|
50
|
+
NilCheck:
|
51
|
+
enabled: true
|
52
|
+
exclude: []
|
53
|
+
RepeatedConditional:
|
54
|
+
enabled: true
|
55
|
+
exclude: []
|
56
|
+
max_ifs: 2
|
57
|
+
TooManyInstanceVariables:
|
58
|
+
enabled: true
|
59
|
+
exclude:
|
60
|
+
- HTTPkit::Connection::EventMachine
|
61
|
+
max_instance_variables: 4
|
62
|
+
TooManyMethods:
|
63
|
+
enabled: true
|
64
|
+
exclude: []
|
65
|
+
max_methods: 11
|
66
|
+
TooManyStatements:
|
67
|
+
enabled: true
|
68
|
+
exclude:
|
69
|
+
- each
|
70
|
+
max_statements: 5
|
71
|
+
UncommunicativeMethodName:
|
72
|
+
enabled: true
|
73
|
+
exclude: []
|
74
|
+
reject:
|
75
|
+
- !ruby/regexp /^[a-z]$/
|
76
|
+
- !ruby/regexp /[0-9]$/
|
77
|
+
- !ruby/regexp /[A-Z]/
|
78
|
+
accept: []
|
79
|
+
UncommunicativeModuleName:
|
80
|
+
enabled: true
|
81
|
+
exclude: []
|
82
|
+
reject:
|
83
|
+
- !ruby/regexp /^.$/
|
84
|
+
- !ruby/regexp /[0-9]$/
|
85
|
+
accept: []
|
86
|
+
UncommunicativeParameterName:
|
87
|
+
enabled: true
|
88
|
+
exclude: []
|
89
|
+
reject:
|
90
|
+
- !ruby/regexp /^.$/
|
91
|
+
- !ruby/regexp /[0-9]$/
|
92
|
+
- !ruby/regexp /[A-Z]/
|
93
|
+
accept:
|
94
|
+
- _
|
95
|
+
UncommunicativeVariableName:
|
96
|
+
enabled: true
|
97
|
+
exclude: []
|
98
|
+
reject:
|
99
|
+
- !ruby/regexp /^.$/
|
100
|
+
- !ruby/regexp /[0-9]$/
|
101
|
+
- !ruby/regexp /[A-Z]/
|
102
|
+
accept:
|
103
|
+
- k
|
104
|
+
- v
|
105
|
+
- a
|
106
|
+
- e
|
107
|
+
- _
|
108
|
+
UnusedParameters:
|
109
|
+
enabled: true
|
110
|
+
exclude: []
|
111
|
+
UtilityFunction:
|
112
|
+
enabled: false
|
113
|
+
exclude: []
|
114
|
+
max_helper_calls: 0
|
data/config/rubocop.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- '**/*.rake'
|
4
|
+
- 'Gemfile'
|
5
|
+
- 'Gemfile.devtools'
|
6
|
+
Excludes:
|
7
|
+
- '**/vendor/**'
|
8
|
+
- '**/benchmarks/**'
|
9
|
+
|
10
|
+
# Avoid parameter lists longer than five parameters.
|
11
|
+
ParameterLists:
|
12
|
+
Max: 4
|
13
|
+
CountKeywordArgs: true
|
14
|
+
|
15
|
+
# Avoid more than `Max` levels of nesting.
|
16
|
+
BlockNesting:
|
17
|
+
Max: 3
|
18
|
+
|
19
|
+
# Align with the style guide.
|
20
|
+
CollectionMethods:
|
21
|
+
PreferredMethods:
|
22
|
+
collect: 'map'
|
23
|
+
inject: 'reduce'
|
24
|
+
find: 'detect'
|
25
|
+
find_all: 'select'
|
26
|
+
|
27
|
+
AccessModifierIndentation:
|
28
|
+
EnforcedStyle: indent
|
29
|
+
|
30
|
+
# Limit line length
|
31
|
+
LineLength:
|
32
|
+
Max: 79
|
33
|
+
|
34
|
+
# Disable documentation checking until a class needs to be documented once
|
35
|
+
Documentation:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
# Do not favor modifier if/unless usage when you have a single-line body
|
39
|
+
IfUnlessModifier:
|
40
|
+
Enabled: false
|
41
|
+
|
42
|
+
# Allow case equality operator (in limited use within the specs)
|
43
|
+
CaseEquality:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
# Constants do not always have to use SCREAMING_SNAKE_CASE
|
47
|
+
ConstantName:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
# Not all trivial readers/writers can be defined with attr_* methods
|
51
|
+
TrivialAccessors:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
SignalException:
|
55
|
+
# Valid values are: semantic, only_raise and only_fail
|
56
|
+
EnforcedStyle: only_raise
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'httpkit'
|
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
|
+
HTTPkit::Response.new(200, { 'Content-Type' => 'text/plain' },
|
18
|
+
HTTPkit::Body.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize(request, response)
|
22
|
+
writer = response.body.closed.method(:progress)
|
23
|
+
serializer = HTTPkit::Serializer.new(request, writer)
|
24
|
+
serializer.serialize
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
HTTPkit.start do
|
29
|
+
HTTPkit::Server.start(address: ENV.fetch('ADDRESS', '127.0.0.1'),
|
30
|
+
port: ENV.fetch('PORT', 3000).to_i,
|
31
|
+
handlers: [HTTPkit::Server::KeepAlive.new,
|
32
|
+
EchoServer.new])
|
33
|
+
|
34
|
+
Signal.trap(:INT) { HTTPkit.stop }
|
35
|
+
Signal.trap(:TERM) { HTTPkit.stop }
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'httpkit'
|
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
|
+
HTTPkit::Response.new(200, { 'Content-Type' => 'text/plain' }, 'hello')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
HTTPkit.run do
|
22
|
+
HTTPkit::Server.start(address: '127.0.0.1', port: 3000,
|
23
|
+
handlers: [HelloServer.new])
|
24
|
+
|
25
|
+
client = HTTPkit::Client.start(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/httpkit.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'httpkit/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "httpkit"
|
9
|
+
spec.version = HTTPkit::VERSION
|
10
|
+
spec.authors = ["Lars Gierth"]
|
11
|
+
spec.email = ["lars.gierth@gmail.com"]
|
12
|
+
spec.summary = %q{The HTTP toolkit for Ruby}
|
13
|
+
spec.description = %q{HTTPkit is a Ruby toolkit for building HTTP clients and servers, as well as compositions of them.}
|
14
|
+
spec.homepage = "https://github.com/lgierth/httpkit"
|
15
|
+
spec.license = "Public Domain"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "eventmachine"
|
23
|
+
spec.add_dependency "http_parser.rb"
|
24
|
+
spec.add_dependency "promise.rb", "~> 0.6"
|
25
|
+
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
end
|
data/lib/httpkit/body.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HTTPkit
|
4
|
+
class Body
|
5
|
+
def self.build(arg)
|
6
|
+
if arg.is_a?(Body)
|
7
|
+
arg
|
8
|
+
else
|
9
|
+
body = new(arg.to_s)
|
10
|
+
body.closed.fulfill
|
11
|
+
body
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :closed
|
16
|
+
|
17
|
+
# TODO: eliminate string param
|
18
|
+
def initialize(string = '')
|
19
|
+
@io = StringIO.new(string)
|
20
|
+
|
21
|
+
@closed = Promise.new
|
22
|
+
closed.on_progress { |str| @io.write(str) }
|
23
|
+
end
|
24
|
+
|
25
|
+
# don't optimize the sync call, we don't wanna search in @io.string
|
26
|
+
# because search time increases with its size.
|
27
|
+
def gets(*args)
|
28
|
+
closed.sync
|
29
|
+
@io.gets(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
def read(length = nil, buffer = nil)
|
33
|
+
closed.sync unless optimized_read?(length)
|
34
|
+
@io.read(length, buffer)
|
35
|
+
end
|
36
|
+
|
37
|
+
def rewind
|
38
|
+
closed.sync
|
39
|
+
@io.rewind
|
40
|
+
end
|
41
|
+
|
42
|
+
def each(&block)
|
43
|
+
yield_string(&block)
|
44
|
+
closed.on_progress(&block)
|
45
|
+
closed.sync
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
closed.sync
|
50
|
+
@io.string
|
51
|
+
end
|
52
|
+
|
53
|
+
def string
|
54
|
+
@io.string
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def optimized_read?(length)
|
60
|
+
length && length < (@io.length - pos)
|
61
|
+
end
|
62
|
+
|
63
|
+
def yield_string(&block)
|
64
|
+
block.call(@io.string) unless @io.string.empty?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module HTTPkit
|
4
|
+
# @see EM.heartbeat_interval
|
5
|
+
class Client::Timeouts
|
6
|
+
def setup(config, _, connection)
|
7
|
+
@config = config
|
8
|
+
@connection = connection
|
9
|
+
|
10
|
+
@connection.comm_inactivity_timeout = @config[:timeout] ||= 2.0
|
11
|
+
@connection.pending_connect_timeout = @config[:connect_timeout] ||= 2.0
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|