experella-proxy 0.0.6
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/.gitignore +15 -0
- data/Gemfile +3 -0
- data/README.md +219 -0
- data/Rakefile +25 -0
- data/TODO.txt +20 -0
- data/bin/experella-proxy +54 -0
- data/config/default/404.html +16 -0
- data/config/default/503.html +18 -0
- data/config/default/config.rb +64 -0
- data/config/default/ssl/certs/experella-proxy.pem +18 -0
- data/config/default/ssl/private/experella-proxy.key +28 -0
- data/dev/experella-proxy +62 -0
- data/experella-proxy.gemspec +39 -0
- data/lib/experella-proxy/backend.rb +58 -0
- data/lib/experella-proxy/backend_server.rb +100 -0
- data/lib/experella-proxy/configuration.rb +154 -0
- data/lib/experella-proxy/connection.rb +557 -0
- data/lib/experella-proxy/connection_manager.rb +167 -0
- data/lib/experella-proxy/globals.rb +37 -0
- data/lib/experella-proxy/http_status_codes.rb +45 -0
- data/lib/experella-proxy/proxy.rb +61 -0
- data/lib/experella-proxy/request.rb +106 -0
- data/lib/experella-proxy/response.rb +204 -0
- data/lib/experella-proxy/server.rb +68 -0
- data/lib/experella-proxy/version.rb +15 -0
- data/lib/experella-proxy.rb +93 -0
- data/spec/echo-server/echo_server.rb +49 -0
- data/spec/experella-proxy/backend_server_spec.rb +101 -0
- data/spec/experella-proxy/configuration_spec.rb +27 -0
- data/spec/experella-proxy/connection_manager_spec.rb +159 -0
- data/spec/experella-proxy/experella-proxy_spec.rb +471 -0
- data/spec/experella-proxy/request_spec.rb +88 -0
- data/spec/experella-proxy/response_spec.rb +44 -0
- data/spec/fixtures/404.html +16 -0
- data/spec/fixtures/503.html +18 -0
- data/spec/fixtures/spec.log +331 -0
- data/spec/fixtures/test_config.rb +34 -0
- data/spec/spec.log +235 -0
- data/spec/spec_helper.rb +35 -0
- data/test/sinatra/hello_world_server.rb +17 -0
- data/test/sinatra/server_one.rb +89 -0
- data/test/sinatra/server_two.rb +89 -0
- metadata +296 -0
@@ -0,0 +1,471 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Dirty integration tests for the proxy connection logic
|
4
|
+
#
|
5
|
+
# uses the simple echo server in spec/echo-server/echo_server.rb and the test_config.rb
|
6
|
+
#
|
7
|
+
# Proxy logfile in spec/log/spec.log
|
8
|
+
#
|
9
|
+
describe ExperellaProxy do
|
10
|
+
include POSIX::Spawn
|
11
|
+
include ExperellaProxy::Globals
|
12
|
+
let(:echo_server) {
|
13
|
+
File.expand_path("../../echo-server/echo_server.rb", __FILE__)
|
14
|
+
}
|
15
|
+
let(:experella_proxy) {
|
16
|
+
File.expand_path("../../../bin/experella-proxy", __FILE__)
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
describe "EchoServer" do
|
22
|
+
before :each do
|
23
|
+
@pid = spawn("ruby", "#{echo_server}", "127.0.0.10", "7654")
|
24
|
+
sleep(0.8) #let the server startup, specs may fail if this is set to low
|
25
|
+
end
|
26
|
+
after :each do
|
27
|
+
Process.kill('QUIT', @pid)
|
28
|
+
sleep(1.0) # give the kill command some time
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should get response from the echoserver" do
|
32
|
+
lambda {
|
33
|
+
EM.run do
|
34
|
+
http = EventMachine::HttpRequest.new("http://127.0.0.10:7654").get({:connect_timeout => 1})
|
35
|
+
http.errback {
|
36
|
+
EventMachine.stop
|
37
|
+
raise "http request failed"
|
38
|
+
}
|
39
|
+
http.callback {
|
40
|
+
http.response.should start_with "you sent: "
|
41
|
+
EventMachine.stop
|
42
|
+
}
|
43
|
+
end
|
44
|
+
}.should_not raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "Proxy" do
|
49
|
+
before :each do
|
50
|
+
@pid = spawn("ruby", "#{echo_server}", "127.0.0.10", "7654")
|
51
|
+
@pid2 = spawn("#{experella_proxy}", "run", "--", "--config=#{File.join(File.dirname(__FILE__),"/../fixtures/test_config.rb")}")
|
52
|
+
sleep(0.8) #let the server startup, specs may fail if this is set to low
|
53
|
+
ExperellaProxy.init(:configfile => File.join(File.dirname(__FILE__),"/../fixtures/test_config.rb"))
|
54
|
+
config.backends.each do |backend|
|
55
|
+
connection_manager.add_backend(ExperellaProxy::BackendServer.new(backend[:host], backend[:port], backend))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
after :each do
|
59
|
+
log.close
|
60
|
+
Process.kill('QUIT', @pid)
|
61
|
+
Process.kill('TERM', @pid2)
|
62
|
+
sleep(1.0) # give the kill command some time
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should get response from the echoserver via the proxy" do
|
66
|
+
log.info "should get response from the echoserver via the proxy"
|
67
|
+
EM.epoll
|
68
|
+
EM.run do
|
69
|
+
lambda {
|
70
|
+
EventMachine.add_timer(0.2) do
|
71
|
+
http = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
72
|
+
).get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
73
|
+
http.errback {
|
74
|
+
EventMachine.stop
|
75
|
+
raise "http request failed"
|
76
|
+
}
|
77
|
+
http.callback {
|
78
|
+
http.response.should start_with "you sent: "
|
79
|
+
EventMachine.stop
|
80
|
+
}
|
81
|
+
end
|
82
|
+
}.should_not raise_error
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should respond with 404" do
|
87
|
+
log.info "should respond with 404"
|
88
|
+
EM.epoll
|
89
|
+
EM.run do
|
90
|
+
lambda {
|
91
|
+
EventMachine.add_timer(0.2) do
|
92
|
+
|
93
|
+
multi = EventMachine::MultiRequest.new
|
94
|
+
multi_shuffle = []
|
95
|
+
multi_shuffle[0] = Proc.new {
|
96
|
+
multi.add :head, EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
97
|
+
).head({:connect_timeout => 1})
|
98
|
+
}
|
99
|
+
multi_shuffle[1] = Proc.new {
|
100
|
+
multi.add :get, EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
101
|
+
).get({:connect_timeout => 1})
|
102
|
+
}
|
103
|
+
multi_shuffle.shuffle!
|
104
|
+
multi_shuffle.each do |p|
|
105
|
+
p.call
|
106
|
+
end
|
107
|
+
|
108
|
+
multi.callback do
|
109
|
+
unless multi.responses[:errback].empty?
|
110
|
+
EventMachine.stop
|
111
|
+
raise "http request failed"
|
112
|
+
end
|
113
|
+
multi.responses[:callback][:head].response.empty?.should be_true
|
114
|
+
multi.responses[:callback][:head].response_header.status.should == 404
|
115
|
+
multi.responses[:callback][:get].response_header.status.should == 404
|
116
|
+
multi.responses[:callback][:get].response.should start_with "<!DOCTYPE html>"
|
117
|
+
EventMachine.stop
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
}.should_not raise_error
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should respond with 400 on malformed request" do
|
127
|
+
log.info "should respond with 400 on malformed request"
|
128
|
+
EM.epoll
|
129
|
+
EM.run do
|
130
|
+
lambda {
|
131
|
+
EventMachine.add_timer(0.2) do
|
132
|
+
http = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
133
|
+
).post({:connect_timeout => 1, :head => {"Host" => "experella.com", "Transfer-Encoding" => "chunked"},
|
134
|
+
:body => "9\r\nMalformed\r\na\r\nchunked da\r\n2\rta HERE\r\n0\r\n\r\n"})
|
135
|
+
http.errback {
|
136
|
+
EventMachine.stop
|
137
|
+
raise "http request failed"
|
138
|
+
}
|
139
|
+
http.callback {
|
140
|
+
http.response_header.status.should == 400
|
141
|
+
EventMachine.stop
|
142
|
+
}
|
143
|
+
end
|
144
|
+
}.should_not raise_error
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should respond with 503" do
|
149
|
+
log.info "should respond with 503"
|
150
|
+
EM.epoll
|
151
|
+
EM.run do
|
152
|
+
lambda {
|
153
|
+
EventMachine.add_timer(0.2) do
|
154
|
+
|
155
|
+
multi = EventMachine::MultiRequest.new
|
156
|
+
multi_shuffle = []
|
157
|
+
multi_shuffle[0] = Proc.new {
|
158
|
+
multi.add :head, EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}/oneroute"
|
159
|
+
).head({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
160
|
+
}
|
161
|
+
multi_shuffle[1] = Proc.new {
|
162
|
+
multi.add :get, EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}/anotherpath"
|
163
|
+
).get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
164
|
+
}
|
165
|
+
multi_shuffle.shuffle!
|
166
|
+
multi_shuffle.each do |p|
|
167
|
+
p.call
|
168
|
+
end
|
169
|
+
|
170
|
+
multi.callback do
|
171
|
+
unless multi.responses[:errback].empty?
|
172
|
+
EventMachine.stop
|
173
|
+
raise "http request failed"
|
174
|
+
end
|
175
|
+
multi.responses[:callback][:head].response.empty?.should be_true
|
176
|
+
multi.responses[:callback][:head].response_header.status.should == 503
|
177
|
+
multi.responses[:callback][:get].response_header.status.should == 503
|
178
|
+
multi.responses[:callback][:get].response.should start_with "<!DOCTYPE html>"
|
179
|
+
EventMachine.stop
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
end
|
184
|
+
}.should_not raise_error
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should reuse keep-alive connections" do
|
189
|
+
log.info "should reuse keep-alive connections"
|
190
|
+
EM.epoll
|
191
|
+
EM.run do
|
192
|
+
lambda {
|
193
|
+
EventMachine.add_timer(0.2) do
|
194
|
+
conn = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}")
|
195
|
+
req1 = conn.get({:connect_timeout => 1, :keepalive => true, :head => {"Host" => "experella.com"}})
|
196
|
+
|
197
|
+
req1.errback {
|
198
|
+
EventMachine.stop
|
199
|
+
raise "http request 1 failed"
|
200
|
+
}
|
201
|
+
req1.callback {
|
202
|
+
req1.response.should start_with "you sent: "
|
203
|
+
req2 = conn.get({:path => '/about/', :connect_timeout => 1, :keepalive => true, :head => {"Host" => "experella.com"}})
|
204
|
+
req2.errback {
|
205
|
+
EventMachine.stop
|
206
|
+
raise "http request 2 failed"
|
207
|
+
}
|
208
|
+
req2.callback {
|
209
|
+
req2.response.should start_with "you sent: "
|
210
|
+
req3 = conn.get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
211
|
+
req3.errback {
|
212
|
+
EventMachine.stop
|
213
|
+
raise "http request 3 failed"
|
214
|
+
}
|
215
|
+
req3.callback {
|
216
|
+
req3.response.should start_with "you sent: "
|
217
|
+
EventMachine.stop
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
end
|
222
|
+
}.should_not raise_error
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should handle chunked post requests and strip invalid Content-Length" do
|
227
|
+
log.info "should stream chunked post requests"
|
228
|
+
EM.epoll
|
229
|
+
EM.run do
|
230
|
+
lambda {
|
231
|
+
EventMachine.add_timer(0.2) do
|
232
|
+
# this will issue a Post Request with Content-Length AND Transfer-Encoding chunked, where the data is
|
233
|
+
# correctly encoded in chunks. The Proxy should therefor strip the Content-Length and forward the data
|
234
|
+
# in chunks.
|
235
|
+
expected_headers = []
|
236
|
+
expected_headers << "POST / HTTP/1.1"
|
237
|
+
expected_headers << "Host: experella.com"
|
238
|
+
expected_headers << "Connection: close"
|
239
|
+
expected_headers << "Via: 1.1 experella"
|
240
|
+
expected_headers << "User-Agent: EventMachine HttpClient"
|
241
|
+
expected_headers << "Transfer-Encoding: chunked"
|
242
|
+
|
243
|
+
# generate random chunked message
|
244
|
+
body = String.new
|
245
|
+
expected_body = String.new
|
246
|
+
chunks = 20 + rand(20)
|
247
|
+
# all alphanumeric characters
|
248
|
+
o = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map { |i| i.to_a }.flatten
|
249
|
+
while chunks > 0 do
|
250
|
+
#chunksize 10 to 1510 characters
|
251
|
+
string = (0...(10 + rand(1500))).map { o[rand(o.length)] }.join
|
252
|
+
body << string.size.to_s(16)
|
253
|
+
body << "\r\n"
|
254
|
+
body << string
|
255
|
+
expected_body << string
|
256
|
+
body << "\r\n"
|
257
|
+
chunks -= 1
|
258
|
+
end
|
259
|
+
body << "0\r\n\r\n"
|
260
|
+
|
261
|
+
http = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
262
|
+
).post({:connect_timeout => 1, :head => {"Host" => "experella.com", "Transfer-Encoding" => "chunked"},
|
263
|
+
:body => body})
|
264
|
+
http.errback {
|
265
|
+
EventMachine.stop
|
266
|
+
raise "http request failed"
|
267
|
+
}
|
268
|
+
http.callback {
|
269
|
+
# as the proxy can rechunk large data in different chunks, it's required to remove all chunk encoding
|
270
|
+
# characters and compare it to the unchunked random data saved in expected_body
|
271
|
+
|
272
|
+
# split header and body
|
273
|
+
response = http.response.partition("\\r\\n\\r\\n")
|
274
|
+
# split by chunked encoding delimiter
|
275
|
+
response[2] = response[2].split("\\r\\n").map { |i|
|
276
|
+
# delete all strings containing the hex-size information (FFF = length 3 = 4500 chars)
|
277
|
+
if i.length <= 3
|
278
|
+
i = ""
|
279
|
+
else
|
280
|
+
i = i
|
281
|
+
end
|
282
|
+
}.join
|
283
|
+
response = response.join
|
284
|
+
expected_headers.each do |header|
|
285
|
+
response.should include header
|
286
|
+
end
|
287
|
+
response.should include expected_body
|
288
|
+
|
289
|
+
EventMachine.stop
|
290
|
+
}
|
291
|
+
end
|
292
|
+
}.should_not raise_error
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
# check echo_server for the response
|
298
|
+
it "should rechunk and stream Transfer-Encoding chunked responses" do
|
299
|
+
log.info "should rechunk and stream Transfer-Encoding chunked responses"
|
300
|
+
EM.epoll
|
301
|
+
EM.run do
|
302
|
+
lambda {
|
303
|
+
EventMachine.add_timer(0.2) do
|
304
|
+
http = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}/chunked"
|
305
|
+
).get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
306
|
+
http.errback {
|
307
|
+
EventMachine.stop
|
308
|
+
raise "http request failed"
|
309
|
+
}
|
310
|
+
received_chunks = ""
|
311
|
+
http.stream { |chunk|
|
312
|
+
received_chunks << chunk
|
313
|
+
}
|
314
|
+
http.callback {
|
315
|
+
true.should be_true
|
316
|
+
received_chunks.should == "chunk one chunk two chunk three chunk four chunk 123456789abcdef"
|
317
|
+
http.response_header["Transfer-Encoding"].should == "chunked"
|
318
|
+
EventMachine.stop
|
319
|
+
}
|
320
|
+
end
|
321
|
+
}.should_not raise_error
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should timeout inactive connections after config.timeout" do
|
327
|
+
log.info "should timeout inactive connections after config.timeout"
|
328
|
+
EM.epoll
|
329
|
+
EM.run do
|
330
|
+
|
331
|
+
lambda {
|
332
|
+
EventMachine.add_timer(0.2) do
|
333
|
+
time = Time.now
|
334
|
+
conn = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}")
|
335
|
+
req1 = conn.get({:connect_timeout => 1, :inactivity_timeout => config.timeout + 5,
|
336
|
+
:keepalive => true, :head => {"Host" => "experella.com"}})
|
337
|
+
req1.errback {
|
338
|
+
time = Time.now - time
|
339
|
+
time.should >= config.timeout
|
340
|
+
time.should < config.timeout + 5
|
341
|
+
EventMachine.stop
|
342
|
+
raise "http request failed"
|
343
|
+
}
|
344
|
+
req1.callback {
|
345
|
+
req1.response.should start_with "you sent: "
|
346
|
+
}
|
347
|
+
#check for inactivity timeout
|
348
|
+
EventMachine.add_periodic_timer(1) do
|
349
|
+
if conn.conn.get_idle_time.nil?
|
350
|
+
time = Time.now - time
|
351
|
+
time.should >= config.timeout
|
352
|
+
time.should <= config.timeout + 5
|
353
|
+
EventMachine.stop
|
354
|
+
elsif Time.now - time > config.timeout + 6
|
355
|
+
EventMachine.stop
|
356
|
+
raise "Timeout failed completly"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
}.should_not raise_error
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
|
365
|
+
it "should handle pipelined requests correctly" do
|
366
|
+
log.info "should handle pipelined requests correctly"
|
367
|
+
EM.epoll
|
368
|
+
EM.run do
|
369
|
+
lambda {
|
370
|
+
EventMachine.add_timer(0.2) do
|
371
|
+
conn = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}")
|
372
|
+
|
373
|
+
pipe1 = conn.get({:connect_timeout => 1, :keepalive => true, :head => {"Host" => "experella.com"}})
|
374
|
+
pipe2 = conn.get({:path => '/about/', :connect_timeout => 1, :keepalive => true, :head => {"Host" => "experella.com"}})
|
375
|
+
pipe3 = conn.get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
376
|
+
pipe1.errback {
|
377
|
+
EventMachine.stop
|
378
|
+
raise "http request 1 failed"
|
379
|
+
}
|
380
|
+
pipe1.callback {
|
381
|
+
pipe1.response.should start_with "you sent: "
|
382
|
+
pipe2.finished?.should be_false
|
383
|
+
pipe3.finished?.should be_false
|
384
|
+
}
|
385
|
+
pipe2.errback {
|
386
|
+
EventMachine.stop
|
387
|
+
raise "http request 2 failed"
|
388
|
+
}
|
389
|
+
pipe2.callback {
|
390
|
+
pipe2.response.should start_with "you sent: "
|
391
|
+
pipe1.finished?.should be_true
|
392
|
+
pipe3.finished?.should be_false
|
393
|
+
}
|
394
|
+
pipe3.errback {
|
395
|
+
EventMachine.stop
|
396
|
+
raise "http request 3 failed"
|
397
|
+
}
|
398
|
+
pipe3.callback {
|
399
|
+
pipe3.response.should start_with "you sent: "
|
400
|
+
pipe1.finished?.should be_true
|
401
|
+
pipe2.finished?.should be_true
|
402
|
+
EventMachine.stop
|
403
|
+
}
|
404
|
+
end
|
405
|
+
}.should_not raise_error
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
it "should accept requests on all set proxy domains" do
|
410
|
+
log.info "should accept requests on all set proxy domains"
|
411
|
+
EM.epoll
|
412
|
+
EM.run do
|
413
|
+
lambda {
|
414
|
+
EventMachine.add_timer(0.2) do
|
415
|
+
|
416
|
+
multi = EventMachine::MultiRequest.new
|
417
|
+
multi_shuffle = []
|
418
|
+
i = 0
|
419
|
+
while config.proxy.length > i do
|
420
|
+
multi_shuffle[i] = Proc.new { |i|
|
421
|
+
multi.add i, EventMachine::HttpRequest.new("http://#{config.proxy[i][:host]}:#{config.proxy[i][:port]}"
|
422
|
+
).get({:connect_timeout => 1, :head => {"Host" => "experella.com"}})
|
423
|
+
}
|
424
|
+
i += 1
|
425
|
+
end
|
426
|
+
multi_shuffle.shuffle!
|
427
|
+
i = 0
|
428
|
+
multi_shuffle.each do |p|
|
429
|
+
p.call(i)
|
430
|
+
i += 1
|
431
|
+
end
|
432
|
+
|
433
|
+
multi.callback do
|
434
|
+
unless multi.responses[:errback].empty?
|
435
|
+
EventMachine.stop
|
436
|
+
raise "http request failed"
|
437
|
+
end
|
438
|
+
multi.responses[:callback].each_value do |resp|
|
439
|
+
resp.response.should start_with "you sent: "
|
440
|
+
end
|
441
|
+
EventMachine.stop
|
442
|
+
end
|
443
|
+
end
|
444
|
+
}.should_not raise_error
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
it "should be able to handle post requests" do
|
449
|
+
log.info "should be able to handle post requests"
|
450
|
+
EM.epoll
|
451
|
+
EM.run do
|
452
|
+
lambda {
|
453
|
+
EventMachine.add_timer(0.2) do
|
454
|
+
http = EventMachine::HttpRequest.new("http://#{config.proxy[0][:host]}:#{config.proxy[0][:port]}"
|
455
|
+
).post({:connect_timeout => 1, :head => {"Host" => "experella.com"}, :body => "Message body"})
|
456
|
+
http.errback {
|
457
|
+
EventMachine.stop
|
458
|
+
raise "http post failed"
|
459
|
+
}
|
460
|
+
http.callback {
|
461
|
+
http.response.should start_with "you sent: "
|
462
|
+
http.response.should end_with "Message body\""
|
463
|
+
EventMachine.stop
|
464
|
+
}
|
465
|
+
end
|
466
|
+
}.should_not raise_error
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
end
|
471
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ExperellaProxy::Request do
|
4
|
+
|
5
|
+
let(:request) {
|
6
|
+
ExperellaProxy::Request.new("conn")
|
7
|
+
}
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
|
11
|
+
it "initializes connection variable and reader" do
|
12
|
+
request.conn.should eql("conn")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "initializes header hash and reader" do
|
16
|
+
request.header.should be_an_instance_of Hash
|
17
|
+
end
|
18
|
+
|
19
|
+
it "initializes uri hash and reader" do
|
20
|
+
request.uri.should be_an_instance_of Hash
|
21
|
+
end
|
22
|
+
|
23
|
+
it "initializes keep_alive boolean and reader" do
|
24
|
+
request.keep_alive.should be_true
|
25
|
+
request.keep_alive = false
|
26
|
+
request.keep_alive.should be_false
|
27
|
+
end
|
28
|
+
|
29
|
+
it "initializes chunked boolean and reader" do
|
30
|
+
request.chunked.should be_false
|
31
|
+
request.chunked = true
|
32
|
+
request.chunked.should be_true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#<<" do
|
37
|
+
it "adds data to send_buffer" do
|
38
|
+
request << "hel"
|
39
|
+
request << "lo"
|
40
|
+
request.flush.should eql("hello")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#flush" do
|
45
|
+
it "returns and clears the send_buffer" do
|
46
|
+
request << "hello"
|
47
|
+
request.flush.should eql("hello")
|
48
|
+
request.flushed?.should == true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#add_uri" do
|
53
|
+
it "adds a hash to the URI hash" do
|
54
|
+
request.add_uri({:path => "/hello"})
|
55
|
+
request.uri[:path].should eql("/hello")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#update_header" do
|
60
|
+
it "updates the header hash and symbolizes input keys" do
|
61
|
+
request.update_header("Host" => "xyz", :request_url => "abcd")
|
62
|
+
request.header[:Host].should eql("xyz")
|
63
|
+
request.header[:request_url].should eql("abcd")
|
64
|
+
request.header["Host"].should be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it "overwrites values of existing keys" do
|
68
|
+
request.update_header("Host" => "xyz", :request_url => "abcd")
|
69
|
+
request.update_header("Host" => "abc")
|
70
|
+
request.header.should eql({:Host => "abc", :request_url => "abcd"})
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#reconstruct_header" do
|
75
|
+
it "writes a valid http header into send_buffer" do
|
76
|
+
request << "HeaderDummy\r\n\r\n"
|
77
|
+
request.update_header({:http_method => "GET", :request_url => "/index",
|
78
|
+
"Host" => "localhost", "Connection" => "keep-alive", :"Via-X" => ["Lukas", "Amy", "George"]})
|
79
|
+
request.reconstruct_header
|
80
|
+
data = request.flush
|
81
|
+
data.start_with?("GET /index HTTP/1.1\r\n").should be_true
|
82
|
+
data.should include("Connection: keep-alive\r\n")
|
83
|
+
data.should include("Via-X: Lukas,Amy,George\r\n")
|
84
|
+
data.end_with?("\r\n\r\n").should be_true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ExperellaProxy::Response do
|
4
|
+
|
5
|
+
let(:response) {
|
6
|
+
ExperellaProxy::Response.new(ExperellaProxy::Request.new("conn"))
|
7
|
+
}
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
|
11
|
+
it "initializes header hash and reader" do
|
12
|
+
response.header.should be_an_instance_of Hash
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#update_header" do
|
17
|
+
it "updates the header hash and symbolizes input keys" do
|
18
|
+
response.update_header("Host" => "xyz", :response_url => "abcd")
|
19
|
+
response.header[:Host].should eql("xyz")
|
20
|
+
response.header[:response_url].should eql("abcd")
|
21
|
+
response.header["Host"].should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "overwrites values of existing keys" do
|
25
|
+
response.update_header("Host" => "xyz", :response_url => "abcd")
|
26
|
+
response.update_header("Host" => "abc")
|
27
|
+
response.header.should eql({:Host => "abc", :response_url => "abcd"})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#reconstruct_header" do
|
32
|
+
it "writes a valid http header into send_buffer" do
|
33
|
+
response.update_header({"Connection" => "keep-alive",
|
34
|
+
:"Via-X" => ["Lukas", "Amy", "George"]})
|
35
|
+
response.reconstruct_header
|
36
|
+
data = response.flush
|
37
|
+
data.start_with?("HTTP/1.1 500 Internal Server Error\r\n").should be_true
|
38
|
+
data.should include("Connection: keep-alive\r\n")
|
39
|
+
data.should include("Via-X: Lukas,Amy,George\r\n")
|
40
|
+
data.end_with?("\r\n\r\n").should be_true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<style type="text/css"> body {
|
5
|
+
text-align: center;
|
6
|
+
font-family: helvetica, arial;
|
7
|
+
font-size: 22px;
|
8
|
+
color: #000;
|
9
|
+
margin: 20px
|
10
|
+
}
|
11
|
+
</style>
|
12
|
+
</head>
|
13
|
+
<body>
|
14
|
+
<h2>404 Page not found!</h2>
|
15
|
+
</body>
|
16
|
+
</html>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<style type="text/css"> body {
|
5
|
+
text-align: center;
|
6
|
+
font-family: helvetica, arial;
|
7
|
+
font-size: 22px;
|
8
|
+
color: #000;
|
9
|
+
margin: 20px
|
10
|
+
|
11
|
+
}
|
12
|
+
|
13
|
+
</style>
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<h2> 503 Service unavailable!</h2>
|
17
|
+
</body>
|
18
|
+
</html>
|