10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/iodine/http/http1.rb', line 10
def on_message data
return if @refuse_requests
@http2_pri_review ||= ( ::Iodine::Http.http2 && ::Iodine::Http::Http2.pre_handshake(self, data) && (return true) ) || true
data = ::StringIO.new data
until data.eof?
request = (@request ||= ::Iodine::Http::Request.new(self))
unless request[:method]
l = data.gets.strip
if l.bytesize > 16_384
write "HTTP/1.0 414 Request-URI Too Long\r\ncontent-length: 20\r\n\r\nRequest URI too Long".freeze
Iodine.warn "Http/1 URI too long, closing connection.".freeze
return close
end
next if l.empty?
request[:method], request[:query], request[:version] = l.split(/[\s]+/.freeze, 3)
return (Iodine.warn('Http1 Protocol Error, closing connection.'.freeze, l, request) && close) unless request[:method] =~ HTTP_METHODS_REGEXP
request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/.freeze)[0]
request[:time_recieved] = Time.now
end
until request[:headers_complete] || (l = data.gets).nil?
if l.include? ':'.freeze
request[:headers_size] ||= 0
request[:headers_size] += l.bytesize
l = l.strip.split(/:[\s]?/.freeze, 2)
l[0].strip! ; l[0].downcase!;
request[l[0]] ? (request[l[0]].is_a?(Array) ? (request[l[0]] << l[1]) : request[l[0]] = [request[l[0]], l[1] ]) : (request[l[0]] = l[1])
elsif l =~ /^[\r]?\n/.freeze
request[:headers_complete] = true
else
Iodine.warn 'Protocol Error, closing connection.'.freeze
return close
end
if request.length > 2096 || request[:headers_size] > 262_144
write "HTTP/1.0 431 Request Header Fields Too Large\r\ncontent-length: 31\r\n\r\nRequest Header Fields Too Large".freeze
return (Iodine.warn('Http1 header overloading, closing connection.'.freeze) && close)
end
end
until request[:body_complete] && request[:headers_complete]
if request['transfer-coding'.freeze] == 'chunked'.freeze
if @parser[:length].to_i == 0
chunk = data.gets
return false unless chunk
@parser[:length] = chunk.to_i(16)
return (Iodine.warn('Protocol Error, closing connection.'.freeze) && close) unless @parser[:length]
request[:body_complete] = true && break if @parser[:length] == 0
@parser[:act_length] = 0
request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze)
end
chunk = data.read(@parser[:length] - @parser[:act_length])
return false unless chunk
request[:body] << chunk
@parser[:act_length] += chunk.bytesize
(@parser[:act_length] = @parser[:length] = 0) && (data.gets) if @parser[:act_length] >= @parser[:length]
elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze)
packet = data.read(request['content-length'.freeze].to_i - request[:body].size)
return false unless packet
request[:body] << packet
request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].size <= 0
elsif request['content-type'.freeze]
Iodine.warn 'Body type protocol error.'.freeze unless request[:body]
line = data.gets
return false unless line
(request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze) ) << line
request[:body_complete] = true if line =~
else
request[:body_complete] = true
end
end
if request[:body] && request[:body].size > ::Iodine::Http.max_body_size
Iodine.warn("Http1 message body too big, closing connection (Iodine::Http.max_body_size == #{::Iodine::Http.max_body_size} bytes) - #{request[:body].size} bytes.")
request.delete(:body).tap {|f| f.close unless f.closed? } rescue false
write "HTTP/1.0 413 Payload Too Large\r\ncontent-length: 17\r\n\r\nPayload Too Large".freeze
return close
end
(@request = ::Iodine::Http::Request.new(self)) && ( (::Iodine::Http.http2 && ::Iodine::Http::Http2.handshake(request, self, data)) || dispatch(request, data) ) if request.delete :body_complete
end
end
|