class HTTP_Spew::Request
This is the base class actually capable of making a normal HTTP request
Attributes
Stores any exception that was raised in another thread (e.g. ContentMD5 or InputSpray write drivers).
Stores the Rack response (a 3-element Array) on success
May be called by IO.select or for use with IO#wait_*able
Public Class Methods
Creates a new Request
based on a Rack env
and input
object and prepares it for writing to sock
. input
supercedes env since it may be an alternate IO object (such as one filtered through HTTP_Spew::ContentMD5
.
sock
may be the String representing an address created with Socket.pack_sockaddr_un
or Socket.pack_sockaddr_in
, or it may be an actual Socket object
# File lib/http_spew/request.rb, line 26 def initialize(env, input, sock, allow = nil) @to_io = BasicSocket === sock ? sock : start_sock(sock) if Hash === env @buf, @input = env_to_headers(env, input) else @buf, @input = env, input end @allow = allow end
Public Instance Methods
Called by Rack servers after writing a response to a client
# File lib/http_spew/request.rb, line 128 def close @to_io.close @input = nil end
Called by Rack servers to write the response to a client
# File lib/http_spew/request.rb, line 106 def each buf = "" case @to_io.read_nonblock(0x4000, buf, exception: false) when :wait_readable @to_io.wait_readable when nil buf.clear return else yield buf end while true end
Used internally by various HTTP_Spew
elements to report errors across different Threads and Fibers
# File lib/http_spew/request.rb, line 121 def error=(exception) @input.respond_to?(:error=) and @input.error = exception close @error = exception end
returns a 3-element Rack response array on completion returns :wait_readable or :wait_writable if busy Users do not need to call this directly, resume
will return the result of this.
# File lib/http_spew/request.rb, line 83 def read_response buf = @to_io.recv_nonblock(0x4000, Socket::MSG_PEEK, exception: false) or raise HttpSpew::EOF, "upstream server closed connection", [] String === buf or return buf # Kcar::Parser#headers shortens +buf+ for us hdr_len = buf.size r = Kcar::Parser.new.headers({}, buf) or too_big! if @allow && ! @allow.include?(r[0].to_i) raise HTTP_Spew::UnexpectedResponse, "#{r[0].to_i} not in #{@allow.inspect}", [] end # discard the header data from the socket buffer (hdr_len -= buf.size) > 0 and @to_io.read(hdr_len, buf) @response = r << self end
returns a 3-element Rack response array on completion returns :wait_readable or :wait_writable if busy
# File lib/http_spew/request.rb, line 38 def resume if @buf case w = @to_io.write_nonblock(@buf, exception: false) when :wait_writable, :wait_readable return w else # Integer len = @buf.size if w == len @buf = @input ? @input.read(0x4000, @buf) : nil else tmp = @buf.byteslice(w, len - w) @buf.clear @buf = tmp # loop retry, socket buffer could've expanded end end while @buf end read_response end
returns a 3-element Rack response array on successful completion returns an Exception if one was raised
# File lib/http_spew/request.rb, line 59 def run(timeout) t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC) buf, @buf = @buf, nil # make inspect nicer @to_io.write(buf) if @input @to_io.write(buf) while @input.read(0x4000, buf) end buf.clear timeout -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) while :wait_readable == (rv = read_response) && timeout >= 0.0 t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC) @to_io.wait_readable(timeout) if timeout > 0.0 timeout -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) end rv rescue => e @input.respond_to?(:close) and @input.close rescue nil self.error = e end
# File lib/http_spew/request.rb, line 133 def start_sock(ai) ai = Addrinfo.new(ai) unless Addrinfo === ai sock = Socket.new(ai.afamily, :SOCK_STREAM) case sock.connect_nonblock(ai, exception: false) when 0, :wait_writable end sock end