Exemplo n.º 1
0
void ProxygenTransport::onHeadersComplete(
  unique_ptr<HTTPMessage> msg) noexcept {

  Timer::GetMonotonicTime(m_requestStart);
  m_request = std::move(msg);
  if (m_request->isSecure()) {
    setSSL();
  }
  m_request->dumpMessage(4);
  auto method = m_request->getMethod();
  const auto& methodStr = m_request->getMethodString();
  if (method == HTTPMethod::GET) {
    m_method = Transport::Method::GET;
  } else if (method == HTTPMethod::POST ||
             s_post_methods.find(methodStr) != s_post_methods.end()) {
    m_method = Transport::Method::POST;
  } else if (method == HTTPMethod::HEAD) {
    m_method = Transport::Method::HEAD;
  } else if (method == HTTPMethod::CONNECT) {
    sendErrorResponse(400 /* Bad Request */);
    return;
  } else {
    // looks like proxygen HTTP parser understands a few more methods
    // than libevent:
    //   TRACE, COPY, MOVE, MKACTIVITY, CHECKOUT, MERGE, MSEARCH, NOTIFY,
    //   SUBSCRIBE, UNSUBSCRIBE, PATCH
    sendErrorResponse(400 /* Bad Request */);
    return;
  }
  m_extended_method = methodStr.c_str();

  const auto& headers = m_request->getHeaders();
  headers.forEach([&] (const std::string &header, const std::string &val) {
      m_requestHeaders[header.c_str()].push_back(val.c_str());
    });

  if (m_method == Transport::Method::POST && m_request->isHTTP1_1()) {
    const std::string& expectation =
      headers.getSingleOrEmpty(HTTP_HEADER_EXPECT);
    if (!expectation.empty()) {
      bool sendEom = false;
      HTTPMessage response;
      if (!boost::iequals(expectation, "100-continue")) {
        response.setStatusCode(417);
        response.setStatusMessage(HTTPMessage::getDefaultReason(417));
        response.getHeaders().add(HTTP_HEADER_CONNECTION, "close");
        sendEom = true;
      } else {
        response.setStatusCode(100);
        response.setStatusMessage(HTTPMessage::getDefaultReason(100));
      }
      response.setHTTPVersion(1, 1);
      response.dumpMessage(4);
      m_clientTxn->sendHeaders(response);
      if (sendEom) {
        m_responseCode = response.getStatusCode();
        m_responseCodeInfo = response.getStatusMessage();
        m_server->onRequestError(this);
        m_clientTxn->sendEOM();
        // this object is no longer valid
        return;
      }
    }
  }

  if (!bufferRequest()) {
    m_enqueued = true;
    m_server->onRequest(shared_from_this());
  } // otherwise we wait for EOM
}
Exemplo n.º 2
0
TEST(HTTPMessage, TestParseCookiesSingleCookie) {
  HTTPMessage msg;

  msg.getHeaders().add("Cookie", "   user_id=1256679245  ");
  EXPECT_EQ(msg.getCookie("user_id"), "1256679245");
}
Exemplo n.º 3
0
TEST(HTTPMessage, TestEmptyName) {
  HTTPMessage msg;
  EXPECT_DEATH_NO_CORE(msg.getHeaders().set("", "empty name?!"), ".*");
}
Exemplo n.º 4
0
TEST(HTTPMessage, TestHeaderStripPerHop) {
  HTTPMessage msg;

  msg.getHeaders().add("Connection", "a, b, c");
  msg.getHeaders().add("Connection", "d");
  msg.getHeaders().add("Connection", ",,,,");
  msg.getHeaders().add("Connection", " , , , ,");
  msg.getHeaders().add("Connection", ", e");
  msg.getHeaders().add("Connection", " f ,\tg\t, \r\n\th ");
  msg.getHeaders().add("Keep-Alive", "true");

  msg.getHeaders().add("a", "1");
  msg.getHeaders().add("b", "2");
  msg.getHeaders().add("c", "3");
  msg.getHeaders().add("d", "4");
  msg.getHeaders().add("e", "5");
  msg.getHeaders().add("f", "6");
  msg.getHeaders().add("g", "7");
  msg.getHeaders().add("h", "8");

  EXPECT_EQ(msg.getHeaders().size(), 15);
  msg.stripPerHopHeaders();
  EXPECT_EQ(msg.getHeaders().size(), 0);
  EXPECT_EQ(msg.getStrippedPerHopHeaders().size(), 15);
}
Exemplo n.º 5
0
TEST(HTTPMessage, TestKeepaliveCheck) {
  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 0);
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    EXPECT_TRUE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "close");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "ClOsE");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "foo,bar");
    EXPECT_TRUE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "foo,bar");
    msg.getHeaders().add("Connection", "abc,CLOSE,def");
    msg.getHeaders().add("Connection", "xyz");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "foo,bar");
    msg.getHeaders().add("Connection", "abc ,  CLOSE , def");
    msg.getHeaders().add("Connection", "xyz");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "  close ");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", ",  close ");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 1);
    msg.getHeaders().add("Connection", "  close , ");
    EXPECT_FALSE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 0);
    msg.getHeaders().add("Connection", "Keep-Alive");
    EXPECT_TRUE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 0);
    msg.getHeaders().add("Connection", "keep-alive");
    EXPECT_TRUE(msg.computeKeepalive());
  }

  {
    HTTPMessage msg;
    msg.setHTTPVersion(1, 0);
    msg.getHeaders().add("Connection", "keep-alive");
    msg.getHeaders().add("Connection", "close");
    EXPECT_FALSE(msg.computeKeepalive());
  }
}
Exemplo n.º 6
0
/**
 * Mostly ripped from HTTP2Codec::generateHeader.  This writes out frames
 * like Chrome does, breaking on 1024 - frame header, with some of the not
 * needed cases removed.  It's specialized to write only a single continuation
 * frame with optionally malformed length
 */
