hatetepe 0.4.0 → 0.4.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/Gemfile +0 -3
- data/README.md +3 -1
- data/hatetepe.gemspec +2 -0
- data/lib/hatetepe/client/keep_alive.rb +0 -26
- data/lib/hatetepe/client.rb +37 -5
- data/lib/hatetepe/version.rb +1 -1
- data/spec/unit/client_spec.rb +14 -43
- metadata +40 -18
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Install it via `gem install hatetepe` or add `gem "hatetepe"` to your Gemfile.
|
|
11
11
|
Hatetepe only implements core HTTP functionality. If you need stuff like
|
12
12
|
automatic JSON or form-data encoding, have a look at
|
13
13
|
[Faraday](https://github.com/technoweenie/faraday), there's also an
|
14
|
-
[Hatetepe adapter](https://github.com/
|
14
|
+
[Hatetepe adapter](https://github.com/technoweenie/faraday/pull/108)
|
15
15
|
for it being worked on.
|
16
16
|
|
17
17
|
[](http://travis-ci.org/lgierth/hatetepe)
|
@@ -39,8 +39,10 @@ Getting Started (Client)
|
|
39
39
|
The `Hatetepe::Client` class can be used to make requests to an HTTP server.
|
40
40
|
|
41
41
|
client = Hatetepe::Client.start(:host => "example.org", :port => 80)
|
42
|
+
|
42
43
|
request = Hatetepe::Request.new(:post, "/search", {}, :q => "herp derp")
|
43
44
|
client << request
|
45
|
+
|
44
46
|
request.callback do |response|
|
45
47
|
puts "Results:"
|
46
48
|
puts response.body.read
|
data/hatetepe.gemspec
CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.add_development_dependency "rspec"
|
23
23
|
s.add_development_dependency "fakefs"
|
24
|
+
s.add_development_dependency "yard"
|
25
|
+
s.add_development_dependency "rdiscount"
|
24
26
|
|
25
27
|
s.files = `git ls-files`.split("\n") - [".gitignore", ".rspec", ".travis.yml", ".yardopts"]
|
26
28
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -10,32 +10,6 @@ class Hatetepe::Client
|
|
10
10
|
# i think it doesn't matter if we send it as we don't wait
|
11
11
|
# for the first response to see if we're talking to an HTTP/1.1
|
12
12
|
# server. we're sending more requests anyway.
|
13
|
-
|
14
|
-
# priority
|
15
|
-
# 1. if X-Hatetepe-Single then Connection header, Client#request closes
|
16
|
-
# 2. if req.Connection == close then Connection header and close
|
17
|
-
# 3. if res.Connection == close then close
|
18
|
-
def call(request)
|
19
|
-
req, conn = request, request.connection
|
20
|
-
|
21
|
-
single = req.headers.delete("X-Hatetepe-Single")
|
22
|
-
req.headers["Connection"] ||= if single
|
23
|
-
"close"
|
24
|
-
else
|
25
|
-
"keep-alive"
|
26
|
-
end
|
27
|
-
close = req.headers["Connection"] == "close"
|
28
|
-
|
29
|
-
# stop processing further requests as early as possible
|
30
|
-
conn.processing_enabled = false if close
|
31
|
-
|
32
|
-
app.call(request).tap do |response|
|
33
|
-
if !single && response.headers["Connection"] == "close"
|
34
|
-
conn.processing_enabled = false
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
13
|
def call(request)
|
40
14
|
req, conn = request, request.connection
|
41
15
|
|
data/lib/hatetepe/client.rb
CHANGED
@@ -76,6 +76,8 @@ class Hatetepe::Client
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def <<(request)
|
79
|
+
request.headers["Host"] ||= "#{config[:host]}:#{config[:port]}"
|
80
|
+
|
79
81
|
request.connection = self
|
80
82
|
unless processing_enabled?
|
81
83
|
request.fail
|
@@ -101,18 +103,17 @@ class Hatetepe::Client
|
|
101
103
|
end
|
102
104
|
|
103
105
|
def request(verb, uri, headers = {}, body = nil, http_version = "1.1")
|
104
|
-
headers["Host"] ||= "#{config[:host]}:#{config[:port]}"
|
105
106
|
headers["User-Agent"] ||= "hatetepe/#{Hatetepe::VERSION}"
|
106
107
|
|
107
108
|
body = wrap_body(body)
|
108
|
-
|
109
|
-
enum = Enumerator.new(body)
|
110
|
-
headers["Content-Length"] = enum.inject(0) {|a, e| a + e.length }
|
111
|
-
end
|
109
|
+
headers, body = encode_body(headers.dup, body)
|
112
110
|
|
113
111
|
request = Hatetepe::Request.new(verb, uri, headers, body, http_version)
|
114
112
|
self << request
|
113
|
+
|
114
|
+
# XXX shouldn't this happen in ::request ?
|
115
115
|
self.processing_enabled = false
|
116
|
+
|
116
117
|
EM::Synchrony.sync request
|
117
118
|
|
118
119
|
request.response.body.close_write if request.verb == "HEAD"
|
@@ -161,6 +162,37 @@ class Hatetepe::Client
|
|
161
162
|
end
|
162
163
|
end
|
163
164
|
|
165
|
+
def encode_body(headers, body)
|
166
|
+
multipart, urlencoded = false, false
|
167
|
+
if Hash === body
|
168
|
+
query = lambda do |value|
|
169
|
+
case value
|
170
|
+
when Array
|
171
|
+
value.each &query
|
172
|
+
when Hash
|
173
|
+
value.values.each &query
|
174
|
+
when Rack::Multipart::UploadedFile
|
175
|
+
multipart = true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
body.values.each &query
|
179
|
+
urlencoded = !multipart
|
180
|
+
end
|
181
|
+
|
182
|
+
body = if multipart
|
183
|
+
boundary = Rack::Multipart::MULTIPART_BOUNDARY
|
184
|
+
headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
|
185
|
+
[Rack::Multipart.build_multipart(body)]
|
186
|
+
elsif urlencoded
|
187
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
188
|
+
[Rack::Utils.build_nested_query(body)]
|
189
|
+
else
|
190
|
+
body
|
191
|
+
end
|
192
|
+
|
193
|
+
[headers, body]
|
194
|
+
end
|
195
|
+
|
164
196
|
class << self
|
165
197
|
def start(config)
|
166
198
|
EM.connect config[:host], config[:port], self, config
|
data/lib/hatetepe/version.rb
CHANGED
data/spec/unit/client_spec.rb
CHANGED
@@ -154,6 +154,13 @@ describe Hatetepe::Client do
|
|
154
154
|
Fiber.stub(:new) {|blk| blk.call; fiber }
|
155
155
|
end
|
156
156
|
|
157
|
+
it "sets a Host header if none is set" do
|
158
|
+
app.should_receive :call do |req|
|
159
|
+
req.headers["Host"].should == "example.net:8080"
|
160
|
+
end
|
161
|
+
client << request
|
162
|
+
end
|
163
|
+
|
157
164
|
it "sets the request's connection" do
|
158
165
|
request.should_receive(:connection=).with client
|
159
166
|
client << request
|
@@ -218,25 +225,11 @@ describe Hatetepe::Client do
|
|
218
225
|
end
|
219
226
|
|
220
227
|
describe "#request(verb, uri, headers, body)" do
|
221
|
-
let :config do
|
222
|
-
{
|
223
|
-
:host => "example.org",
|
224
|
-
:port => 8080
|
225
|
-
}
|
226
|
-
end
|
227
|
-
|
228
228
|
before do
|
229
229
|
EM::Synchrony.stub :sync
|
230
230
|
client.stub :<<
|
231
231
|
end
|
232
232
|
|
233
|
-
it "sets a Host header if none is set" do
|
234
|
-
client.should_receive :<< do |request|
|
235
|
-
request.headers["Host"].should == "example.org:8080"
|
236
|
-
end
|
237
|
-
client.request :get, uri
|
238
|
-
end
|
239
|
-
|
240
233
|
it "sets the User-Agent header" do
|
241
234
|
client.should_receive :<< do |request|
|
242
235
|
request.headers["User-Agent"].should == "hatetepe/#{Hatetepe::VERSION}"
|
@@ -252,35 +245,9 @@ describe Hatetepe::Client do
|
|
252
245
|
end
|
253
246
|
client.request :get, uri, "User-Agent" => user_agent
|
254
247
|
end
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
{"Content-Type" => "application/x-www-form-urlencoded"}
|
259
|
-
end
|
260
|
-
|
261
|
-
let :body do
|
262
|
-
[
|
263
|
-
stub("body#1", :length => 12),
|
264
|
-
stub("body#2", :length => 13),
|
265
|
-
stub("body#3", :length => 14)
|
266
|
-
]
|
267
|
-
end
|
268
|
-
|
269
|
-
it "computes the body's length" do
|
270
|
-
client.should_receive :<< do |request|
|
271
|
-
request.headers["Content-Length"].should equal(39)
|
272
|
-
end
|
273
|
-
client.request :get, uri, headers, body
|
274
|
-
end
|
275
|
-
|
276
|
-
it "sets Content-Length to 0 if no body was passed" do
|
277
|
-
client.should_receive :<< do |request|
|
278
|
-
request.headers["Content-Length"].should equal(0)
|
279
|
-
end
|
280
|
-
client.request :get, uri, headers
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
248
|
+
|
249
|
+
it "passes the body through #encode_body"
|
250
|
+
|
284
251
|
it "doesn't close the body" do
|
285
252
|
body.should_not_receive :close_write
|
286
253
|
client.request :get, uri, {}, body
|
@@ -350,6 +317,10 @@ describe Hatetepe::Client do
|
|
350
317
|
client.wrap_body(nil).should == []
|
351
318
|
end
|
352
319
|
end
|
320
|
+
|
321
|
+
describe "#encode_body(headers, body)" do
|
322
|
+
it ""
|
323
|
+
end
|
353
324
|
|
354
325
|
describe ".start(config)" do
|
355
326
|
let(:config) { {:host => "0.0.0.0", :port => 1234} }
|
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.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: http_parser.rb
|
16
|
-
requirement: &
|
16
|
+
requirement: &69946770 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 0.5.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *69946770
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: eventmachine
|
27
|
-
requirement: &
|
27
|
+
requirement: &69946160 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *69946160
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: em-synchrony
|
38
|
-
requirement: &
|
38
|
+
requirement: &69945450 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *69945450
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rack
|
49
|
-
requirement: &
|
49
|
+
requirement: &69944990 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *69944990
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: async-rack
|
60
|
-
requirement: &
|
60
|
+
requirement: &69944610 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *69944610
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: thor
|
71
|
-
requirement: &
|
71
|
+
requirement: &69883990 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *69883990
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rspec
|
82
|
-
requirement: &
|
82
|
+
requirement: &69883740 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *69883740
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: fakefs
|
93
|
-
requirement: &
|
93
|
+
requirement: &69883520 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,7 +98,29 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *69883520
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: yard
|
104
|
+
requirement: &69883290 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *69883290
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rdiscount
|
115
|
+
requirement: &69883080 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *69883080
|
102
124
|
description:
|
103
125
|
email:
|
104
126
|
- lars.gierth@gmail.com
|