void LibEventTransport::sendImpl(const void *data, int size, int code, bool chunked) { assert(data); assert(!m_sendEnded); assert(!m_sendStarted || chunked); if (chunked) { assert(m_method != HEAD); evbuffer *chunk = evbuffer_new(); evbuffer_add(chunk, data, size); /* * 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); m_server->onChunkedResponse(m_workerId, m_request, code, chunk, !m_sendStarted); } else { if (m_method != HEAD) { evbuffer_add(m_request->output_buffer, data, size); } else if (!evhttp_find_header(m_request->output_headers, "Content-Length")) { char buf[11]; snprintf(buf, sizeof(buf), "%d", size); addHeaderImpl("Content-Length", buf); } m_server->onResponse(m_workerId, m_request, code, this); m_sendEnded = true; } m_sendStarted = true; }
void LibEventTransport::sendImpl(const void *data, int size, int code, bool chunked) { assert(data); 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; } assert(!m_sendStarted || chunked); if (chunked) { assert(m_method != Method::HEAD); evbuffer *chunk = evbuffer_new(); evbuffer_add(chunk, data, size); /* * 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); m_server->onChunkedResponse(m_workerId, m_request, code, chunk, !m_sendStarted); } else { if (m_method != Method::HEAD) { evbuffer_add(m_request->output_buffer, data, size); } else if (!evhttp_find_header(m_request->output_headers, "Content-Length")) { char buf[11]; snprintf(buf, sizeof(buf), "%d", size); addHeaderImpl("Content-Length", buf); } m_server->onResponse(m_workerId, m_request, code, this); m_sendEnded = true; } m_sendStarted = true; }
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); } }