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;
}
Example #3
0
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);
  }
}