Class: Iodine::Http::Http1
Instance Attribute Summary
Attributes inherited from Protocol
#io, #locker, #options
Instance Method Summary
collapse
Methods inherited from Protocol
#call, #close, #closed?, each, #id, #initialize, #on_close, #on_shutdown, #ping, #read, #set_timeout, #ssl?, #timeout?, #write
Instance Method Details
#go_away(error_code) ⇒ Object
154
155
156
157
|
# File 'lib/iodine/http/http1.rb', line 154
def go_away error_code
return false if @io.closed?
close
end
|
#on_message(data) ⇒ Object
9
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
94
95
96
97
98
99
|
# File 'lib/iodine/http/http1.rb', line 9
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] = Iodine.time
end
until request[:headers_complete] || (l = data.gets).nil?
if l.include? ':'.freeze
request[:headers_size] ||= 0
request[:headers_size] += l.bytesize
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
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
end
next unless request[:headers_complete]
if request['transfer-coding'.freeze] == 'chunked'.freeze
until request[:body_complete]
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]
return if bad_body_size?
end
elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
until request[:body_complete]
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
return if bad_body_size?
request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].size <= 0
end
elsif request['content-type'.freeze]
until request[:body_complete]
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
return if bad_body_size?
request[:body_complete] = true if line =~
end
else
request[:body_complete] = true
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
|
#on_open ⇒ Object
4
5
6
7
8
|
# File 'lib/iodine/http/http1.rb', line 4
def on_open
set_timeout 1
@refuse_requests = false
@parser = {}
end
|
#send_response(response) ⇒ Object
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/iodine/http/http1.rb', line 101
def send_response response
return false if response..frozen?
body = response.extract_body
request = response.request
= response.
['content-length'.freeze] ||= body.size if body
keep_alive = response.keep_alive
if (request[:version].to_f > 1 && request['connection'.freeze].nil?) || request['connection'.freeze].to_s =~ /ke/i.freeze || (['connection'.freeze] && ['connection'.freeze] =~ /^ke/i.freeze)
keep_alive = true
['connection'.freeze] ||= 'keep-alive'.freeze
['keep-alive'.freeze] ||= "timeout=#{(@timeout ||= 3).to_s}".freeze
else
['connection'.freeze] ||= 'close'.freeze
end
response
return log_finished(response) && (body && body.close) if request.head? || body.nil?
until body.eof?
written = write(body.read 65_536, Thread.current[:write_buffer])
return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
response.bytes_written += written
end
body.close
close unless keep_alive
log_finished response
end
|
#stream_response(response, finish = false) ⇒ Object
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# File 'lib/iodine/http/http1.rb', line 130
def stream_response response, finish = false
set_timeout 15
unless response..frozen?
response['transfer-encoding'.freeze] = 'chunked'.freeze
response.['connection'.freeze] = 'close'.freeze
response
@refuse_requests = true
end
return if response.request.head?
body = response.extract_body
until body.eof?
written = stream_data(body.read 65_536, Thread.current[:write_buffer])
return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
response.bytes_written += written
end if body
if finish
response.bytes_written += stream_data(''.freeze)
log_finished response
close unless response.keep_alive
end
body.close if body
true
end
|