Parent

Included Modules

EventMachine::HttpClient

Constants

TRANSFER_ENCODING
CONTENT_ENCODING
CONTENT_LENGTH
KEEP_ALIVE
SET_COOKIE
LOCATION
HOST
CRLF

Attributes

method[RW]
options[RW]
uri[RW]
response[R]
response_header[R]
error[R]
redirects[R]
last_effective_url[R]

Public Instance Methods

connection_completed() click to toggle source

start HTTP request once we establish connection to host

     # File lib/em-http/client.rb, line 212
212:     def connection_completed
213:       # if connecting to proxy, then first negotiate the connection
214:       # to intermediate server and wait for 200 response
215:       if @options[:proxy] and @state == :response_header
216:         @state = :response_proxy
217:         send_request_header
218: 
219:         # if connecting via proxy, then state will be :proxy_connected,
220:         # indicating successful tunnel. from here, initiate normal http
221:         # exchange
222:       else
223:         @state = :response_header
224:         ssl = @options[:tls] || @options[:ssl] || {}
225:         start_tls(ssl) if @uri.scheme == "https" or @uri.port == 443
226:         send_request_header
227:         send_request_body
228:       end
229:     end
disconnect(&blk) click to toggle source

assign disconnect callback for websocket

     # File lib/em-http/client.rb, line 257
257:     def disconnect(&blk)
258:       @disconnect = blk
259:     end
dispatch() click to toggle source

Response processing

     # File lib/em-http/client.rb, line 406
406:     def dispatch
407:       while case @state
408:           when :response_proxy
409:             parse_response_header
410:           when :response_header
411:             parse_response_header
412:           when :chunk_header
413:             parse_chunk_header
414:           when :chunk_body
415:             process_chunk_body
416:           when :chunk_footer
417:             process_chunk_footer
418:           when :response_footer
419:             process_response_footer
420:           when :body
421:             process_body
422:           when :websocket
423:             process_websocket
424:           when :finished, :invalid
425:             break
426:           else raise RuntimeError, "invalid state: #{@state}"
427:         end
428:       end
normalize_body() click to toggle source
     # File lib/em-http/client.rb, line 275
275:     def normalize_body
276:       @normalized_body ||= begin
277:         if @options[:body].is_a? Hash
278:           @options[:body].to_params
279:         else
280:           @options[:body]
281:         end
282:       end
283:     end
on_body_data(data) click to toggle source

Called when part of the body has been read

     # File lib/em-http/client.rb, line 357
357:     def on_body_data(data)
358:       if @content_decoder
359:         begin
360:           @content_decoder << data
361:         rescue HttpDecoders::DecoderError
362:           on_error "Content-decoder error"
363:         end
364:       else
365:         on_decoded_body_data(data)
366:       end
367:     end
on_decoded_body_data(data) click to toggle source
     # File lib/em-http/client.rb, line 369
369:     def on_decoded_body_data(data)
370:       if @stream
371:         @stream.call(data)
372:       else
373:         @response << data
374:       end
375:     end
on_error(msg, dns_error = false) click to toggle source

request failed, invoke errback

     # File lib/em-http/client.rb, line 243
243:     def on_error(msg, dns_error = false)
244:       @error = msg
245: 
246:       # no connection signature on DNS failures
247:       # fail the connection directly
248:       dns_error == true ? fail(self) : unbind
249:     end
on_request_complete() click to toggle source

request is done, invoke the callback

     # File lib/em-http/client.rb, line 232
232:     def on_request_complete
233:       begin
234:         @content_decoder.finalize! if @content_decoder
235:       rescue HttpDecoders::DecoderError
236:         on_error "Content-decoder error"
237:       end
238: 
239:       close_connection
240:     end
post_init() click to toggle source
     # File lib/em-http/client.rb, line 195
195:     def post_init
196:       @parser = HttpClientParser.new
197:       @data = EventMachine::Buffer.new
198:       @chunk_header = HttpChunkHeader.new
199:       @response_header = HttpResponseHeader.new
200:       @parser_nbytes = 0
201:       @redirects = 0
202:       @response = ''
203:       @error = ''
204:       @last_effective_url = nil
205:       @content_decoder = nil
206:       @stream = nil
207:       @disconnect = nil
208:       @state = :response_header
209:     end
receive_data(data) click to toggle source
     # File lib/em-http/client.rb, line 351
