Exemple #1
0
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);
}
Exemple #2
0
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);
}
Exemple #4
0
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);
}
Exemple #5
0
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();
}
Exemple #8
0
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
}
Exemple #9
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);
}
/**

    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 );
}
Exemple #11
0
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);
}
Exemple #12
0
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;
}
Exemple #15
0
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;
}
Exemple #17
0
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));
}
Exemple #18
0
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"));
}
Exemple #21
0
// 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
}
Exemple #23
0
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);
}
Exemple #24
0
// 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;
}
Exemple #25
0
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);
    }
}
Exemple #29
0
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);
}
Exemple #30
0
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
    }
  }
}