Exemplo n.º 1
0
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);
    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 {
      char buf[11];
      snprintf(buf, sizeof(buf), "%d", size);
      addHeaderImpl("Content-Length", buf);
    }
    m_server->onResponse(m_workerId, m_request, code);
    m_sendEnded = true;
  }
  m_sendStarted = true;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
void Transport::redirect(const char *location, int code /* = 302 */,
                         const char *info) {
  FiberWriteLock lock(this);
  addHeaderImpl("Location", location);
  setResponse(code, info);
  sendStringLocked(location, code);
}
Exemplo n.º 4
0
void Transport::prepareHeaders(bool compressed, const void *data, int size) {
  for (HeaderMap::const_iterator iter = m_responseHeaders.begin();
       iter != m_responseHeaders.end(); ++iter) {
    const vector<string> &values = iter->second;
    for (unsigned int i = 0; i < values.size(); i++) {
      addHeaderImpl(iter->first.c_str(), values[i].c_str());
    }
  }

  for (CookieMap::const_iterator iter = m_responseCookies.begin();
       iter != m_responseCookies.end(); ++iter) {
    addHeaderImpl("Set-Cookie", iter->second.c_str());
  }

  if (compressed) {
    addHeaderImpl("Content-Encoding", "gzip");
    removeHeaderImpl("Content-Length");
    if (m_responseHeaders.find("Content-MD5") != m_responseHeaders.end()) {
      String response((const char *)data, size, AttachLiteral);
      removeHeaderImpl("Content-MD5");
      addHeaderImpl("Content-MD5", StringUtil::Base64Encode(
                      StringUtil::MD5(response, true)).c_str());
    }
  }

  if (m_responseHeaders.find("Content-Type") == m_responseHeaders.end() &&
      m_responseCode != 304) {
    string contentType = "text/html; charset="
                         + RuntimeOption::DefaultCharsetName;
    addHeaderImpl("Content-Type", contentType.c_str());
  }

  if (RuntimeOption::ExposeHPHP) {
    addHeaderImpl("X-Powered-By", "HPHP");
  }

  if (RuntimeOption::ExposeXFBServer &&
      m_responseHeaders.find("X-FB-Server") == m_responseHeaders.end()) {
    addHeaderImpl("X-FB-Server", String(RuntimeOption::ServerPrimaryIP));
  }

  // shutting down servers, so need to terminate all Keep-Alive connections
  if (!RuntimeOption::EnableKeepAlive || isServerStopping()) {
    addHeaderImpl("Connection", "close");
    removeHeaderImpl("Keep-Alive");

    // so lower level transports can ignore incoming "Connection: keep-alive"
    removeRequestHeaderImpl("Connection");
  }
}
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;
}
Exemplo n.º 6
0
void Transport::redirect(const char *location, int code /* = 302 */,
                         const char *info) {
  addHeaderImpl("Location", location);
  setResponse(code, info);
  sendStringLocked("Moved", code);
}
Exemplo n.º 7
0
void Transport::prepareHeaders(bool compressed, bool chunked,
    const String &response, const String& orig_response) {
  for (HeaderMap::const_iterator iter = m_responseHeaders.begin();
       iter != m_responseHeaders.end(); ++iter) {
    const vector<string> &values = iter->second;
    for (unsigned int i = 0; i < values.size(); i++) {
      addHeaderImpl(iter->first.c_str(), values[i].c_str());
    }
  }

  for (CookieMap::const_iterator iter = m_responseCookies.begin();
       iter != m_responseCookies.end(); ++iter) {
    addHeaderImpl("Set-Cookie", iter->second.c_str());
  }

  if (compressed) {
    addHeaderImpl("Content-Encoding", "gzip");
    removeHeaderImpl("Content-Length");
    // Remove the Content-MD5 header coming from PHP if we compressed the data,
    // as the checksum is going to be invalid.
    auto it = m_responseHeaders.find("Content-MD5");
    if (it != m_responseHeaders.end()) {
      removeHeaderImpl("Content-MD5");
      // Re-add it back unless this is a chunked response. We'd have to buffer
      // the response completely to compute the MD5, which defeats the purpose
      // of chunking.
      if (chunked) {
        raise_warning("Cannot use chunked HTTP response and Content-MD5 header "
          "at the same time. Dropping Content-MD5.");
      } else {
        string cur_md5 = it->second[0];
        String expected_md5 = StringUtil::Base64Encode(StringUtil::MD5(
          orig_response, true));
        // Can never trust these PHP people...
        if (expected_md5.c_str() != cur_md5) {
          raise_warning("Content-MD5 mismatch. Expected: %s, Got: %s",
            expected_md5.c_str(), cur_md5.c_str());
        }
        addHeaderImpl("Content-MD5", StringUtil::Base64Encode(StringUtil::MD5(
          response, true)).c_str());
      }
    }
  }

  if (m_responseHeaders.find("Content-Type") == m_responseHeaders.end() &&
      m_responseCode != 304) {
    string contentType = "text/html; charset="
                         + RuntimeOption::DefaultCharsetName;
    addHeaderImpl("Content-Type", contentType.c_str());
  }

  if (RuntimeOption::ExposeHPHP) {
    addHeaderImpl("X-Powered-By", "HPHP");
  }

  if ((RuntimeOption::ExposeXFBServer || RuntimeOption::ExposeXFBDebug) &&
      !RuntimeOption::XFBDebugSSLKey.empty() &&
      m_responseHeaders.find("X-FB-Debug") == m_responseHeaders.end()) {
    String ip = RuntimeOption::ServerPrimaryIP;
    String key = RuntimeOption::XFBDebugSSLKey;
    String cipher("AES-256-CBC");
    int iv_len = f_openssl_cipher_iv_length(cipher).toInt32();
    String iv = f_openssl_random_pseudo_bytes(iv_len);
    String encrypted =
      f_openssl_encrypt(ip, cipher, key, k_OPENSSL_RAW_DATA, iv);
    String output = StringUtil::Base64Encode(iv + encrypted);
    if (debug) {
      String decrypted =
        f_openssl_decrypt(encrypted, cipher, key, k_OPENSSL_RAW_DATA, iv);
      assert(decrypted->same(ip.get()));
    }
    addHeaderImpl("X-FB-Debug", output.c_str());
  }

  // shutting down servers, so need to terminate all Keep-Alive connections
  if (!RuntimeOption::EnableKeepAlive || isServerStopping()) {
    addHeaderImpl("Connection", "close");
    removeHeaderImpl("Keep-Alive");

    // so lower level transports can ignore incoming "Connection: keep-alive"
    removeRequestHeaderImpl("Connection");
  }
}
Exemplo n.º 8
0
void Transport::prepareHeaders(bool compressed, const void *data, int size) {
  for (HeaderMap::const_iterator iter = m_responseHeaders.begin();
       iter != m_responseHeaders.end(); ++iter) {
    const vector<string> &values = iter->second;
    for (unsigned int i = 0; i < values.size(); i++) {
      addHeaderImpl(iter->first.c_str(), values[i].c_str());
    }
  }

  for (CookieMap::const_iterator iter = m_responseCookies.begin();
       iter != m_responseCookies.end(); ++iter) {
    addHeaderImpl("Set-Cookie", iter->second.c_str());
  }

  if (compressed) {
    addHeaderImpl("Content-Encoding", "gzip");
    removeHeaderImpl("Content-Length");
    if (m_responseHeaders.find("Content-MD5") != m_responseHeaders.end()) {
      String response((const char *)data, size, AttachLiteral);
      removeHeaderImpl("Content-MD5");
      addHeaderImpl("Content-MD5", StringUtil::Base64Encode(
                      StringUtil::MD5(response, true)).c_str());
    }
  }

  if (m_responseHeaders.find("Content-Type") == m_responseHeaders.end() &&
      m_responseCode != 304) {
    string contentType = "text/html; charset="
                         + RuntimeOption::DefaultCharsetName;
    addHeaderImpl("Content-Type", contentType.c_str());
  }

  if (RuntimeOption::ExposeHPHP) {
    addHeaderImpl("X-Powered-By", "HPHP");
  }

  if ((RuntimeOption::ExposeXFBServer || RuntimeOption::ExposeXFBDebug) &&
      !RuntimeOption::XFBDebugSSLKey.empty() &&
      m_responseHeaders.find("X-FB-Debug") == m_responseHeaders.end()) {
    String ip = RuntimeOption::ServerPrimaryIP;
    String key = RuntimeOption::XFBDebugSSLKey;
    String cipher("AES-256-CBC");
    int iv_len = f_openssl_cipher_iv_length(cipher);
    String iv = f_openssl_random_pseudo_bytes(iv_len);
    String encrypted =
      f_openssl_encrypt(ip, cipher, key, k_OPENSSL_RAW_DATA, iv);
    String output = StringUtil::Base64Encode(iv + encrypted);
    if (debug) {
      String decrypted =
        f_openssl_decrypt(encrypted, cipher, key, k_OPENSSL_RAW_DATA, iv);
      ASSERT(decrypted->same(ip.get()));
    }
    addHeaderImpl("X-FB-Debug", output);
  }

  // shutting down servers, so need to terminate all Keep-Alive connections
  if (!RuntimeOption::EnableKeepAlive || isServerStopping()) {
    addHeaderImpl("Connection", "close");
    removeHeaderImpl("Keep-Alive");

    // so lower level transports can ignore incoming "Connection: keep-alive"
    removeRequestHeaderImpl("Connection");
  }
}