class EmmyHttp::Client::Client
Attributes
adapter[RW]
connection[RW]
decoder[RW]
operation[RW]
parser[RW]
redirects[RW]
request[RW]
response[RW]
state[RW]
stop_reason[RW]
url[RW]
Public Class Methods
new(request, adapter)
click to toggle source
# File lib/emmy_http/client/client.rb, line 21 def initialize(request, adapter) @request = request @adapter = adapter @operation = adapter.operation @redirects = 0 #@cookie = Cookie.new prepare_url change_state(:idle) end
Public Instance Methods
attach(conn)
click to toggle source
# File lib/emmy_http/client/client.rb, line 217 def attach(conn) listen conn, :connect, :connect listen conn, :data, :data listen conn, :close, :close end
change_state(new_state)
click to toggle source
# File lib/emmy_http/client/client.rb, line 212 def change_state(new_state) @state = new_state change!(state, self) end
close(reason=nil)
click to toggle source
# File lib/emmy_http/client/client.rb, line 78 def close(reason=nil) if state == :body && !response.content_length? response.finish end if response && response.redirection? change_state(:redirect) self.url = url + response.location self.response = nil parser.reset! begin operation.reconnect rescue EventMachine::ConnectionError => e finalize(e.to_s) end return end finalize(stop_reason || reason) end
connect()
click to toggle source
# File lib/emmy_http/client/client.rb, line 66 def connect connection.start_tls(request.ssl ? request.ssl.serializable_hash : {}) if ssl? send_request change_state(:wait_response) end
data(chunk)
click to toggle source
# File lib/emmy_http/client/client.rb, line 72 def data(chunk) parser << chunk rescue EmmyHttp::ParserError => e stop(e.message) end
dettach(conn)
click to toggle source
# File lib/emmy_http/client/client.rb, line 223 def dettach(conn) stop_listen conn, :connect stop_listen conn, :data stop_listen conn, :close end
finalize(reason=nil)
click to toggle source
# File lib/emmy_http/client/client.rb, line 187 def finalize(reason=nil) dettach(connection) if response && response.finished? change_state(:success) response.data!(decoder.finalize || '') if decoder operation.success!(response, operation, connection) else change_state(:catch_error) operation.error!(reason ? reason.to_s : 'bad response', operation, connection) end end
initialize_connection(conn)
click to toggle source
# File lib/emmy_http/client/client.rb, line 31 def initialize_connection(conn) @connection = conn @parser = Client::Parser.new #@parser.header_value_type = :mixed client = self conn.pending_connect_timeout = request.timeouts.connect conn.comm_inactivity_timeout = request.timeouts.inactivity attach(conn) parser.on :head do |headers| #parser.http_version change_state(:body) client.response = EmmyHttp::Response.new( status: parser.status_code, # for responses headers: headers, body: '' ) client.decoder = new_decoder_by_encoding(headers['Content-Encoding']) if request.decoding operation.head!(response, operation, connection) #parser.reset = true if request.no_body? end parser.on :body do |chunk| response.data!(client.decoder ? (client.decoder.decompress(chunk) || '') : chunk) end parser.on :completed do client.response.finish request.keep_alive? ? finalize : client.stop end change_state(:wait_connect) end
new_decoder_by_encoding(encoding)
click to toggle source
# File lib/emmy_http/client/client.rb, line 229 def new_decoder_by_encoding(encoding) case encoding when 'deflate', 'compressed' EmmyHttp::Client::Decoders::Deflate.new when 'gzip' EmmyHttp::Client::Decoders::GZip.new else nil end end
prepare_body(headers)
click to toggle source
# File lib/emmy_http/client/client.rb, line 123 def prepare_body(headers) body, form, json, file = request.body, request.form, request.json, request.file if body raise "body cannot be hash use form attribute instead" if body.is_a?(Hash) body_text = body.is_a?(Array) ? body.join : body.to_s headers['Content-Length'] = body_text.bytesize body_text elsif form form_encoded = form.is_a?(String) ? form : Encoders.www_form(form) body_text = Encoders.rfc3986(form_encoded) headers['Content-Type'] = 'application/x-www-form-urlencoded' headers['Content-Length'] = body_text.bytesize body_text elsif json json_string = json.is_a?(String) ? json : (json.respond_to?(:to_json) ? json.to_json : JSON.dump(json)) headers['Content-Type'] = 'application/json' headers['Content-Length'] = json_string.size json_string elsif file headers['Content-Length'] = File.size(file) nil else headers['Content-Length'] = 0 if %w('POST PUT').include? request.type '' # empty body end end
prepare_headers(headers)
click to toggle source
# File lib/emmy_http/client/client.rb, line 154 def prepare_headers(headers) headers.merge!(EmmyHttp::Utils.convert_headers(request.headers)) # TODO: proxy authorization # TODO: cookie headers['Connection'] = 'close' unless request.keep_alive? headers['User-Agent'] = Client::USER_AGENT unless headers.key? 'User-Agent' headers['Authorization'] ||= Encoders.encode_auth(url.userinfo) if url.userinfo unless headers.key? 'Host' headers['Host'] = url.host headers['Host'] += ":#{url.port}" unless url.port.nil? || (url.scheme == 'http' && url.port == 80) || (url.scheme == 'https' && url.port == 443) end end
prepare_url()
click to toggle source
# File lib/emmy_http/client/client.rb, line 108 def prepare_url @url = request.real_url raise 'relative url' if @url.relative? @url.normalize! if path = request.real_path raise 'path is not relative' unless path.relative? @url += path end @url.user = request.user if request.user @url.password = request.password if request.password @url.query = request.query.is_a?(Hash) ? Encoders.query(request.query) : request.query.to_s if request.query end
send_http_request(headers, body)
click to toggle source
# File lib/emmy_http/client/client.rb, line 172 def send_http_request(headers, body) # Send headers head = "#{request.type.upcase} #{url_path} #{Client::HTTP_VERSION}\r\n" head = headers.inject(head) { |r, (k, v)| "#{r}#{k}:#{v}\r\n" } head += "\r\n" connection.send_data head # Send body connection.send_data body if body connection.send_stream_file_data request.file if request.file end
send_request()
click to toggle source
# File lib/emmy_http/client/client.rb, line 99 def send_request headers = {} body = prepare_body(headers) body = Encoders.encode_body(request.headers["Content-Encoding"], body) if request.encoding? prepare_headers(headers) send_http_request(headers, body) end
ssl?()
click to toggle source
# File lib/emmy_http/client/client.rb, line 203 def ssl? request.ssl || url.scheme == 'https' || url.port == 443 end
stop(reason=nil)
click to toggle source
# File lib/emmy_http/client/client.rb, line 207 def stop(reason=nil) @stop_reason ||= reason connection.close_connection if connection end
to_a()
click to toggle source
# File lib/emmy_http/client/client.rb, line 240 def to_a ["tcp://#{url.host}:#{url.port || url.default_port}", connection || EmmyMachine::Connection, method(:initialize_connection), self] end
url_path()
click to toggle source
# File lib/emmy_http/client/client.rb, line 199 def url_path url.query ? url.path + '?' + url.query : url.path end