spider-gazelle 3.0.2 → 3.0.3
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89774225b2801a3f2556563940da21588a6fef70
|
4
|
+
data.tar.gz: 441d840391e7ccb87d98b4bd2830b80a2ed6b1e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96c3c3b76bf21d2756db7e9b51a50f4125ed26a8b60f12ba8e789b0e73aff65ccdd0a933254485bb600f340ce82b42f9bc8c324deb27eec29a1f14002c762712
|
7
|
+
data.tar.gz: 1208f6382502b44b2f02099fd527441d0e923100c7c26801fd5582a48fb53c698d25672e7b85f4f95ddd159ca7c29d7570523bf514b389a64fdbf137855d75b4
|
@@ -62,13 +62,12 @@ module SpiderGazelle
|
|
62
62
|
end
|
63
63
|
|
64
64
|
PROTOCOLS = ['h2', 'http/1.1'].freeze
|
65
|
-
FALLBACK = 'http/1.1'
|
66
65
|
def self.configure_tls(opts)
|
67
66
|
return false unless opts[:tls]
|
68
67
|
|
69
68
|
tls = {
|
70
69
|
protocols: PROTOCOLS,
|
71
|
-
fallback:
|
70
|
+
fallback: 'http/1.1'
|
72
71
|
}
|
73
72
|
tls[:verify_peer] = true if opts[:verify_peer]
|
74
73
|
tls[:ciphers] = opts[:ciphers] if opts[:ciphers]
|
@@ -31,11 +31,6 @@ module SpiderGazelle
|
|
31
31
|
req.header.frozen? ? req.header = header : req.header << header
|
32
32
|
end
|
33
33
|
|
34
|
-
DASH = '-'
|
35
|
-
UNDERSCORE = '_'
|
36
|
-
HTTP_META = 'HTTP_'
|
37
|
-
COMMA = ', '
|
38
|
-
|
39
34
|
def on_header_value(parser, value)
|
40
35
|
req = @connection.parsing
|
41
36
|
if req.header.frozen?
|
@@ -43,11 +38,11 @@ module SpiderGazelle
|
|
43
38
|
else
|
44
39
|
header = req.header
|
45
40
|
header.upcase!
|
46
|
-
header.gsub!(
|
47
|
-
header.prepend(
|
41
|
+
header.gsub!('-', '_')
|
42
|
+
header.prepend('HTTP_')
|
48
43
|
header.freeze
|
49
44
|
if req.env[header]
|
50
|
-
req.env[header] <<
|
45
|
+
req.env[header] << ', '
|
51
46
|
req.env[header] << value
|
52
47
|
else
|
53
48
|
req.env[header] = String.new(value)
|
@@ -99,16 +94,13 @@ module SpiderGazelle
|
|
99
94
|
def self.on_progress(data, socket); end
|
100
95
|
DUMMY_PROGRESS = self.method :on_progress
|
101
96
|
|
102
|
-
HTTP = 'http'
|
103
|
-
HTTPS = 'https'
|
104
|
-
|
105
97
|
def load(socket, port, app, tls)
|
106
98
|
@socket = socket
|
107
99
|
@port = port
|
108
100
|
@app = app
|
109
101
|
|
110
102
|
@remote_ip = socket.peername[0]
|
111
|
-
@scheme = tls ?
|
103
|
+
@scheme = tls ? 'https' : 'http'
|
112
104
|
|
113
105
|
set_on_close(socket)
|
114
106
|
end
|
@@ -161,12 +153,10 @@ module SpiderGazelle
|
|
161
153
|
@parsing = Request.new @thread, @app, @port, @remote_ip, @scheme, @socket
|
162
154
|
end
|
163
155
|
|
164
|
-
REQUEST_METHOD = 'REQUEST_METHOD'
|
165
156
|
def headers_complete
|
166
|
-
@parsing.env[REQUEST_METHOD] = @state.http_method.to_s
|
157
|
+
@parsing.env['REQUEST_METHOD'] = @state.http_method.to_s
|
167
158
|
end
|
168
159
|
|
169
|
-
ASYNC = "async.callback"
|
170
160
|
def finished_parsing
|
171
161
|
request = @parsing
|
172
162
|
@parsing = nil
|
@@ -180,7 +170,7 @@ module SpiderGazelle
|
|
180
170
|
# Process the async request in the same way as Mizuno
|
181
171
|
# See: http://polycrystal.org/2012/04/15/asynchronous_responses_in_rack.html
|
182
172
|
# Process a response that was marked as async.
|
183
|
-
request.env[
|
173
|
+
request.env['async.callback'] = proc { |data|
|
184
174
|
@thread.schedule { request.defer.resolve([request, data]) }
|
185
175
|
}
|
186
176
|
request.upgrade = @state.upgrade?
|
@@ -235,16 +225,6 @@ module SpiderGazelle
|
|
235
225
|
process_next
|
236
226
|
end
|
237
227
|
|
238
|
-
|
239
|
-
HEAD = 'HEAD'
|
240
|
-
ETAG = 'ETag'
|
241
|
-
HTTP_ETAG = 'HTTP_ETAG'
|
242
|
-
CONTENT_LENGTH2 = 'Content-Length'
|
243
|
-
TRANSFER_ENCODING = 'Transfer-Encoding'
|
244
|
-
CHUNKED = 'chunked'
|
245
|
-
ZERO = '0'
|
246
|
-
NOT_MODIFIED_304 = "HTTP/1.1 304 Not Modified\r\n"
|
247
|
-
|
248
228
|
def send_next_response
|
249
229
|
request, result = @responses.shift
|
250
230
|
@transmitting = request
|
@@ -262,7 +242,7 @@ module SpiderGazelle
|
|
262
242
|
body.close if body.respond_to?(:close)
|
263
243
|
else
|
264
244
|
status, headers, body = result
|
265
|
-
send_body = request.env[REQUEST_METHOD] != HEAD
|
245
|
+
send_body = request.env['REQUEST_METHOD'] != 'HEAD'
|
266
246
|
|
267
247
|
# If a file, stream the body in a non-blocking fashion
|
268
248
|
if body.respond_to? :to_path
|
@@ -280,17 +260,17 @@ module SpiderGazelle
|
|
280
260
|
#if etag == request.env[HTTP_ETAG]
|
281
261
|
# header = NOT_MODIFIED_304.dup
|
282
262
|
# add_header(header, ETAG, etag)
|
283
|
-
# header <<
|
263
|
+
# header << "\r\n"
|
284
264
|
# @socket.write header
|
285
265
|
# return
|
286
266
|
#end
|
287
267
|
#headers[ETAG] ||= etag
|
288
268
|
|
289
|
-
if headers[
|
269
|
+
if headers['Content-Length']
|
290
270
|
type = :raw
|
291
271
|
else
|
292
272
|
type = :http
|
293
|
-
headers[
|
273
|
+
headers['Transfer-Encoding'] = 'chunked'
|
294
274
|
end
|
295
275
|
|
296
276
|
data_written = true
|
@@ -339,7 +319,7 @@ module SpiderGazelle
|
|
339
319
|
# Optimize the response
|
340
320
|
begin
|
341
321
|
if body.size < 2
|
342
|
-
headers[
|
322
|
+
headers['Content-Length'] = body.size == 1 ? body[0].bytesize.to_s : '0'
|
343
323
|
end
|
344
324
|
rescue # just in case
|
345
325
|
end
|
@@ -359,59 +339,51 @@ module SpiderGazelle
|
|
359
339
|
end
|
360
340
|
end
|
361
341
|
|
362
|
-
CLOSE_CHUNKED = "0\r\n\r\n"
|
363
342
|
def write_response(request, status, headers, body)
|
364
343
|
keep_alive = request.keep_alive
|
365
344
|
|
366
|
-
if headers[
|
367
|
-
headers[
|
345
|
+
if headers['Content-Length']
|
346
|
+
headers['Content-Length'] = headers['Content-Length'].to_s
|
368
347
|
write_headers keep_alive, status, headers
|
369
348
|
|
370
349
|
# Stream the response (pass directly into @socket.write)
|
371
350
|
body.each &@socket.method(:write)
|
372
351
|
@socket.shutdown if keep_alive == false
|
373
352
|
else
|
374
|
-
headers[
|
353
|
+
headers['Transfer-Encoding'] = 'chunked'
|
375
354
|
write_headers keep_alive, status, headers
|
376
355
|
|
377
356
|
# Stream the response
|
378
357
|
body.each &@write_chunk
|
379
358
|
|
380
|
-
@socket.write
|
359
|
+
@socket.write "0\r\n\r\n"
|
381
360
|
@socket.shutdown if keep_alive == false
|
382
361
|
end
|
383
362
|
|
384
363
|
body.close if body.respond_to?(:close)
|
385
364
|
end
|
386
365
|
|
387
|
-
COLON_SPACE = ': '
|
388
|
-
LINE_END = "\r\n"
|
389
366
|
def add_header(header, key, value)
|
390
367
|
header << key
|
391
|
-
header <<
|
368
|
+
header << ': '
|
392
369
|
header << value
|
393
|
-
header <<
|
370
|
+
header << "\r\n"
|
394
371
|
end
|
395
372
|
|
396
|
-
CONNECTION = "Connection"
|
397
|
-
NEWLINE = "\n"
|
398
|
-
CLOSE = "close"
|
399
|
-
RACK = "rack"
|
400
373
|
def write_headers(keep_alive, status, headers)
|
401
|
-
headers[
|
374
|
+
headers['Connection'] = 'close' if keep_alive == false
|
402
375
|
|
403
376
|
header = String.new("HTTP/1.1 #{status} #{fetch_code(status)}\r\n")
|
404
377
|
headers.each do |key, value|
|
405
|
-
next if key.start_with?
|
406
|
-
value.to_s.split(
|
378
|
+
next if key.start_with? 'rack'
|
379
|
+
value.to_s.split("\n").each {|val| add_header(header, key, val)}
|
407
380
|
end
|
408
|
-
header <<
|
381
|
+
header << "\r\n"
|
409
382
|
@socket.write header
|
410
383
|
end
|
411
384
|
|
412
|
-
HEX_ENCODED = 16
|
413
385
|
def write_chunk(part)
|
414
|
-
chunk = part.bytesize.to_s(
|
386
|
+
chunk = part.bytesize.to_s(16) << "\r\n" << part << "\r\n"
|
415
387
|
@socket.write chunk
|
416
388
|
end
|
417
389
|
|
@@ -446,19 +418,17 @@ module SpiderGazelle
|
|
446
418
|
end
|
447
419
|
end
|
448
420
|
|
449
|
-
ERROR_400_RESPONSE = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
450
421
|
def send_parsing_error
|
451
422
|
@logger.info "Parsing error!"
|
452
423
|
@socket.stop_read
|
453
|
-
@socket.write
|
424
|
+
@socket.write "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
454
425
|
@socket.shutdown
|
455
426
|
end
|
456
427
|
|
457
|
-
ERROR_500_RESPONSE = "HTTP/1.1 500 Internal Server Error\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
458
428
|
def send_internal_error
|
459
429
|
@logger.info "Internal error"
|
460
430
|
@socket.stop_read
|
461
|
-
@socket.write
|
431
|
+
@socket.write "HTTP/1.1 500 Internal Server Error\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
462
432
|
@socket.shutdown
|
463
433
|
end
|
464
434
|
end
|
@@ -5,46 +5,26 @@ require 'rack' # Ruby webserver abstraction
|
|
5
5
|
|
6
6
|
module SpiderGazelle
|
7
7
|
class Request < ::Libuv::Q::DeferredPromise
|
8
|
-
RACK_VERSION = 'rack.version'
|
9
|
-
RACK_ERRORS = 'rack.errors'
|
10
|
-
RACK_MULTITHREAD = "rack.multithread"
|
11
|
-
RACK_MULTIPROCESS = "rack.multiprocess"
|
12
|
-
RACK_RUN_ONCE = "rack.run_once"
|
13
|
-
SCRIPT_NAME = "SCRIPT_NAME"
|
14
|
-
EMPTY = ''
|
15
|
-
SERVER_PROTOCOL = "SERVER_PROTOCOL"
|
16
|
-
HTTP_11 = "HTTP/1.1"
|
17
|
-
SERVER_SOFTWARE = "SERVER_SOFTWARE"
|
18
|
-
GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
|
19
|
-
CGI_VER = "CGI/1.2"
|
20
|
-
SERVER = "SpiderGazelle"
|
21
|
-
LOCALHOST = 'localhost'
|
22
|
-
|
23
8
|
|
24
9
|
# TODO:: Add HTTP headers to the env and capitalise them and prefix them with HTTP_
|
25
10
|
# convert - signs to underscores
|
26
11
|
PROTO_ENV = {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
SERVER_SOFTWARE => SERVER
|
12
|
+
'rack.version' => ::Rack::VERSION, # Should be an array of integers
|
13
|
+
'rack.errors' => $stderr, # An error stream that supports: puts, write and flush
|
14
|
+
'rack.multithread' => true, # can the app be simultaneously invoked by another thread?
|
15
|
+
'rack.multiprocess' => false, # will the app be simultaneously be invoked in a separate process?
|
16
|
+
'rack.run_once' => false, # this isn't CGI so will always be false
|
17
|
+
'SCRIPT_NAME' => ENV['SCRIPT_NAME'] || '', # The virtual path of the app base (empty if root)
|
18
|
+
'SERVER_PROTOCOL' => 'HTTP/1.1',
|
19
|
+
|
20
|
+
'GATEWAY_INTERFACE' => 'CGI/1.2',
|
21
|
+
'SERVER_SOFTWARE' => 'SpiderGazelle'
|
38
22
|
}
|
39
23
|
|
40
24
|
attr_accessor :env, :url, :header, :body, :keep_alive, :upgrade
|
41
25
|
attr_reader :hijacked, :defer, :is_async
|
42
26
|
|
43
27
|
|
44
|
-
SERVER_PORT = "SERVER_PORT"
|
45
|
-
REMOTE_ADDR = "REMOTE_ADDR"
|
46
|
-
RACK_URL_SCHEME = "rack.url_scheme"
|
47
|
-
|
48
28
|
def initialize(thread, app, port, remote_ip, scheme, socket)
|
49
29
|
super(thread, thread.defer)
|
50
30
|
|
@@ -54,81 +34,53 @@ module SpiderGazelle
|
|
54
34
|
@header = String.new
|
55
35
|
@url = String.new
|
56
36
|
@env = PROTO_ENV.dup
|
57
|
-
@env[SERVER_PORT] = port
|
58
|
-
@env[REMOTE_ADDR] = remote_ip
|
59
|
-
@env[
|
37
|
+
@env['SERVER_PORT'] = port
|
38
|
+
@env['REMOTE_ADDR'] = remote_ip
|
39
|
+
@env['rack.url_scheme'] = scheme
|
60
40
|
end
|
61
|
-
|
62
|
-
|
63
|
-
CONTENT_LENGTH = "CONTENT_LENGTH"
|
64
|
-
HTTP_CONTENT_LENGTH = "HTTP_CONTENT_LENGTH"
|
65
|
-
CONTENT_TYPE = "CONTENT_TYPE"
|
66
|
-
HTTP_CONTENT_TYPE = "HTTP_CONTENT_TYPE"
|
67
|
-
DEFAULT_TYPE = "text/plain"
|
68
|
-
REQUEST_URI= "REQUEST_URI"
|
69
|
-
ASCII_8BIT = "ASCII-8BIT"
|
70
|
-
RACK_INPUT = "rack.input"
|
71
|
-
PATH_INFO = "PATH_INFO"
|
72
|
-
REQUEST_PATH = "REQUEST_PATH"
|
73
|
-
QUERY_STRING = "QUERY_STRING"
|
74
|
-
HTTP_HOST = "HTTP_HOST"
|
75
|
-
COLON = ":"
|
76
|
-
SERVER_NAME = "SERVER_NAME"
|
77
|
-
# Hijacking IO is supported
|
78
|
-
HIJACK_P = "rack.hijack?"
|
79
|
-
# Callback for indicating that this socket will be hijacked
|
80
|
-
HIJACK = "rack.hijack"
|
81
|
-
# The object for performing IO on after hijack is called
|
82
|
-
HIJACK_IO = "rack.hijack_io"
|
83
|
-
QUESTION_MARK = "?"
|
84
41
|
|
85
|
-
HTTP_UPGRADE = 'HTTP_UPGRADE'
|
86
|
-
USE_HTTP2 = 'h2c'
|
87
|
-
|
88
|
-
|
89
|
-
|
90
42
|
|
91
43
|
def execute!
|
92
|
-
@env[CONTENT_LENGTH] = @env.delete(HTTP_CONTENT_LENGTH) || @body.bytesize.to_s
|
93
|
-
@env[CONTENT_TYPE] = @env.delete(HTTP_CONTENT_TYPE) ||
|
94
|
-
@env[REQUEST_URI] = @url.freeze
|
44
|
+
@env['CONTENT_LENGTH'] = @env.delete('HTTP_CONTENT_LENGTH') || @body.bytesize.to_s
|
45
|
+
@env['CONTENT_TYPE'] = @env.delete('HTTP_CONTENT_TYPE') || 'text/plain'
|
46
|
+
@env['REQUEST_URI'] = @url.freeze
|
95
47
|
|
96
48
|
# For Rack::Lint on 1.9, ensure that the encoding is always for spec
|
97
|
-
@body.force_encoding(ASCII_8BIT)
|
98
|
-
@env[
|
49
|
+
@body.force_encoding(Encoding::ASCII_8BIT)
|
50
|
+
@env['rack.input'] = StringIO.new @body
|
99
51
|
|
100
52
|
# Break the request into its components
|
101
|
-
query_start = @url.index
|
53
|
+
query_start = @url.index '?'
|
102
54
|
if query_start
|
103
55
|
path = @url[0...query_start].freeze
|
104
|
-
@env[PATH_INFO] = path
|
105
|
-
@env[REQUEST_PATH] = path
|
106
|
-
@env[QUERY_STRING] = @url[query_start + 1..-1].freeze
|
56
|
+
@env['PATH_INFO'] = path
|
57
|
+
@env['REQUEST_PATH'] = path
|
58
|
+
@env['QUERY_STRING'] = @url[query_start + 1..-1].freeze
|
107
59
|
else
|
108
|
-
@env[PATH_INFO] = @url
|
109
|
-
@env[REQUEST_PATH] = @url
|
110
|
-
@env[QUERY_STRING] =
|
60
|
+
@env['PATH_INFO'] = @url
|
61
|
+
@env['REQUEST_PATH'] = @url
|
62
|
+
@env['QUERY_STRING'] = ''
|
111
63
|
end
|
112
64
|
|
113
65
|
# Grab the host name from the request
|
114
|
-
if host = @env[HTTP_HOST]
|
115
|
-
if colon = host.index(
|
116
|
-
@env[SERVER_NAME] = host[0, colon]
|
117
|
-
@env[SERVER_PORT] = host[colon + 1, host.bytesize]
|
66
|
+
if host = @env['HTTP_HOST']
|
67
|
+
if colon = host.index(':')
|
68
|
+
@env['SERVER_NAME'] = host[0, colon]
|
69
|
+
@env['SERVER_PORT'] = host[colon + 1, host.bytesize]
|
118
70
|
else
|
119
|
-
@env[SERVER_NAME] = host
|
71
|
+
@env['SERVER_NAME'] = host
|
120
72
|
end
|
121
73
|
else
|
122
|
-
@env[SERVER_NAME] =
|
74
|
+
@env['SERVER_NAME'] = 'localhost'
|
123
75
|
end
|
124
76
|
|
125
|
-
if @upgrade == true && @env[HTTP_UPGRADE] ==
|
77
|
+
if @upgrade == true && @env['HTTP_UPGRADE'] == 'h2c'
|
126
78
|
# TODO:: implement the upgrade process here
|
127
79
|
end
|
128
80
|
|
129
81
|
# Provide hijack options
|
130
|
-
@env[
|
131
|
-
@env[
|
82
|
+
@env['rack.hijack?'] = true
|
83
|
+
@env['rack.hijack'] = proc { @env['rack.hijack_io'] = @socket }
|
132
84
|
|
133
85
|
# Execute the request
|
134
86
|
# NOTE:: Catch was overloaded by Promise so this does the trick now
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spider-gazelle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.3
|
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: 2016-11-
|
11
|
+
date: 2016-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-parser
|