bool Transport::splitHeader(CStrRef header, String &name, const char *&value) { int pos = header.find(':'); if (pos != String::npos) { name = header.substr(0, pos); value = header.data() + pos; do { value++; } while (*value == ' '); return true; } // header("HTTP/1.0 404 Not Found"); // header("HTTP/1.0 404"); if (strncasecmp(header.data(), "http/", 5) == 0) { int pos1 = header.find(' '); if (pos1 != String::npos) { int pos2 = header.find(' ', pos1 + 1); if (pos2 == String::npos) pos2 = header.size(); if (pos2 - pos1 > 1) { setResponse(atoi(header.data() + pos1), getResponseInfo().empty() ? "splitHeader" : getResponseInfo().c_str() ); return false; } } } throw InvalidArgumentException("header", header.c_str()); }
void FastCGITransport::sendResponseHeaders(IOBufQueue& queue, int code) { CHECK(!m_headersSent); m_headersSent = true; if (code != 200) { queue.append(s_status); queue.append(std::to_string(code)); auto reasonStr = getResponseInfo(); if (reasonStr.empty()) { reasonStr = HttpProtocol::GetReasonString(code); } queue.append(s_space); queue.append(reasonStr); queue.append(s_newline); } for (auto& header : m_responseHeaders) { for (auto& value : header.second) { queue.append(header.first); queue.append(s_colon); queue.append(value); queue.append(s_newline); } } queue.append(s_newline); }
void ProxygenTransport::sendImpl(const void *data, int size, int code, bool chunked, bool eom) { assert(data); assert(!m_sendStarted || chunked); if (m_sendEnded) { // This should never happen, but when it does we have to bail out, // since there's no sensible way to send data at this point and // trying to do so will horribly corrupt memory. // TODO #2821803: Figure out whether this is caused by another bug // somewhere. return; } VLOG(4) << "sendImpl called with data size=" << size << ", code=" << code << ", chunked=" << chunked << ", eom=" << eom; eom |= !chunked; if (!m_sendStarted) { if (!chunked) { if (!m_response.getHeaders().exists(HTTP_HEADER_CONTENT_LENGTH)) { m_response.getHeaders().add(HTTP_HEADER_CONTENT_LENGTH, folly::to<std::string>(size)); } } else { // Explicitly add Transfer-Encoding: chunked here. libproxygen will only // add it for keep-alive connections m_response.getHeaders().set(HTTP_HEADER_TRANSFER_ENCODING, "chunked"); } m_response.setStatusCode(code); auto const& reasonStr = getResponseInfo(); const char* reason = reasonStr.empty() ? HTTPMessage::getDefaultReason(code) : reasonStr.c_str(); m_response.setStatusMessage(reason); m_response.setHTTPVersion(1, 1); m_response.setIsChunked(chunked); m_response.dumpMessage(4); m_server->putResponseMessage( ResponseMessage(shared_from_this(), ResponseMessage::Type::HEADERS, 0, chunked, data, size, eom)); m_sendStarted = true; } else { m_server->putResponseMessage( ResponseMessage(shared_from_this(), ResponseMessage::Type::BODY, 0, chunked, data, size, eom)); } if (eom) { m_sendEnded = true; } if (chunked) { assert(m_method != Method::HEAD); /* * Chunked replies are sent async, so there is no way to know the * time it took to flush the response, but tracking the bytes sent is * very useful. */ onChunkedProgress(size); } }