TEST_F(HTTP2CodecTest, Chrome16kb) { HTTPMessage req = getGetRequest(); string bigval(8691, '!'); bigval.append(8691, ' '); req.getHeaders().add("x-headr", bigval); req.getHeaders().add("user-agent", agent2); upstreamCodec_.generateHeader(output_, 1, req, 0); upstreamCodec_.generateRstStream(output_, 1, ErrorCode::PROTOCOL_ERROR); parse(); callbacks_.expectMessage(false, -1, "/"); const auto& headers = callbacks_.msg->getHeaders(); EXPECT_EQ(bigval, headers.getSingleOrEmpty("x-headr")); 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_.aborts, 1); EXPECT_EQ(callbacks_.lastErrorCode, ErrorCode::NO_ERROR); upstreamCodec_.generateSettingsAck(output_); parse(); EXPECT_EQ(callbacks_.settingsAcks, 1); }
TEST_F(HTTP2CodecTest, MissingContinuation) { IOBufQueue output(IOBufQueue::cacheChainLength()); HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); // empirically determined the header block will be 20 bytes, so split at N-1 HTTP2Codec::setHeaderSplitSize(19); size_t prevLen = output_.chainLength(); upstreamCodec_.generateHeader(output_, 1, req, 0); EXPECT_EQ(output_.chainLength() - prevLen, 20 + 2 * 9); // strip the continuation frame (1 byte payload) output_.trimEnd(http2::kFrameHeaderSize + 1); // insert a non-continuation (but otherwise valid) frame http2::writeGoaway(output_, 17, ErrorCode::ENHANCE_YOUR_CALM); parse(); EXPECT_EQ(callbacks_.messageBegin, 1); EXPECT_EQ(callbacks_.headersComplete, 0); EXPECT_EQ(callbacks_.messageComplete, 0); EXPECT_EQ(callbacks_.streamErrors, 0); EXPECT_EQ(callbacks_.sessionErrors, 1); #ifndef NDEBUG EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2); #endif }
// Test serializing and deserializing a header that has many values TEST(SPDYCodecTest, HeaderWithManyValues) { const std::string kMultiValued = "X-Multi-Valued"; const unsigned kNumValues = 1000; FakeHTTPCodecCallback callbacks; SPDYCodec egressCodec(TransportDirection::UPSTREAM, SPDYVersion::SPDY3); SPDYCodec ingressCodec(TransportDirection::DOWNSTREAM, SPDYVersion::SPDY3); ingressCodec.setCallback(&callbacks); HTTPMessage req; req.setMethod("GET"); req.getHeaders().set("HOST", "www.foo.com"); req.setURL("https://www.foo.com"); for (unsigned i = 0; i < kNumValues; ++i) { req.getHeaders().add(kMultiValued, folly::to<string>("Value", i)); } auto syn = getSynStream(egressCodec, 1, req); 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); CHECK_NOTNULL(callbacks.msg.get()); EXPECT_EQ(callbacks.msg->getHeaders().getNumberOfValues(kMultiValued), kNumValues); }
TEST_P(ChromeHTTP2Test, ChromeContinuationSecondStream) { HPACKCodec09 headerCodec(TransportDirection::UPSTREAM); HTTPMessage req = getGetRequest(); string agent = GetParam(); req.getHeaders().add("user-agent", agent); generateHeaderChrome(headerCodec, output_, 1, req, 0, false, nullptr, false); string bigval(1004, '!'); bigval.append(1004, ' '); req.getHeaders().add("x-headerx", bigval); generateHeaderChrome(headerCodec, output_, 3, req, 0, false, nullptr, agent.find("Chrome/43") == string::npos); parse(); const auto& headers = callbacks_.msg->getHeaders(); EXPECT_EQ(agent, headers.getSingleOrEmpty("user-agent")); EXPECT_EQ(bigval, headers.getSingleOrEmpty("x-headerx")); EXPECT_EQ(callbacks_.messageBegin, 2); EXPECT_EQ(callbacks_.headersComplete, 2); EXPECT_EQ(callbacks_.messageComplete, 0); EXPECT_EQ(callbacks_.streamErrors, 0); EXPECT_EQ(callbacks_.sessionErrors, 0); upstreamCodec_.generateSettingsAck(output_); parse(); EXPECT_EQ(callbacks_.settingsAcks, 1); }
TEST_F(EchoHandlerFixture, ReplaysBodyProperly) { EXPECT_CALL(stats, recordRequest()).WillOnce(Return()); EXPECT_CALL(stats, getRequestCount()).WillOnce(Return(5)); HTTPMessage response; folly::fbstring body; EXPECT_CALL(*responseHandler, sendHeaders(_)).WillOnce( DoAll(SaveArg<0>(&response), Return())); EXPECT_CALL(*responseHandler, sendBody(_)).WillRepeatedly( DoAll( Invoke([&] (std::shared_ptr<folly::IOBuf> b) { body += b->moveToFbString(); }), Return())); EXPECT_CALL(*responseHandler, sendEOM()).WillOnce(Return()); // Since we know we dont touch request, its ok to pass `nullptr` here. handler->onRequest(nullptr); handler->onBody(folly::IOBuf::copyBuffer("part1")); handler->onBody(folly::IOBuf::copyBuffer("part2")); handler->onEOM(); handler->requestComplete(); EXPECT_EQ("5", response.getHeaders().getSingleOrEmpty("Request-Number")); EXPECT_EQ(200, response.getStatusCode()); EXPECT_EQ("part1part2", body); }
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")); }
void HTTPTransaction::sendHeadersWithOptionalEOM( const HTTPMessage& headers, bool eom) { CHECK(HTTPTransactionEgressSM::transit( egressState_, HTTPTransactionEgressSM::Event::sendHeaders)); DCHECK(!isEgressComplete()); if (isDownstream() && !isPushed()) { lastResponseStatus_ = headers.getStatusCode(); } if (headers.isRequest()) { headRequest_ = (headers.getMethod() == HTTPMethod::HEAD); } HTTPHeaderSize size; transport_.sendHeaders(this, headers, &size, eom); if (transportCallback_) { transportCallback_->headerBytesGenerated(size); } if (eom) { CHECK(HTTPTransactionEgressSM::transit( egressState_, HTTPTransactionEgressSM::Event::sendEOM)); // trailers are supported in this case: // trailers are for chunked encoding-transfer of a body if (transportCallback_) { transportCallback_->bodyBytesGenerated(0); } CHECK(HTTPTransactionEgressSM::transit( egressState_, HTTPTransactionEgressSM::Event::eomFlushed)); } flushWindowUpdate(); }
TEST_F(HTTP2CodecTest, MissingContinuationBadFrame) { IOBufQueue output(IOBufQueue::cacheChainLength()); HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); // empirically determined the header block will be 20 bytes, so split at N-1 HTTP2Codec::setHeaderSplitSize(19); size_t prevLen = output_.chainLength(); upstreamCodec_.generateHeader(output_, 1, req, 0); EXPECT_EQ(output_.chainLength() - prevLen, 20 + 2 * 9); // strip the continuation frame (1 byte payload) output_.trimEnd(http2::kFrameHeaderSize + 1); // insert an invalid frame auto frame = makeBuf(9); *((uint32_t *)frame->writableData()) = 0xfa000000; output_.append(std::move(frame)); parse(); EXPECT_EQ(callbacks_.messageBegin, 1); EXPECT_EQ(callbacks_.headersComplete, 0); EXPECT_EQ(callbacks_.messageComplete, 0); EXPECT_EQ(callbacks_.streamErrors, 0); EXPECT_EQ(callbacks_.sessionErrors, 1); #ifndef NDEBUG EXPECT_EQ(downstreamCodec_.getReceivedFrameCount(), 2); #endif }
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); }
/** Process HTTP response message from cimserver @param httpResponse Array<char> reply from cimserver @param ostream the ostream to which output should be written @param estream the ostream to which errors should be written @return true = wait for data from challenge response @return false = client response has been received */ void WbemExecCommand::_handleResponse( Array<char> responseMessage, ostream& oStream, ostream& eStream ) { String startLine; Array<HTTPHeader> headers; Uint32 contentLength; Uint32 contentOffset = 0; HTTPMessage* httpMessage; Boolean needsAuthentication = false; httpMessage = new HTTPMessage( responseMessage, 0 ); httpMessage->parse( startLine, headers, contentLength ); if( contentLength > 0 ) { contentOffset = responseMessage.size() - contentLength; } else { contentOffset = responseMessage.size(); } String httpVersion; Uint32 statusCode; String reasonPhrase; Boolean parsableMessage = HTTPMessage::parseStatusLine( startLine, httpVersion, statusCode, reasonPhrase); if (!parsableMessage || (statusCode != HTTP_STATUSCODE_OK)) { // Received an HTTP error response // Output the HTTP error message and exit for (Uint32 i = 0; i < contentOffset; i++) { oStream << responseMessage[i]; } oStream.flush(); if( contentLength > 0 ) { _printContent( oStream, responseMessage, contentOffset ); } exit( 1 ); } // // Received a valid HTTP response from the server. // if (_debugOutput2) { for (Uint32 i = 0; i < contentOffset; i++) { oStream << responseMessage[i]; } oStream.flush(); } _printContent( oStream, responseMessage, contentOffset ); }
unique_ptr<folly::IOBuf> getSynStream(Codec& egressCodec, uint32_t streamID) { HTTPMessage msg; msg.setMethod("GET"); msg.getHeaders().set("HOST", "www.foo.com"); msg.setURL("https://www.foo.com"); return getSynStream(egressCodec, streamID, msg); }
TEST(HTTPMessage, TestParseCookiesSimple) { HTTPMessage msg; msg.getHeaders().add("Cookie", "id=1256679245; data=0:1234567"); EXPECT_EQ(msg.getCookie("id"), "1256679245"); EXPECT_EQ(msg.getCookie("data"), "0:1234567"); EXPECT_EQ(msg.getCookie("mising"), ""); }
HTTPMessage getGetRequest(const std::string& url) { HTTPMessage req; req.setMethod("GET"); req.setURL(url); req.setHTTPVersion(1, 1); req.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com"); return req; }
HTTPMessage getResponse(uint32_t code, uint32_t bodyLen) { HTTPMessage resp; resp.setStatusCode(code); if (bodyLen > 0) { resp.getHeaders().set(HTTP_HEADER_CONTENT_LENGTH, folly::to<string>(bodyLen)); } return resp; }
HTTPMessage getPostRequest() { HTTPMessage req; req.setMethod("POST"); req.setURL<string>("/"); req.setHTTPVersion(1, 1); req.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com"); req.getHeaders().set(HTTP_HEADER_CONTENT_LENGTH, "200"); return req; }
HTTPMessage getPostRequest(uint32_t contentLength) { HTTPMessage req; req.setMethod("POST"); req.setURL<string>("/"); req.setHTTPVersion(1, 1); req.getHeaders().set(HTTP_HEADER_HOST, "www.foo.com"); req.getHeaders().set(HTTP_HEADER_CONTENT_LENGTH, folly::to<string>(contentLength)); return req; }
TEST(HTTPMessage, TestCheckForHeaderToken) { HTTPMessage msg; HTTPHeaders& headers = msg.getHeaders(); headers.add(HTTP_HEADER_CONNECTION, "HTTP2-Settings"); EXPECT_TRUE(msg.checkForHeaderToken(HTTP_HEADER_CONNECTION, "HTTP2-Settings", false)); EXPECT_FALSE(msg.checkForHeaderToken(HTTP_HEADER_CONNECTION, "http2-settings", true)); }
void testPathAndQuery(const string& url, const string& expectedPath, const string& expectedQuery) { HTTPMessage msg; msg.setURL(url); EXPECT_EQ(msg.getURL(), url); EXPECT_EQ(msg.getPath(), expectedPath); EXPECT_EQ(msg.getQueryString(), expectedQuery); }
HTTPMessage getUpgradeRequest(const std::string& upgradeHeader, HTTPMethod method, uint32_t bodyLen) { HTTPMessage req = getGetRequest(); req.setMethod(method); req.getHeaders().set(HTTP_HEADER_UPGRADE, upgradeHeader); if (bodyLen > 0) { req.getHeaders().set(HTTP_HEADER_CONTENT_LENGTH, folly::to<std::string>(bodyLen)); } return req; }
TEST_F(HTTP2CodecTest, BasicPushPromise) { HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); downstreamCodec_.generateHeader(output_, 2, req, 1); parseUpstream(); callbacks_.expectMessage(false, 2, "/"); // + host EXPECT_EQ(callbacks_.assocStreamId, 1); const auto& headers = callbacks_.msg->getHeaders(); EXPECT_EQ("coolio", headers.getSingleOrEmpty("user-agent")); }
// Send response in form of a SOAPMessage AND error status void WebServiceServer::SendResponse(SOAPMessage* p_response,int p_httpStatus) { HTTPMessage* answer = new HTTPMessage(HTTPCommand::http_response,p_response); answer->SetStatus(p_httpStatus); m_httpServer->SendResponse(answer); answer->DropReference(); // Do not respond with the original message p_response->SetHasBeenAnswered(); }
TEST_F(HTTP2CodecTest, UnknownFrameType) { HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); // unknown frame type 17 writeFrameHeaderManual(output_, 17, 37, 0, 1); output_.append("wicked awesome!!!"); upstreamCodec_.generateHeader(output_, 1, req, 0); parse(); callbacks_.expectMessage(false, 2, ""); // + host }
void testRemoveQueryParam(const string& url, const string& queryParam, const string& expectedUrl, const string& expectedQuery) { HTTPMessage msg; msg.setURL(url); bool expectedChange = (url != expectedUrl); EXPECT_EQ(msg.removeQueryParam(queryParam), expectedChange); EXPECT_EQ(msg.getURL(), expectedUrl); EXPECT_EQ(msg.getQueryString(), expectedQuery); }
// Not much useful things here, but hey: it's a test! void SiteFilterTester23::Handle(HTTPMessage* p_message) { HTTPMessage* msg = const_cast<HTTPMessage*>(p_message); xprintf("FILTER TESTER NR 23: %s FROM %s\n", (LPCTSTR)msg->GetURL(), (LPCTSTR)SocketToServer(msg->GetSender())); xprintf("Registering the body length: %lu\n",(unsigned long)msg->GetBodyLength()); // SUMMARY OF THE TEST // --- "---------------------------------------------- - ------ qprintf("Filter handler with priority 23 : OK\n"); --totalChecks; }
TEST(HTTPMessage, TestHeaderRemove) { HTTPMessage msg; HTTPHeaders& hdrs = msg.getHeaders(); hdrs.add("Jojo", "1"); hdrs.add("Binky", "2"); hdrs.add("jOJo", "3"); hdrs.add("bINKy", "4"); hdrs.remove("jojo"); EXPECT_EQ(hdrs.size(), 2); EXPECT_EQ(hdrs.getNumberOfValues("binky"), 2); }
TEST_F(HTTP2CodecTest, BasicContinuation) { HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); HTTP2Codec::setHeaderSplitSize(1); upstreamCodec_.generateHeader(output_, 1, req, 0); parse(); callbacks_.expectMessage(false, -1, "/"); #ifndef NDEBUG EXPECT_GT(downstreamCodec_.getReceivedFrameCount(), 1); #endif const auto& headers = callbacks_.msg->getHeaders(); EXPECT_EQ("coolio", headers.getSingleOrEmpty("user-agent")); }
TEST_F(HTTP2CodecTest, BadPushPromise) { HTTPMessage req = getGetRequest(); req.getHeaders().add("user-agent", "coolio"); downstreamCodec_.generateHeader(output_, 2, req, 1); upstreamCodec_.getEgressSettings()->setSetting(SettingsId::ENABLE_PUSH, 0); parseUpstream(); EXPECT_EQ(callbacks_.messageBegin, 0); EXPECT_EQ(callbacks_.headersComplete, 0); EXPECT_EQ(callbacks_.messageComplete, 0); EXPECT_EQ(callbacks_.assocStreamId, 0); EXPECT_EQ(callbacks_.streamErrors, 0); EXPECT_EQ(callbacks_.sessionErrors, 1); }
void CIMExportRequestDecoder::sendResponse( Uint32 queueId, Buffer& message, Boolean closeConnect) { MessageQueue* queue = MessageQueue::lookup(queueId); if (queue) { HTTPMessage* httpMessage = new HTTPMessage(message); httpMessage->setCloseConnect(closeConnect); queue->enqueue(httpMessage); } }
void HTTPChecks::generateHeader(folly::IOBufQueue& writeBuf, StreamID stream, const HTTPMessage& msg, StreamID assocStream, HTTPHeaderSize* sizeOut) { if (msg.isRequest() && RFC2616::bodyImplied(msg.getHeaders())) { CHECK(RFC2616::isRequestBodyAllowed(msg.getMethod()) != RFC2616::BodyAllowed::NOT_ALLOWED); // We could also add a "strict" mode that disallows sending body on GET // requests here too. } call_->generateHeader(writeBuf, stream, msg, assocStream, sizeOut); }
void doEmptyHeaderValueTest(Codec1& ingressCodec, Codec2& egressCodec) { uint8_t version = ingressCodec.getVersion(); bool emptyAllowed = version != 2; FakeHTTPCodecCallback callbacks; ingressCodec.setCallback(&callbacks); HTTPMessage toSend; toSend.setMethod("GET"); toSend.setURL("http://www.foo.com"); auto& headers = toSend.getHeaders(); headers.set("Host", "www.foo.com"); headers.set("Pragma", ""); headers.set("X-Test1", "yup"); HTTPHeaderSize size; std::string pragmaValue; HTTPCodec::StreamID id(1); for (auto i = 0; i < 3; i++) { auto toParse = getSynStream(egressCodec, id + 2 * i, toSend, 0, false, &size); ingressCodec.onIngress(*toParse); EXPECT_EQ(callbacks.sessionErrors, 0); EXPECT_EQ(callbacks.streamErrors, 0); ASSERT_NE(callbacks.msg.get(), nullptr); const auto& parsed = callbacks.msg->getHeaders(); EXPECT_EQ(parsed.exists("Pragma"), emptyAllowed); EXPECT_EQ(parsed.exists("pragma"), emptyAllowed); EXPECT_EQ(parsed.getSingleOrEmpty("Pragma"), pragmaValue); EXPECT_EQ(parsed.getSingleOrEmpty("X-Test1"), "yup"); // All codecs add the accept-encoding header EXPECT_EQ(parsed.exists("accept-encoding"), true); // SPDY/2 subtracts the Host header, but it should infer it from the // host:port portion of the requested url and present it in the headers EXPECT_EQ(parsed.exists("host"), true); EXPECT_EQ(callbacks.msg->getURL(), "http://www.foo.com"); EXPECT_EQ(parsed.size(), emptyAllowed ? 4 : 3); EXPECT_TRUE(size.uncompressed > 0); EXPECT_TRUE(size.compressed > 0); if (i == 0) { headers.add("Pragma", ""); } if (i == 1) { pragmaValue = "foo"; headers.add("Pragma", pragmaValue); emptyAllowed = true; // SPDY/2 better have it now too } } }