351:     def receive_data(data)
352:       @data << data
353:       dispatch
354:     end
send(data) click to toggle source

raw data push from the client (WebSocket) should only be invoked after handshake, otherwise it will inject data into the header exchange

frames need to start with 0x00-0x7f byte and end with an 0xFF byte. Per spec, we can also set the first byte to a value betweent 0x80 and 0xFF, followed by a leading length indicator

     # File lib/em-http/client.rb, line 269
269:     def send(data)
270:       if @state == :websocket
271:         send_data("\x00#{data}\xff")
272:       end
273:     end
send_request_body() click to toggle source
     # File lib/em-http/client.rb, line 341
341:     def send_request_body
342:       if @options[:body]
343:         body = normalize_body
344:         send_data body
345:         return
346:       elsif @options[:file]
347:         stream_file_data @options[:file], :http_chunks => false
348:       end
349:     end
send_request_header() click to toggle source
     # File lib/em-http/client.rb, line 287
287:     def send_request_header
288:       query   = @options[:query]
289:       head    = @options[:head] ? munge_header_keys(@options[:head]) : {}
290:       file    = @options[:file]
291:       body    = normalize_body
292:       request_header = nil
293: 
294:       if @state == :response_proxy
295:         proxy = @options[:proxy]
296: 
297:         # initialize headers to establish the HTTP tunnel
298:         head = proxy[:head] ? munge_header_keys(proxy[:head]) : {}
299:         head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization]
300:         request_header = HTTP_REQUEST_HEADER % ['CONNECT', "#{@uri.host}:#{@uri.port}"]
301: 
302:       elsif websocket?
303:         head['upgrade'] = 'WebSocket'
304:         head['connection'] = 'Upgrade'
305:         head['origin'] = @options[:origin] || @uri.host
306: 
307:       else
308:         # Set the Content-Length if file is given
309:         head['content-length'] = File.size(file) if file
310: 
311:         # Set the Content-Length if body is given
312:         head['content-length'] =  body.bytesize if body
313: 
314:         # Set the cookie header if provided
315:         if cookie = head.delete('cookie')
316:           head['cookie'] = encode_cookie(cookie)
317:         end
318: 
319:         # Set content-type header if missing and body is a Ruby hash
320:         if not head['content-type'] and options[:body].is_a? Hash
321:           head['content-type'] = "application/x-www-form-urlencoded"
322:         end
323:       end
324: 
325:       # Set the Host header if it hasn't been specified already
326:       head['host'] ||= encode_host
327: 
328:       # Set the User-Agent if it hasn't been specified
329:       head['user-agent'] ||= "EventMachine HttpClient"
330: 
331:       # Record last seen URL
332:       @last_effective_url = @uri
333: 
334:       # Build the request headers
335:       request_header ||= encode_request(@method, @uri.path, query, @uri.query)
336:       request_header << encode_headers(head)
337:       request_header << CRLF
338:       send_data request_header
339:     end
stream(&blk) click to toggle source

assign a stream processing block

     # File lib/em-http/client.rb, line 252
252:     def stream(&blk)
253:       @stream = blk
254:     end
unbind() click to toggle source
     # File lib/em-http/client.rb, line 377
377:     def unbind
378:       if (@state == :finished) && (@last_effective_url != @uri) && (@redirects < @options[:redirects])
379:         # update uri to redirect location if we're allowed to traverse deeper
380:         @uri = @last_effective_url
381: 
382:         # keep track of the depth of requests we made in this session
383:         @redirects += 1
384: 
385:         # swap current connection and reassign current handler
386:         req = HttpOptions.new(@method, @uri, @options)
387:         reconnect(req.host, req.port)
388: 
389:         @response_header = HttpResponseHeader.new
390:         @state = :response_header
391:         @data.clear
392:       else
393:         if @state == :finished || (@state == :body && @bytes_remaining.nil?)
394:           succeed(self)
395:         else
396:           @disconnect.call(self) if @state == :websocket and @disconnect
397:           fail(self)
398:         end
399:       end
400:     end
websocket?() click to toggle source
     # File lib/em-http/client.rb, line 285
285:     def websocket?; @uri.scheme == 'ws'; end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.