Exemplo n.º 1
0
TEST_F(HTTP2CodecTest, BadSettingsTableSize) {
  auto settings = upstreamCodec_.getEgressSettings();
  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 8192);
  // This sets the max decoder table size to 8k
  upstreamCodec_.generateSettings(output_);

  parse();
  EXPECT_EQ(callbacks_.settings, 1);
  EXPECT_EQ(callbacks_.streamErrors, 0);
  EXPECT_EQ(callbacks_.sessionErrors, 0);

  callbacks_.reset();

  // Set max decoder table size back to 4k, but don't parse it.  The
  // upstream encoder will up the table size to 8k per the first settings frame
  // and the HPACK codec will send a code to update the decoder.
  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 4096);
  upstreamCodec_.generateSettings(output_);

  HTTPMessage resp;
  resp.setStatusCode(200);
  resp.setStatusMessage("nifty-nice");
  resp.getHeaders().add("content-type", "x-coolio");
  SetUpUpstreamTest();
  downstreamCodec_.generateHeader(output_, 1, resp, 0);

  parseUpstream();
  EXPECT_EQ(callbacks_.streamErrors, 0);
  EXPECT_EQ(callbacks_.sessionErrors, 1);
  EXPECT_EQ(callbacks_.messageBegin, 0);
  EXPECT_EQ(callbacks_.headersComplete, 0);
}
Exemplo n.º 2
0
TEST_F(HTTP2CodecTest, SettingsTableSize) {
  auto settings = upstreamCodec_.getEgressSettings();
  settings->setSetting(SettingsId::HEADER_TABLE_SIZE, 8192);
  upstreamCodec_.generateSettings(output_);

  parse();
  EXPECT_EQ(callbacks_.settings, 1);
  EXPECT_EQ(callbacks_.streamErrors, 0);
  EXPECT_EQ(callbacks_.sessionErrors, 0);

  callbacks_.reset();

  HTTPMessage resp;
  resp.setStatusCode(200);
  resp.setStatusMessage("nifty-nice");
  resp.getHeaders().add("content-type", "x-coolio");
  output_.move();
  downstreamCodec_.generateConnectionPreface(output_);
  downstreamCodec_.generateHeader(output_, 1, resp, 0);

  parseUpstream();
  callbacks_.expectMessage(false, 1, 200);
  const auto& headers = callbacks_.msg->getHeaders();
  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty("content-type"));
}
Exemplo n.º 3
0
TEST(HTTP1xCodecTest, TestBadPost100) {
  HTTP1xCodec codec(TransportDirection::DOWNSTREAM);
  MockHTTPCodecCallback callbacks;
  codec.setCallback(&callbacks);
  folly::IOBufQueue writeBuf(folly::IOBufQueue::cacheChainLength());

  InSequence enforceOrder;
  EXPECT_CALL(callbacks, onMessageBegin(1, _));
  EXPECT_CALL(callbacks, onHeadersComplete(1, _))
    .WillOnce(InvokeWithoutArgs([&] {
          HTTPMessage cont;
          cont.setStatusCode(100);
          cont.setStatusMessage("Continue");
          codec.generateHeader(writeBuf, 1, cont);
        }));

  EXPECT_CALL(callbacks, onBody(1, _, _));
  EXPECT_CALL(callbacks, onMessageComplete(1, _));
  EXPECT_CALL(callbacks, onMessageBegin(2, _))
    .WillOnce(InvokeWithoutArgs([&] {
          // simulate HTTPSession's aversion to pipelining
          codec.setParserPaused(true);

          // Trigger the response to the POST
          HTTPMessage resp;
          resp.setStatusCode(200);
          resp.setStatusMessage("OK");
          codec.generateHeader(writeBuf, 1, resp);
          codec.generateEOM(writeBuf, 1);
          codec.setParserPaused(false);
        }));
  EXPECT_CALL(callbacks, onError(2, _, _))
    .WillOnce(InvokeWithoutArgs([&] {
          HTTPMessage resp;
          resp.setStatusCode(400);
          resp.setStatusMessage("Bad");
          codec.generateHeader(writeBuf, 2, resp);
          codec.generateEOM(writeBuf, 2);
        }));
  // Generate a POST request with a bad content-length
  auto reqBuf = folly::IOBuf::copyBuffer(
      "POST /www.facebook.com HTTP/1.1\r\nHost: www.facebook.com\r\n"
      "Expect: 100-Continue\r\nContent-Length: 5\r\n\r\nabcdefghij");
  codec.onIngress(*reqBuf);
}
Exemplo n.º 4
0
TEST(SPDYCodecTest, SegmentedHeaderBlock) {
  SPDYCodec egressCodec(TransportDirection::UPSTREAM,
                        SPDYVersion::SPDY3_1_HPACK);
  SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM,
                         SPDYVersion::SPDY3_1_HPACK);
  // generate huge string to use as a header value
  string huge;
  uint32_t size = 20000;
  char ch = 'a';
  for (uint32_t i = 0; i < size; i++) {
    huge.push_back(ch);
    if (ch == 'z') {
      ch = 'a';
    } else {
      ch++;
    }
  }
  HTTPMessage req;
  req.setMethod("GET");
  req.setURL("http://www.facebook.com");
  auto& reqHeaders = req.getHeaders();
  reqHeaders.set("HOST", "www.facebook.com");
  // setting this huge header value will cause allocation of a separate IOBuf
  reqHeaders.set("X-FB-Huge", huge);
  auto buf = getSynStream(egressCodec, 1, req);
  FakeHTTPCodecCallback callbacks;
  ingressCodec.setCallback(&callbacks);
  ingressCodec.onIngress(*buf);
  EXPECT_EQ(callbacks.streamErrors, 0);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_EQ(callbacks.headersComplete, 1);
  EXPECT_EQ(callbacks.msg->getHeaders().getSingleOrEmpty("x-fb-huge").size(),
            size);

  // do it for responses
  HTTPMessage resp;
  resp.setStatusCode(200);
  resp.setStatusMessage("OK");
  auto& respHeaders = resp.getHeaders();
  respHeaders.set("X-FB-Huge", huge);
  auto buf2 = getSynStream(ingressCodec, 1, resp);
  callbacks.reset();
  egressCodec.setCallback(&callbacks);
  egressCodec.onIngress(*buf2);
  EXPECT_EQ(callbacks.streamErrors, 0);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_EQ(callbacks.headersComplete, 1);
  EXPECT_EQ(callbacks.msg->getHeaders().getSingleOrEmpty("x-fb-huge").size(),
            size);
}
Exemplo n.º 5
0
void ProxygenTransport::sendErrorResponse(uint32_t code) noexcept {
  HTTPMessage response;
  response.setHTTPVersion(1, 1);
  response.setStatusCode(code);
  response.setStatusMessage(HTTPMessage::getDefaultReason(code));
  response.getHeaders().add(HTTP_HEADER_CONNECTION, "close");
  CHECK(!m_sendStarted);
  m_sendStarted = true;
  m_sendEnded = true;
  m_responseCode = code;
  m_responseCodeInfo = response.getStatusMessage();
  m_server->onRequestError(this);
  m_clientTxn->sendHeaders(response);
  m_clientTxn->sendEOM();
}
Exemplo n.º 6
0
TEST_F(HTTP2CodecTest, BasicHeaderReply) {
  HTTPMessage resp;
  resp.setStatusCode(200);
  resp.setStatusMessage("nifty-nice");
  resp.getHeaders().add("content-type", "x-coolio");
  downstreamCodec_.generateHeader(output_, 1, resp, 0);
  downstreamCodec_.generateEOM(output_, 1);

  parseUpstream();
  callbacks_.expectMessage(true, 1, 200);
  const auto& headers = callbacks_.msg->getHeaders();
  // HTTP/2 doesnt support serialization - instead you get the default
  EXPECT_EQ("OK", callbacks_.msg->getStatusMessage());
  EXPECT_EQ("x-coolio", headers.getSingleOrEmpty("content-type"));
}
Exemplo n.º 7
0
TEST_F(HTTP2CodecTest, GoawayReply) {
  upstreamCodec_.generateGoaway(output_, 0, ErrorCode::NO_ERROR);

  parse();
  EXPECT_EQ(callbacks_.goaways, 1);
  EXPECT_EQ(callbacks_.streamErrors, 0);
  EXPECT_EQ(callbacks_.sessionErrors, 0);

  SetUpUpstreamTest();
  HTTPMessage resp;
  resp.setStatusCode(200);
  resp.setStatusMessage("nifty-nice");
  downstreamCodec_.generateHeader(output_, 1, resp, 0);
  downstreamCodec_.generateEOM(output_, 1);
  parseUpstream();
  callbacks_.expectMessage(true, 0, 200);
}
Exemplo n.º 8
0
bool
HTTPDownstreamSession::onNativeProtocolUpgrade(
  HTTPCodec::StreamID streamID, CodecProtocol protocol,
  const std::string& protocolString,
  HTTPMessage& msg) {
  VLOG(4) << *this << " onNativeProtocolUpgrade streamID=" << streamID <<
    " protocol=" << protocolString;
  auto txn = findTransaction(streamID);
  CHECK(txn);
  if (txn->canSendHeaders()) {
    // Create the new Codec
    auto codec = HTTPCodecFactory::getCodec(protocol,
                                            TransportDirection::DOWNSTREAM);
    CHECK(codec);
    if (!codec->onIngressUpgradeMessage(msg)) {
      VLOG(4) << *this << " codec rejected upgrade";
      return false;
    }

    // Send a 101 Switching Protocols message while we still have HTTP codec
    // Note: it's possible that the client timed out waiting for a
    // 100-continue and ended up here first.  In this case the 100 may go
    // out in the new protocol
    HTTPMessage switchingProtos;
    switchingProtos.setHTTPVersion(1, 1);
    switchingProtos.setStatusCode(101);
    switchingProtos.setStatusMessage("Switching Protocols");
    switchingProtos.getHeaders().set(HTTP_HEADER_UPGRADE, protocolString);
    txn->sendHeaders(switchingProtos);
    // no sendEOM for 1xx

    // This will actually switch the protocol
    bool ret = HTTPSession::onNativeProtocolUpgradeImpl(
      streamID, std::move(codec), protocolString);
    if (ret) {
      codec_->addPriorityNodes(txnEgressQueue_, writeBuf_, 0);
    }
    return ret;
  } else {
    VLOG(4) << *this << " plaintext upgrade failed due to early response";
    return false;
  }
}
Exemplo n.º 9
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.º 10
0
TEST(SPDYCodecTest, StatusReason) {
  FakeHTTPCodecCallback callbacks;
  SPDYCodec egressCodec(TransportDirection::DOWNSTREAM,
                        SPDYVersion::SPDY3);
  SPDYCodec ingressCodec(TransportDirection::UPSTREAM,
                         SPDYVersion::SPDY3);
  ingressCodec.setCallback(&callbacks);

  HTTPMessage resp;
  resp.setStatusCode(200);
  auto syn = getSynStream(egressCodec, 1, resp, 0);
  ingressCodec.onIngress(*syn);
  EXPECT_EQ(callbacks.messageBegin, 1);
  EXPECT_EQ(callbacks.headersComplete, 1);
  EXPECT_EQ(callbacks.messageComplete, 0);
  EXPECT_EQ(callbacks.streamErrors, 0);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_EQ(callbacks.msg->getStatusCode(), 200);
  EXPECT_EQ(callbacks.msg->getStatusMessage(), "");
  callbacks.reset();

  resp.setStatusCode(200);
  resp.setStatusMessage("Awesome");
  syn = getSynStream(egressCodec, 1, resp, 0);
  ingressCodec.onIngress(*syn);
  EXPECT_EQ(callbacks.messageBegin, 1);
  EXPECT_EQ(callbacks.headersComplete, 1);
  EXPECT_EQ(callbacks.messageComplete, 0);
  EXPECT_EQ(callbacks.streamErrors, 0);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_EQ(callbacks.msg->getStatusCode(), 200);
  EXPECT_EQ(callbacks.msg->getStatusMessage(), "Awesome");
  callbacks.reset();

  // Out of range
  resp.setStatusCode(2000);
  resp.setStatusMessage("10x OK");
  syn = getSynStream(egressCodec, 1, resp, 0);
  ingressCodec.onIngress(*syn);
  EXPECT_EQ(callbacks.messageBegin, 0);
  EXPECT_EQ(callbacks.headersComplete, 0);
  EXPECT_EQ(callbacks.messageComplete, 0);
  EXPECT_EQ(callbacks.streamErrors, 1);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_TRUE(callbacks.lastParseError->hasCodecStatusCode());
  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
            spdy::rstToErrorCode(spdy::RST_PROTOCOL_ERROR));
  callbacks.reset();

  resp.setStatusCode(64);
  resp.setStatusMessage("Ought to be enough for anybody");
  syn = getSynStream(egressCodec, 1, resp, 0);
  ingressCodec.onIngress(*syn);
  EXPECT_EQ(callbacks.messageBegin, 0);
  EXPECT_EQ(callbacks.headersComplete, 0);
  EXPECT_EQ(callbacks.messageComplete, 0);
  EXPECT_EQ(callbacks.streamErrors, 1);
  EXPECT_EQ(callbacks.sessionErrors, 0);
  EXPECT_TRUE(callbacks.lastParseError->hasCodecStatusCode());
  EXPECT_EQ(callbacks.lastParseError->getCodecStatusCode(),
            spdy::rstToErrorCode(spdy::RST_PROTOCOL_ERROR));
  callbacks.reset();
}