         # File lib/protocols/httpclient.rb, line 98
     98:   def send_request args
     99:     args[:verb] ||= args[:method] # Support :method as an alternative to :verb.
    100:     args[:verb] ||= :get # IS THIS A GOOD IDEA, to default to GET if nothing was specified?
    101:
    102:     verb = args[:verb].to_s.upcase
    103:     unless ["GET", "POST", "PUT", "DELETE", "HEAD"].include?(verb)
    104:       set_deferred_status :failed, {:status => 0} # TODO, not signalling the error type
    105:       return # NOTE THE EARLY RETURN, we're not sending any data.
    106:     end
    107:
    108:     request = args[:request] || "/"
    109:     unless request[0,1] == "/"
    110:       request = "/" + request
    111:     end
    112:
    113:     qs = args[:query_string] || ""
    114:     if qs.length > 0 and qs[0,1] != '?'
    115:       qs = "?" + qs
    116:     end
    117:
    118:     version = args[:version] || "1.1"
    119:
    120:     # Allow an override for the host header if it's not the connect-string.
    121:     host = args[:host_header] || args[:host] || "_"
    122:     # For now, ALWAYS tuck in the port string, although we may want to omit it if it's the default.
    123:     port = args[:port]
    124:
    125:     # POST items.
    126:     postcontenttype = args[:contenttype] || "application/octet-stream"
    127:     postcontent = args[:content] || ""
    128:     raise "oversized content in HTTP POST" if postcontent.length > MaxPostContentLength
    129:
    130:     # ESSENTIAL for the request's line-endings to be CRLF, not LF. Some servers misbehave otherwise.
    131:     # TODO: We ASSUME the caller wants to send a 1.1 request. May not be a good assumption.
    132:     req = [
    133:       "#{verb} #{request}#{qs} HTTP/#{version}",
    134:       "Host: #{host}:#{port}",
    135:       "User-agent: Ruby EventMachine",
    136:     ]
    137:
    138:     if verb == "POST" || verb == "PUT"
    139:       req << "Content-type: #{postcontenttype}"
    140:       req << "Content-length: #{postcontent.length}"
    141:     end
    142:
    143:     # TODO, this cookie handler assumes it's getting a single, semicolon-delimited string.
    144:     # Eventually we will want to deal intelligently with arrays and hashes.
    145:     if args[:cookie]
    146:       req << "Cookie: #{args[:cookie]}"
    147:     end
    148:
    149:     # Basic-auth stanza contributed by Matt Murphy.
    150:     if args[:basic_auth]
    151:       basic_auth_string = ["#{args[:basic_auth][:username]}:#{args[:basic_auth][:password]}"].pack('m').strip.gsub(/\n/,'')
    152:       req << "Authorization: Basic #{basic_auth_string}"
    153:     end
    154:
    155:     req << ""
    156:     reqstring = req.map {|l| "#{l}\r\n"}.join
    157:     send_data reqstring
    158:
    159:     if verb == "POST" || verb == "PUT"
    160:       send_data postcontent
    161:     end
    162:   end