void generateHeaderChrome(HPACKCodec09& headerCodec,
                          folly::IOBufQueue& writeBuf,
                          HTTPCodec::StreamID stream,
                          const HTTPMessage& msg,
                          HTTPCodec::StreamID assocStream,
                          bool eom,
                          HTTPHeaderSize* size,
                          bool malformed) {
  VLOG(4) << "generating " << ((assocStream != 0) ? "PUSH_PROMISE" : "HEADERS")
          << " for stream=" << stream;
  std::vector<proxygen::compress::Header> allHeaders;

  const string& method = msg.getMethodString();
  const string& scheme = (msg.isSecure() ? http2::kHttps : http2::kHttp);
  const string& path = msg.getURL();
  const HTTPHeaders& headers = msg.getHeaders();
  const string& host = headers.getSingleOrEmpty(HTTP_HEADER_HOST);
  allHeaders.emplace_back(http2::kMethod, method);
  allHeaders.emplace_back(http2::kScheme, scheme);
  allHeaders.emplace_back(http2::kPath, path);
  if (!host.empty()) {
    allHeaders.emplace_back(http2::kAuthority, host);
  }

  // Add the HTTP headers supplied by the caller, but skip
  // any per-hop headers that aren't supported in HTTP/2.
  msg.getHeaders().forEachWithCode(
    [&] (HTTPHeaderCode code,
         const string& name,
         const string& value) {

      // Note this code will not drop headers named by Connection.  That's the
      // caller's job

      // see HTTP/2 spec, 8.1.2
      DCHECK(name != "TE" || value == "trailers");
      if ((name.size() > 0 && name[0] != ':') &&
          code != HTTP_HEADER_HOST) {
        allHeaders.emplace_back(code, name, value);
      }
    });

  headerCodec.setEncodeHeadroom(http2::kFrameHeadersBaseMaxSize);
  auto out = headerCodec.encode(allHeaders);
  if (size) {
    *size = headerCodec.getEncodedSize();
  }

  IOBufQueue queue(IOBufQueue::cacheChainLength());
  queue.append(std::move(out));
  if (queue.chainLength() > 0) {

    auto chunk = queue.split(std::min((size_t)(1024 - 14),
                                      queue.chainLength()));

    bool endHeaders = queue.chainLength() == 0;
    CHECK_EQ(assocStream, 0);
    http2::writeHeaders(writeBuf,
                        std::move(chunk),
                        stream,
                        http2::DefaultPriority,
                        http2::kNoPadding,
                        eom,
                        endHeaders);
    while (!endHeaders) {
      CHECK_EQ(queue.chainLength(), 1015);
      chunk = queue.split(std::min(size_t(1024 - http2::kFrameHeaderSize),
                                   queue.chainLength()));
      endHeaders = queue.chainLength() == 0;
      CHECK(endHeaders);
      VLOG(4) << "generating CONTINUATION for stream=" << stream;
      writeFrameHeaderManual(writeBuf,
                             malformed ? 1024 : chunk->computeChainDataLength(),
                             9,
                             http2::END_HEADERS,
                             stream);
      writeBuf.append(std::move(chunk));
    }
  }
}