hatetepe 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -4,6 +4,3 @@ gemspec
4
4
 
5
5
  gem "rake"
6
6
  gem "awesome_print"
7
-
8
- gem "yard"
9
- gem "rdiscount"
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/lgierth/faraday/tree/hatetepe-support)
14
+ [Hatetepe adapter](https://github.com/technoweenie/faraday/pull/108)
15
15
  for it being worked on.
16
16
 
17
17
  [![Build status](https://secure.travis-ci.org/lgierth/hatetepe.png?branch=master)](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
 
@@ -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
- if headers["Content-Type"] == "application/x-www-form-urlencoded"
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
@@ -1,3 +1,3 @@
1
1
  module Hatetepe
2
- VERSION = "0.4.0"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -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
- describe "with Content-Type: application/x-www-form-urlencoded" do
257
- let :headers do
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.0
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-05 00:00:00.000000000 Z
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: &86213170 !ruby/object:Gem::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: *86213170
24
+ version_requirements: *69946770
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: eventmachine
27
- requirement: &86212940 !ruby/object:Gem::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: *86212940
35
+ version_requirements: *69946160
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: em-synchrony
38
- requirement: &86212670 !ruby/object:Gem::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: *86212670
46
+ version_requirements: *69945450
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rack
49
- requirement: &86212370 !ruby/object:Gem::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: *86212370
57
+ version_requirements: *69944990
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: async-rack
60
- requirement: &86212030 !ruby/object:Gem::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: *86212030
68
+ version_requirements: *69944610
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: thor
71
- requirement: &86211710 !ruby/object:Gem::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: *86211710
79
+ version_requirements: *69883990
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &86211400 !ruby/object:Gem::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: *86211400
90
+ version_requirements: *69883740
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: fakefs
93
- requirement: &86211060 !ruby/object:Gem::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: *86211060
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