uv-rays 0.2.6 → 0.3.0
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.
- checksums.yaml +4 -4
- data/lib/uv-rays/http/request.rb +1 -1
- data/lib/uv-rays/http/response.rb +3 -6
- data/lib/uv-rays/http_endpoint.rb +100 -96
- data/lib/uv-rays/version.rb +1 -1
- data/spec/http_endpoint_spec.rb +0 -104
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 558fed8aba820a41ca678d1eff92f5ffcfe7ffda
|
4
|
+
data.tar.gz: 973e700f3dc30174988ed0e43305bedfd1045adc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b165b0a04fde386e7ec551f1047bf21dd2086c311281f1c243ad39f825cdcd3a99d48ae6ea0ad04b6c4a498ce687c480679ed792a2d7d16f90f1fc062fa9727
|
7
|
+
data.tar.gz: 2bd96402a8f3be5ce823a7f8c893c2fea25060125ba21aafd677fd0aeb55f895ae28c2ec82a7efc1a126eed67ccc55052578981c488897c08351dd867cee825d
|
data/lib/uv-rays/http/request.rb
CHANGED
@@ -14,16 +14,14 @@ module UV
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class Response
|
17
|
-
def initialize
|
18
|
-
@requests = requests
|
19
|
-
|
17
|
+
def initialize
|
20
18
|
@parser = ::HttpParser::Parser.new(self)
|
21
19
|
@state = ::HttpParser::Parser.new_instance
|
22
20
|
@state.type = :response
|
23
21
|
end
|
24
22
|
|
25
23
|
|
26
|
-
|
24
|
+
attr_accessor :request
|
27
25
|
|
28
26
|
|
29
27
|
# Called on connection disconnect
|
@@ -51,7 +49,6 @@ module UV
|
|
51
49
|
##
|
52
50
|
# Parser Callbacks:
|
53
51
|
def on_message_begin(parser)
|
54
|
-
@request = @requests.shift
|
55
52
|
@headers = Headers.new
|
56
53
|
@body = ''
|
57
54
|
@chunked = false
|
@@ -123,7 +120,7 @@ module UV
|
|
123
120
|
# We need to flush the response on disconnect if content-length is undefined
|
124
121
|
# As per the HTTP spec
|
125
122
|
def eof
|
126
|
-
if @headers.nil? && @request.headers[:'Content-Length'].nil?
|
123
|
+
if @headers.nil? && @request.headers && @request.headers[:'Content-Length'].nil?
|
127
124
|
on_message_complete(nil)
|
128
125
|
else
|
129
126
|
# Reject if this is a partial response
|
@@ -47,10 +47,9 @@ module UV
|
|
47
47
|
}
|
48
48
|
|
49
49
|
attr_reader :scheme, :host, :port, :using_tls, :loop, :cookiejar
|
50
|
-
attr_reader :
|
50
|
+
attr_reader :inactivity_timeout
|
51
51
|
|
52
52
|
def initialize(uri, options = {})
|
53
|
-
@connect_timeout = options[:connect_timeout] ||= 5 # default connection setup timeout
|
54
53
|
@inactivity_timeout = options[:inactivity_timeout] ||= 10 # default connection inactivity (post-setup) timeout
|
55
54
|
|
56
55
|
|
@@ -66,29 +65,24 @@ module UV
|
|
66
65
|
#@transport = @loop.tcp
|
67
66
|
|
68
67
|
# State flags
|
69
|
-
@
|
68
|
+
@closed = true
|
69
|
+
@closing = false
|
70
70
|
@connecting = false
|
71
71
|
|
72
72
|
# Current requests
|
73
73
|
@pending_requests = []
|
74
|
-
@
|
75
|
-
@
|
74
|
+
@staging_request = nil
|
75
|
+
@waiting_response = nil
|
76
76
|
@cookiejar = CookieJar.new
|
77
77
|
|
78
78
|
# Callback methods
|
79
|
-
@connection_method = method(:get_connection)
|
80
|
-
@next_request_method = method(:next_request)
|
81
79
|
@idle_timeout_method = method(:idle_timeout)
|
82
|
-
@connect_timeout_method = method(:connect_timeout)
|
83
|
-
|
84
|
-
# Used to indicate when we can start the next send
|
85
|
-
@breakpoint = ::Libuv::Q::ResolvedPromise.new(@loop, true)
|
86
80
|
|
87
81
|
# Manages the tokenising of response from the input stream
|
88
|
-
@response = Http::Response.new
|
82
|
+
@response = Http::Response.new
|
89
83
|
|
90
84
|
# Timeout timer
|
91
|
-
if @
|
85
|
+
if @inactivity_timeout > 0
|
92
86
|
@timer = @loop.timer
|
93
87
|
end
|
94
88
|
end
|
@@ -109,12 +103,23 @@ module UV
|
|
109
103
|
|
110
104
|
# Setup the request with callbacks
|
111
105
|
request = Http::Request.new(self, options)
|
112
|
-
request.then
|
113
|
-
|
106
|
+
request.then(proc { |result|
|
107
|
+
@waiting_response = nil
|
108
|
+
|
109
|
+
if @closed || result[:headers].keep_alive
|
110
|
+
next_request
|
111
|
+
else
|
112
|
+
@closing = true
|
114
113
|
@transport.close
|
115
114
|
end
|
115
|
+
|
116
116
|
result
|
117
|
-
}
|
117
|
+
}, proc { |err|
|
118
|
+
@waiting_response = nil
|
119
|
+
next_request
|
120
|
+
|
121
|
+
::Libuv::Q.reject(@loop, err)
|
122
|
+
})
|
118
123
|
|
119
124
|
##
|
120
125
|
# TODO:: Add response middleware here
|
@@ -122,54 +127,35 @@ module UV
|
|
122
127
|
|
123
128
|
# Add to pending requests and schedule using the breakpoint
|
124
129
|
@pending_requests << request
|
125
|
-
|
126
|
-
|
127
|
-
options[:keepalive] = true
|
128
|
-
else
|
129
|
-
@breakpoint = request
|
130
|
+
if !@waiting_response && !@staging_request
|
131
|
+
next_request
|
130
132
|
end
|
131
133
|
|
132
134
|
# return the request
|
133
135
|
request
|
134
136
|
end
|
135
137
|
|
136
|
-
def middleware
|
137
|
-
# TODO:: allow for middle ware
|
138
|
-
[]
|
139
|
-
end
|
140
138
|
|
141
|
-
def
|
142
|
-
@
|
143
|
-
|
144
|
-
# Response rejects the request
|
145
|
-
if @response.receive(data)
|
146
|
-
@transport.close
|
147
|
-
end
|
139
|
+
def next_request
|
140
|
+
@staging_request = @pending_requests.shift
|
141
|
+
process_request unless @staging_request.nil?
|
148
142
|
end
|
149
143
|
|
150
|
-
def
|
151
|
-
@
|
152
|
-
|
153
|
-
stop_timer
|
154
|
-
|
155
|
-
# Flush any processing request
|
156
|
-
@response.eof if @response.request
|
144
|
+
def process_request
|
145
|
+
if @closed && !@connecting
|
146
|
+
@transport = @loop.tcp
|
157
147
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
@pending_responses.clear
|
163
|
-
|
164
|
-
# Re-connect if there are pending requests
|
165
|
-
if not @connection_pending.empty?
|
166
|
-
do_connect
|
148
|
+
@connecting = @staging_request
|
149
|
+
::UV.try_connect(@transport, self, @host, @port)
|
150
|
+
elsif !@closing
|
151
|
+
try_send
|
167
152
|
end
|
168
153
|
end
|
169
154
|
|
155
|
+
|
170
156
|
def on_connect(transport)
|
171
157
|
@connecting = false
|
172
|
-
@
|
158
|
+
@closed = false
|
173
159
|
|
174
160
|
# start tls if connection is encrypted
|
175
161
|
use_tls() if @https
|
@@ -183,71 +169,89 @@ module UV
|
|
183
169
|
|
184
170
|
# Kick off pending requests
|
185
171
|
@response.reset!
|
186
|
-
|
187
|
-
callback.call
|
188
|
-
end
|
189
|
-
@connection_pending.clear
|
172
|
+
try_send # we only connect if there is a request waiting
|
190
173
|
end
|
191
174
|
|
192
175
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
176
|
+
def on_close
|
177
|
+
@closed = true
|
178
|
+
clear_staging = @connecting == @staging_request
|
179
|
+
@connecting = false
|
180
|
+
stop_timer
|
198
181
|
|
199
|
-
|
200
|
-
|
201
|
-
|
182
|
+
# On close may be called before on data
|
183
|
+
@loop.next_tick do
|
184
|
+
if @closing
|
185
|
+
@closing = false
|
186
|
+
@connecting = false
|
187
|
+
|
188
|
+
if @staging_request
|
189
|
+
process_request
|
190
|
+
else
|
191
|
+
next_request
|
192
|
+
end
|
193
|
+
else
|
194
|
+
if clear_staging
|
195
|
+
@staging_request.reject(:connection_refused)
|
196
|
+
elsif @waiting_response
|
197
|
+
# Flush any processing request
|
198
|
+
@response.eof if @response.request
|
199
|
+
|
200
|
+
# Reject any requests waiting on a response
|
201
|
+
@waiting_response.reject(:disconnected)
|
202
|
+
elsif @staging_request
|
203
|
+
# Try reconnect
|
204
|
+
process_request
|
205
|
+
end
|
206
|
+
end
|
202
207
|
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def try_send
|
211
|
+
@waiting_response = @staging_request
|
212
|
+
@response.request = @staging_request
|
213
|
+
@staging_request = nil
|
203
214
|
|
204
|
-
@
|
205
|
-
|
215
|
+
@timer.again if @inactivity_timeout > 0
|
216
|
+
@waiting_response.execute(@transport, proc { |err|
|
217
|
+
@transport.close
|
218
|
+
@waiting_response.reject(err)
|
219
|
+
})
|
206
220
|
end
|
207
221
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
@connection_pending << callback
|
213
|
-
elsif !@ready
|
214
|
-
@connection_pending << callback
|
215
|
-
do_connect
|
216
|
-
elsif @transport.closing?
|
217
|
-
@connection_pending << callback
|
218
|
-
else
|
219
|
-
callback.call(@connection)
|
220
|
-
end
|
222
|
+
|
223
|
+
def middleware
|
224
|
+
# TODO:: allow for middle ware
|
225
|
+
[]
|
221
226
|
end
|
222
227
|
|
223
|
-
def
|
224
|
-
@timer.
|
225
|
-
|
226
|
-
|
228
|
+
def on_read(data, *args)
|
229
|
+
@timer.again if @inactivity_timeout > 0
|
230
|
+
|
231
|
+
# returns true on error
|
232
|
+
# Response rejects the request
|
233
|
+
if @response.receive(data)
|
234
|
+
@transport.close
|
235
|
+
end
|
227
236
|
end
|
228
237
|
|
229
|
-
def
|
230
|
-
|
231
|
-
@
|
232
|
-
@
|
233
|
-
|
238
|
+
def close_connection(after_writing = false)
|
239
|
+
stop_timer
|
240
|
+
reqs = @pending_requests
|
241
|
+
@pending_requests.clear
|
242
|
+
reqs.each do |request|
|
243
|
+
request.reject(:close_connection)
|
234
244
|
end
|
245
|
+
super(after_writing)
|
235
246
|
end
|
236
247
|
|
237
|
-
def next_request
|
238
|
-
request = @pending_requests.shift
|
239
248
|
|
240
|
-
|
241
|
-
@pending_responses << request
|
249
|
+
protected
|
242
250
|
|
243
|
-
@timer.again if @inactivity_timeout > 0
|
244
251
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
request.reject(err)
|
249
|
-
})
|
250
|
-
end
|
252
|
+
def idle_timeout
|
253
|
+
@timer.stop
|
254
|
+
@transport.close
|
251
255
|
end
|
252
256
|
|
253
257
|
def stop_timer
|
data/lib/uv-rays/version.rb
CHANGED
data/spec/http_endpoint_spec.rb
CHANGED
@@ -40,33 +40,6 @@ module OldServer
|
|
40
40
|
end
|
41
41
|
|
42
42
|
|
43
|
-
#
|
44
|
-
# TODO:: Write tests for bad server responses
|
45
|
-
# Need to be able to recover when:
|
46
|
-
# * no response is sent
|
47
|
-
# * disconnect
|
48
|
-
# * bad length etc
|
49
|
-
#
|
50
|
-
module BadServer
|
51
|
-
def post_init
|
52
|
-
@parser = ::HttpParser::Parser.new(self)
|
53
|
-
@state = ::HttpParser::Parser.new_instance
|
54
|
-
@state.type = :request
|
55
|
-
end
|
56
|
-
|
57
|
-
def on_message_complete(parser)
|
58
|
-
write("HTTP/1.0 200 OK\r\nContent-type: text/html\r\nContent-length: 0\r\n\r\n")
|
59
|
-
end
|
60
|
-
|
61
|
-
def on_read(data, connection)
|
62
|
-
if @parser.parse(@state, data)
|
63
|
-
p 'parse error'
|
64
|
-
p @state.error
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
43
|
describe UV::HttpEndpoint do
|
71
44
|
before :each do
|
72
45
|
@loop = Libuv::Loop.new
|
@@ -155,47 +128,6 @@ describe UV::HttpEndpoint do
|
|
155
128
|
expect(@response2[:headers].cookies).to eq({})
|
156
129
|
expect(@response2[:headers].keep_alive).to eq(true)
|
157
130
|
end
|
158
|
-
|
159
|
-
it "should send pipelined requests on the same connection" do
|
160
|
-
@loop.run { |logger|
|
161
|
-
logger.progress do |level, errorid, error|
|
162
|
-
begin
|
163
|
-
@general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
|
164
|
-
rescue Exception
|
165
|
-
@general_failure << 'error in logger'
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
tcp = UV.start_server '127.0.0.1', 3250, HttpServer
|
170
|
-
server = UV::HttpEndpoint.new 'http://127.0.0.1:3250'
|
171
|
-
|
172
|
-
request = server.get(:path => '/', :pipeline => true)
|
173
|
-
request.then(proc { |response|
|
174
|
-
@response = response
|
175
|
-
#@loop.stop
|
176
|
-
}, @request_failure)
|
177
|
-
|
178
|
-
request2 = server.get(:path => '/', :pipeline => true)
|
179
|
-
request2.then(proc { |response|
|
180
|
-
@response2 = response
|
181
|
-
tcp.close
|
182
|
-
@loop.stop
|
183
|
-
}, @request_failure)
|
184
|
-
}
|
185
|
-
|
186
|
-
expect(@general_failure).to eq([])
|
187
|
-
expect(@response[:headers][:"Content-type"]).to eq('text/html')
|
188
|
-
expect(@response[:headers].http_version).to eq('1.1')
|
189
|
-
expect(@response[:headers].status).to eq(200)
|
190
|
-
expect(@response[:headers].cookies).to eq({})
|
191
|
-
expect(@response[:headers].keep_alive).to eq(true)
|
192
|
-
|
193
|
-
expect(@response2[:headers][:"Content-type"]).to eq('text/html')
|
194
|
-
expect(@response2[:headers].http_version).to eq('1.1')
|
195
|
-
expect(@response2[:headers].status).to eq(200)
|
196
|
-
expect(@response2[:headers].cookies).to eq({})
|
197
|
-
expect(@response2[:headers].keep_alive).to eq(true)
|
198
|
-
end
|
199
131
|
end
|
200
132
|
|
201
133
|
describe 'old http request' do
|
@@ -268,41 +200,5 @@ describe UV::HttpEndpoint do
|
|
268
200
|
expect(@response2[:headers].cookies).to eq({})
|
269
201
|
expect(@response2[:headers].keep_alive).to eq(false)
|
270
202
|
end
|
271
|
-
|
272
|
-
it "should fail to send pipelined requests" do
|
273
|
-
@loop.run { |logger|
|
274
|
-
logger.progress do |level, errorid, error|
|
275
|
-
begin
|
276
|
-
@general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
|
277
|
-
rescue Exception
|
278
|
-
@general_failure << 'error in logger'
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
tcp = UV.start_server '127.0.0.1', 3250, OldServer
|
283
|
-
server = UV::HttpEndpoint.new 'http://127.0.0.1:3250'
|
284
|
-
|
285
|
-
request = server.get(:path => '/', :pipeline => true)
|
286
|
-
request.then(proc { |response|
|
287
|
-
@response = response
|
288
|
-
#@loop.stop
|
289
|
-
}, @request_failure)
|
290
|
-
|
291
|
-
request2 = server.get(:path => '/', :pipeline => true)
|
292
|
-
request2.then(proc { |response|
|
293
|
-
@response2 = response
|
294
|
-
tcp.close
|
295
|
-
@loop.stop
|
296
|
-
}, @request_failure)
|
297
|
-
}
|
298
|
-
|
299
|
-
expect(@general_failure).to eq([:disconnected])
|
300
|
-
expect(@response[:headers][:"Content-type"]).to eq('text/html')
|
301
|
-
expect(@response[:headers].http_version).to eq('1.0')
|
302
|
-
expect(@response[:headers].status).to eq(200)
|
303
|
-
expect(@response[:headers].cookies).to eq({})
|
304
|
-
expect(@response[:headers].keep_alive).to eq(false)
|
305
|
-
# Response 2 was the general failure
|
306
|
-
end
|
307
203
|
end
|
308
204
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uv-rays
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen von Takach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: libuv
|
@@ -202,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
202
|
version: '0'
|
203
203
|
requirements: []
|
204
204
|
rubyforge_project:
|
205
|
-
rubygems_version: 2.
|
205
|
+
rubygems_version: 2.0.14
|
206
206
|
signing_key:
|
207
207
|
specification_version: 4
|
208
208
|
summary: Abstractions for working with Libuv
|