Class: HTTPX::Connection::HTTP1
Constant Summary
collapse
- MAX_REQUESTS =
100
- CRLF =
"\r\n"
Constants included
from Loggable
Loggable::COLORS
Instance Attribute Summary collapse
Instance Method Summary
collapse
Methods included from Loggable
#log, #log_exception
#emit, #on, #once, #only
Constructor Details
#initialize(buffer, options) ⇒ HTTP1
Returns a new instance of HTTP1.
15
16
17
18
19
20
21
22
23
24
25
|
# File 'lib/httpx/connection/http1.rb', line 15
def initialize(buffer, options)
@options = Options.new(options)
@max_concurrent_requests = @options.max_concurrent_requests || MAX_REQUESTS
@max_requests = @options.max_requests || MAX_REQUESTS
@parser = Parser::HTTP1.new(self)
@buffer = buffer
@version = [1, 1]
@pending = []
@requests = []
@handshake_completed = false
end
|
Instance Attribute Details
#pending ⇒ Object
Returns the value of attribute pending.
13
14
15
|
# File 'lib/httpx/connection/http1.rb', line 13
def pending
@pending
end
|
#requests ⇒ Object
Returns the value of attribute requests.
13
14
15
|
# File 'lib/httpx/connection/http1.rb', line 13
def requests
@requests
end
|
Instance Method Details
#<<(data) ⇒ Object
72
73
74
|
# File 'lib/httpx/connection/http1.rb', line 72
def <<(data)
@parser << data
end
|
#close ⇒ Object
52
53
54
55
|
# File 'lib/httpx/connection/http1.rb', line 52
def close
reset
emit(:close, true)
end
|
#consume ⇒ Object
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/httpx/connection/http1.rb', line 88
def consume
requests_limit = [@max_requests, @requests.size].min
concurrent_requests_limit = [@max_concurrent_requests, requests_limit].min
@requests.each_with_index do |request, idx|
break if idx >= concurrent_requests_limit
next if request.state == :done
handle(request)
end
end
|
#dispatch ⇒ Object
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
# File 'lib/httpx/connection/http1.rb', line 151
def dispatch
if @request.expects?
@parser.reset!
return handle(@request)
end
request = @request
@request = nil
@requests.shift
response = request.response
emit(:response, request, response)
if @parser.upgrade?
response << @parser.upgrade_data
throw(:called)
end
@parser.reset!
@max_requests -= 1
manage_connection(response)
send(@pending.shift) unless @pending.empty?
end
|
#empty? ⇒ Boolean
61
62
63
64
65
66
67
68
69
70
|
# File 'lib/httpx/connection/http1.rb', line 61
def empty?
@requests.empty? || (
!@requests.first.response.nil? &&
(@requests.size == 1 || !@requests.last.response.nil?)
)
end
|
#exhausted? ⇒ Boolean
57
58
59
|
# File 'lib/httpx/connection/http1.rb', line 57
def exhausted?
!@max_requests.positive?
end
|
#handle_error(ex) ⇒ Object
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
# File 'lib/httpx/connection/http1.rb', line 175
def handle_error(ex)
if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request && @request.response &&
!@request.response..key?("content-length") &&
!@request.response..key?("transfer-encoding")
catch(:called) { on_complete }
return
end
if @pipelining
disable
else
@requests.each do |request|
emit(:error, request, ex)
end
@pending.each do |request|
emit(:error, request, ex)
end
end
end
|
#interests ⇒ Object
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/httpx/connection/http1.rb', line 31
def interests
return :r if @request
return if @requests.empty?
request = @requests.first
return unless request
return :w if request.interests == :w || !@buffer.empty?
:r
end
|
#on_complete ⇒ Object
144
145
146
147
148
149
|
# File 'lib/httpx/connection/http1.rb', line 144
def on_complete
return unless @request
log(level: 2) { "parsing complete" }
dispatch
end
|
#on_data(chunk) ⇒ Object
134
135
136
137
138
139
140
141
142
|
# File 'lib/httpx/connection/http1.rb', line 134
def on_data(chunk)
return unless @request
log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
log(level: 2, color: :green) { "-> #{chunk.inspect}" }
response = @request.response
response << chunk
end
|
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
# File 'lib/httpx/connection/http1.rb', line 107
def (h)
@request = @requests.first
return if @request.response
log(level: 2) { "headers received" }
= @request.options..new(h)
response = @request.options.response_class.new(@request,
@parser.status_code,
@parser.http_version.join("."),
)
log(color: :yellow) { "-> HEADLINE: #{response.status} HTTP/#{@parser.http_version.join(".")}" }
log(color: :yellow) { response..each.map { |f, v| "-> HEADER: #{f}: #{v}" }.join("\n") }
@request.response = response
on_complete if response.complete?
end
|
#on_start ⇒ Object
HTTP Parser callbacks
must be public methods, or else they won’t be reachable
103
104
105
|
# File 'lib/httpx/connection/http1.rb', line 103
def on_start
log(level: 2) { "parsing begins" }
end
|
#on_trailers(h) ⇒ Object
124
125
126
127
128
129
130
131
132
|
# File 'lib/httpx/connection/http1.rb', line 124
def on_trailers(h)
return unless @request
response = @request.response
log(level: 2) { "trailer headers received" }
log(color: :yellow) { h.each.map { |f, v| "-> HEADER: #{f}: #{v.join(", ")}" }.join("\n") }
response.(h)
end
|
#ping ⇒ Object
198
199
200
201
|
# File 'lib/httpx/connection/http1.rb', line 198
def ping
emit(:reset)
emit(:exhausted)
end
|
#reset ⇒ Object
46
47
48
49
50
|
# File 'lib/httpx/connection/http1.rb', line 46
def reset
@max_requests = @options.max_requests || MAX_REQUESTS
@parser.reset!
@handshake_completed = false
end
|
#send(request) ⇒ Object
76
77
78
79
80
81
82
83
84
85
86
|
# File 'lib/httpx/connection/http1.rb', line 76
def send(request)
unless @max_requests.positive?
@pending << request
return
end
return if @requests.include?(request)
@requests << request
@pipelining = true if @requests.size > 1
end
|
#timeout ⇒ Object
27
28
29
|
# File 'lib/httpx/connection/http1.rb', line 27
def timeout
@options.timeout[:operation_timeout]
end
|