proxygen
TestUtils.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #pragma once
11 
15 #include <boost/optional/optional_io.hpp>
16 
17 namespace proxygen {
18 
27 template<class T>
28 size_t parse(T* codec,
29  const uint8_t* inputData,
30  uint32_t length,
31  int32_t atOnce = 0,
32  std::function<bool()> stopFn = [] { return false; }) {
33 
34  const uint8_t* start = inputData;
35  size_t consumed = 0;
36  std::uniform_int_distribution<uint32_t> lenDistribution(1, length / 2 + 1);
37  std::mt19937 rng;
38 
39  if (atOnce == 0) {
40  atOnce = length;
41  }
42 
44  while (length > 0 && !stopFn()) {
45  if (consumed == 0) {
46  // Parser wants more data
47  uint32_t len = atOnce;
48  if (atOnce < 0) {
49  // use random chunks
50  len = lenDistribution(rng);
51  }
52  uint32_t chunkLen = std::min(length, len);
53  input.append(folly::IOBuf::copyBuffer(start, chunkLen));
54  start += chunkLen;
55  length -= chunkLen;
56  }
57  consumed = codec->onIngress(*input.front());
58  input.split(consumed);
59  if (input.front() == nullptr && consumed > 0) {
60  consumed = 0;
61  }
62  }
63  return input.chainLength();
64 }
65 
66 template<class T>
67 size_t parseUnidirectional(T* codec,
68  const uint8_t* inputData,
69  uint32_t length,
70  int32_t atOnce = 0,
71  std::function<bool()> stopFn = [] { return false; }) {
72 
73  const uint8_t* start = inputData;
74  size_t consumed = 0;
75  std::uniform_int_distribution<uint32_t> lenDistribution(1, length / 2 + 1);
76  std::mt19937 rng;
77 
78  if (atOnce == 0) {
79  atOnce = length;
80  }
81 
83  while (length > 0 && !stopFn()) {
84  if (consumed == 0) {
85  // Parser wants more data
86  uint32_t len = atOnce;
87  if (atOnce < 0) {
88  // use random chunks
89  len = lenDistribution(rng);
90  }
91  uint32_t chunkLen = std::min(length, len);
92  input.append(folly::IOBuf::copyBuffer(start, chunkLen));
93  start += chunkLen;
94  length -= chunkLen;
95  }
96  auto initialLength = input.chainLength();
97  auto ret = codec->onUnidirectionalIngress(input.move());
98  input.append(std::move(ret));
99  consumed = initialLength - input.chainLength();
100  if (input.front() == nullptr && consumed > 0) {
101  consumed = 0;
102  }
103  }
104  return input.chainLength();
105 }
106 
108  public:
110 
111  void onMessageBegin(HTTPCodec::StreamID /*stream*/, HTTPMessage*) override {
112  messageBegin++;
113  }
115  HTTPCodec::StreamID assocStream,
116  HTTPMessage*) override {
117  messageBegin++;
118  assocStreamId = assocStream;
119  }
121  HTTPCodec::StreamID controlStream,
122  bool unidirectional,
123  HTTPMessage*) override {
124  messageBegin++;
125  controlStreamId = controlStream;
126  isUnidirectional = unidirectional;
127  }
129  std::unique_ptr<HTTPMessage> inMsg) override {
130  headersComplete++;
132  msg = std::move(inMsg);
133  }
134  void onBody(HTTPCodec::StreamID /*stream*/,
135  std::unique_ptr<folly::IOBuf> chain,
136  uint16_t padding) override {
137  bodyCalls++;
138  paddingBytes += padding;
140  data.append(std::move(chain));
141  }
143  size_t /*length*/) override {
144  chunkHeaders++;
145  }
146  void onChunkComplete(HTTPCodec::StreamID /*stream*/) override {
147  chunkComplete++;
148  }
150  std::unique_ptr<HTTPHeaders> inTrailers) override {
151  trailers++;
152  if (msg) {
153  msg->setTrailers(std::move(inTrailers));
154  }
155  }
157  bool /*upgrade*/) override {
158  messageComplete++;
159  }
161  const HTTPException& error,
162  bool /*newStream*/) override {
163  if (stream != sessionStreamId) {
164  streamErrors++;
165  } else {
166  sessionErrors++;
167  }
168  lastParseError = std::make_unique<HTTPException>(error);
169  }
170 
171  void onAbort(HTTPCodec::StreamID /*stream*/, ErrorCode code) override {
172  ++aborts;
173  lastErrorCode = code;
174  }
175 
177  HTTPCodec::StreamID /*streamId*/,
178  uint8_t /*flags*/,
179  uint64_t /*length*/,
180  uint8_t /*type*/,
181  uint16_t /*version*/) override {
182  ++headerFrames;
183  }
184 
185  void onGoaway(uint64_t lastStreamId,
186  ErrorCode,
187  std::unique_ptr<folly::IOBuf> debugData) override {
188  ++goaways;
189  goawayStreamIds.emplace_back(lastStreamId);
190  data.append(std::move(debugData));
191  }
192 
193  void onPingRequest(uint64_t uniqueID) override {
194  recvPingRequest = uniqueID;
195  }
196 
197  void onPingReply(uint64_t uniqueID) override {
198  recvPingReply = uniqueID;
199  }
200 
201  void onPriority(HTTPCodec::StreamID /*streamID*/,
202  const HTTPMessage::HTTPPriority& pri) override {
203  priority = pri;
204  }
205 
208  windowUpdates[stream].push_back(amount);
209  }
210 
211  void onSettings(const SettingsList& inSettings) override {
212  settings++;
213  numSettings += inSettings.size();
214  for (auto& setting: inSettings) {
215  if (setting.id == SettingsId::INITIAL_WINDOW_SIZE) {
216  windowSize = setting.value;
217  } else if (setting.id == SettingsId::MAX_CONCURRENT_STREAMS) {
218  maxStreams = setting.value;
219  }
220  }
221  }
222 
223  void onSettingsAck() override {
224  settingsAcks++;
225  }
226 
228  uint16_t requestId, std::unique_ptr<folly::IOBuf> authRequest) override {
230  lastCertRequestId = requestId;
231  data.append(std::move(authRequest));
232  }
233 
234  void onCertificate(uint16_t certId,
235  std::unique_ptr<folly::IOBuf> authenticator) override {
236  certificates++;
237  lastCertId = certId;
238  data.append(std::move(authenticator));
239  }
240 
243  const std::string&,
244  HTTPMessage&) override {
245  return true;
246  }
247 
248  uint32_t numOutgoingStreams() const override {
249  return 0;
250  }
251 
252  uint32_t numIncomingStreams() const override {
253  return messageBegin;
254  }
255 
256  void expectMessage(bool eom, int32_t headerCount,
257  const std::string& url) const {
258  expectMessageHelper(eom, headerCount, url, -1);
259  }
260  void expectMessage(bool eom, int32_t headerCount,
261  int32_t statusCode) const {
262  expectMessageHelper(eom, headerCount, "", statusCode);
263  }
264 
265  void expectMessageHelper(bool eom, int32_t headerCount,
266  const std::string& url, int32_t statusCode) const {
269  EXPECT_EQ(messageComplete, eom ? 1 : 0);
272  EXPECT_NE(msg, nullptr);
273  if (headerCount >= 0) {
274  EXPECT_EQ(msg->getHeaders().size(), headerCount);
275  }
276  if (!url.empty()) {
277  EXPECT_EQ(msg->getURL(), url);
278  } else if (statusCode > 0) {
279  if (msg->isResponse()) {
280  EXPECT_EQ(msg->getStatusCode(), statusCode);
281  } else {
282  EXPECT_EQ(msg->getPushStatusCode(), statusCode);
283  }
284  }
285  }
286 
287  bool sessionError() const {
288  return sessionErrors > 0;
289  }
290 
291  std::function<bool()> getStopFn() {
293  }
294 
296  sessionStreamId = streamId;
297  }
298 
299  void reset() {
300  headersCompleteId = 0;
301  assocStreamId = 0;
302  controlStreamId = 0;
303  isUnidirectional = false;
304  messageBegin = 0;
305  headersComplete = 0;
306  messageComplete = 0;
307  bodyCalls = 0;
308  bodyLength = 0;
309  paddingBytes = 0;
310  chunkHeaders = 0;
311  chunkComplete = 0;
312  trailers = 0;
313  aborts = 0;
314  goaways = 0;
315  sessionErrors = 0;
316  streamErrors = 0;
317  recvPingRequest = 0;
318  recvPingReply = 0;
319  windowUpdateCalls = 0;
320  settings = 0;
321  settingsAcks = 0;
323  lastCertRequestId = 0;
324  certificates = 0;
325  lastCertId = 0;
326  windowSize = 0;
327  maxStreams = 0;
328  headerFrames = 0;
329  priority = HTTPMessage::HTTPPriority(0, false, 0);
330  windowUpdates.clear();
331  data.move();
332  msg.reset();
333  lastParseError.reset();
335  }
336 
337  void dumpCounters(int verbosity) const {
338  VLOG(verbosity) << "Dumping HTTP codec callback counters";
339  VLOG(verbosity) << "headersCompleteId: " << headersCompleteId;
340  VLOG(verbosity) << "assocStreamId: " << assocStreamId;
341  VLOG(verbosity) << "controlStreamId: " << controlStreamId;
342  VLOG(verbosity) << "unidirectional: " << isUnidirectional;
343  VLOG(verbosity) << "messageBegin: " << messageBegin;
344  VLOG(verbosity) << "headersComplete: " << headersComplete;
345  VLOG(verbosity) << "bodyCalls: " << bodyCalls;
346  VLOG(verbosity) << "bodyLength: " << bodyLength;
347  VLOG(verbosity) << "paddingBytes: " << paddingBytes;
348  VLOG(verbosity) << "chunkHeaders: " << chunkHeaders;
349  VLOG(verbosity) << "chunkComplete: " << chunkComplete;
350  VLOG(verbosity) << "trailers: " << trailers;
351  VLOG(verbosity) << "aborts: " << aborts;
352  VLOG(verbosity) << "goaways: " << goaways;
353  VLOG(verbosity) << "sessionErrors: " << sessionErrors;
354  VLOG(verbosity) << "streamErrors: " << streamErrors;
355  VLOG(verbosity) << "recvPingRequest: " << recvPingRequest;
356  VLOG(verbosity) << "recvPingReply: " << recvPingReply;
357  VLOG(verbosity) << "windowUpdateCalls: " << windowUpdateCalls;
358  VLOG(verbosity) << "settings: " << settings;
359  VLOG(verbosity) << "settingsAcks: " << settingsAcks;
360  VLOG(verbosity) << "certificateRequests: " << certificateRequests;
361  VLOG(verbosity) << "lastCertRequestId: " << lastCertRequestId;
362  VLOG(verbosity) << "certificates: " << certificates;
363  VLOG(verbosity) << "lastCertId: " << lastCertId;
364  VLOG(verbosity) << "windowSize: " << windowSize;
365  VLOG(verbosity) << "maxStreams: " << maxStreams;
366  VLOG(verbosity) << "headerFrames: " << headerFrames;
367  }
368 
372  bool isUnidirectional{false};
401  std::map<proxygen::HTTPCodec::StreamID, std::vector<uint32_t> > windowUpdates;
403 
404  std::unique_ptr<HTTPMessage> msg;
405  std::unique_ptr<HTTPException> lastParseError;
407  std::vector<HTTPCodec::StreamID> goawayStreamIds;
408 };
409 
410 MATCHER_P(PtrBufHasLen, n, "") {
411  return arg->computeChainDataLength() == n;
412 }
413 
414 std::unique_ptr<HTTPMessage> getPriorityMessage(uint8_t priority);
415 
416 std::unique_ptr<folly::IOBuf> makeBuf(uint32_t size = 10);
417 
418 std::unique_ptr<testing::NiceMock<MockHTTPCodec>>
420 
421 std::unique_ptr<testing::NiceMock<MockHTTPCodec>>
423 
426 HTTPMessage getPostRequest(uint32_t contentLength = 200);
429 HTTPMessage getResponse(uint32_t code, uint32_t bodyLen = 0);
430 HTTPMessage getUpgradeRequest(const std::string& upgradeHeader,
431  HTTPMethod method = HTTPMethod::GET,
432  uint32_t bodyLen = 0);
433 
434 std::unique_ptr<HTTPMessage> makeGetRequest();
435 std::unique_ptr<HTTPMessage> makePostRequest(uint32_t contentLength = 200);
436 std::unique_ptr<HTTPMessage> makeResponse(uint16_t statusCode);
437 
438 std::tuple<std::unique_ptr<HTTPMessage>, std::unique_ptr<folly::IOBuf> >
439 makeResponse(uint16_t statusCode, size_t len);
440 
441 // Takes a MockHTTPCodec and fakes out its interface
442 void fakeMockCodec(MockHTTPCodec& codec);
443 
444 }
std::unique_ptr< folly::IOBuf > split(size_t n)
Definition: IOBufQueue.h:420
int verbosity
Definition: upload.py:59
std::unique_ptr< testing::NiceMock< MockHTTPCodec > > makeDownstreamParallelCodec()
Definition: TestUtils.cpp:67
#define T(v)
Definition: http_parser.c:233
std::unique_ptr< folly::IOBuf > makeBuf(uint32_t size)
Definition: TestUtils.cpp:36
const folly::IOBuf * front() const
Definition: IOBufQueue.h:476
HTTPCodec::StreamID assocStreamId
Definition: TestUtils.h:370
void append(std::unique_ptr< folly::IOBuf > &&buf, bool pack=false)
Definition: IOBufQueue.cpp:143
size_t chainLength() const
Definition: IOBufQueue.h:492
spdy::GoawayStatusCode statusCode
Definition: SPDYCodec.cpp:110
void onMessageBegin(HTTPCodec::StreamID, HTTPMessage *) override
Definition: TestUtils.h:111
HTTPMessage getChunkedPostRequest()
Definition: TestUtils.cpp:113
void onSettingsAck() override
Definition: TestUtils.h:223
void onMessageComplete(HTTPCodec::StreamID, bool) override
Definition: TestUtils.h:156
void expectMessageHelper(bool eom, int32_t headerCount, const std::string &url, int32_t statusCode) const
Definition: TestUtils.h:265
void onChunkHeader(HTTPCodec::StreamID, size_t) override
Definition: TestUtils.h:142
std::unique_ptr< HTTPException > lastParseError
Definition: TestUtils.h:405
StreamCodecFactory stream
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void onExMessageBegin(HTTPCodec::StreamID, HTTPCodec::StreamID controlStream, bool unidirectional, HTTPMessage *) override
Definition: TestUtils.h:120
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void onPingReply(uint64_t uniqueID) override
Definition: TestUtils.h:197
HTTPMessage getBigGetRequest(const std::string &url)
Definition: TestUtils.cpp:85
void onGoaway(uint64_t lastStreamId, ErrorCode, std::unique_ptr< folly::IOBuf > debugData) override
Definition: TestUtils.h:185
void onPingRequest(uint64_t uniqueID) override
Definition: TestUtils.h:193
CodecFactory codec
size_t parseUnidirectional(T *codec, const uint8_t *inputData, uint32_t length, int32_t atOnce=0, std::function< bool()> stopFn=[]{return false;})
Definition: TestUtils.h:67
std::function< bool()> getStopFn()
Definition: TestUtils.h:291
std::unique_ptr< folly::IOBuf > move()
Definition: IOBufQueue.h:459
void onPushMessageBegin(HTTPCodec::StreamID, HTTPCodec::StreamID assocStream, HTTPMessage *) override
Definition: TestUtils.h:114
HTTPCodec::StreamID headersCompleteId
Definition: TestUtils.h:369
uint32_t numOutgoingStreams() const override
Definition: TestUtils.h:248
std::unique_ptr< HTTPMessage > makePostRequest(uint32_t contentLength)
Definition: TestUtils.cpp:124
void onFrameHeader(HTTPCodec::StreamID, uint8_t, uint64_t, uint8_t, uint16_t) override
Definition: TestUtils.h:176
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
void expectMessage(bool eom, int32_t headerCount, const std::string &url) const
Definition: TestUtils.h:256
void setSessionStreamId(HTTPCodec::StreamID streamId)
Definition: TestUtils.h:295
auto rng
Definition: CollectTest.cpp:31
std::map< proxygen::HTTPCodec::StreamID, std::vector< uint32_t > > windowUpdates
Definition: TestUtils.h:401
void onAbort(HTTPCodec::StreamID, ErrorCode code) override
Definition: TestUtils.h:171
std::vector< HTTPCodec::StreamID > goawayStreamIds
Definition: TestUtils.h:407
HTTPCodec::StreamID sessionStreamId
Definition: TestUtils.h:373
void onPriority(HTTPCodec::StreamID, const HTTPMessage::HTTPPriority &pri) override
Definition: TestUtils.h:201
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
std::unique_ptr< HTTPMessage > getPriorityMessage(uint8_t priority)
Definition: TestUtils.cpp:29
LogLevel min
Definition: LogLevel.cpp:30
static Options cacheChainLength()
Definition: IOBufQueue.h:83
bool onNativeProtocolUpgrade(HTTPCodec::StreamID, CodecProtocol, const std::string &, HTTPMessage &) override
Definition: TestUtils.h:241
void onSettings(const SettingsList &inSettings) override
Definition: TestUtils.h:211
void onBody(HTTPCodec::StreamID, std::unique_ptr< folly::IOBuf > chain, uint16_t padding) override
Definition: TestUtils.h:134
HTTPMessage getResponse(uint32_t code, uint32_t bodyLen)
Definition: TestUtils.cpp:137
void fakeMockCodec(MockHTTPCodec &codec)
Definition: TestUtils.cpp:173
void onTrailersComplete(HTTPCodec::StreamID, std::unique_ptr< HTTPHeaders > inTrailers) override
Definition: TestUtils.h:149
void expectMessage(bool eom, int32_t headerCount, int32_t statusCode) const
Definition: TestUtils.h:260
void onError(HTTPCodec::StreamID stream, const HTTPException &error, bool) override
Definition: TestUtils.h:160
auto start
std::unique_ptr< HTTPMessage > makeResponse(uint16_t statusCode)
Definition: TestUtils.cpp:147
uint32_t numIncomingStreams() const override
Definition: TestUtils.h:252
std::size_t computeChainDataLength() const
Definition: IOBuf.cpp:501
void onCertificate(uint16_t certId, std::unique_ptr< folly::IOBuf > authenticator) override
Definition: TestUtils.h:234
void onHeadersComplete(HTTPCodec::StreamID stream, std::unique_ptr< HTTPMessage > inMsg) override
Definition: TestUtils.h:128
std::tuple< uint32_t, bool, uint8_t > HTTPPriority
Definition: HTTPMessage.h:592
std::vector< HTTPSetting > SettingsList
Definition: HTTPSettings.h:81
HTTPCodec::StreamID controlStreamId
Definition: TestUtils.h:371
void onWindowUpdate(HTTPCodec::StreamID stream, uint32_t amount) override
Definition: TestUtils.h:206
HTTPMessage getGetRequest(const std::string &url)
Definition: TestUtils.cpp:76
const char * string
Definition: Conv.cpp:212
int bind(NetworkSocket s, const sockaddr *name, socklen_t namelen)
Definition: NetOps.cpp:76
void dumpCounters(int verbosity) const
Definition: TestUtils.h:337
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
HTTPMessage getPostRequest(uint32_t contentLength)
Definition: TestUtils.cpp:102
std::unique_ptr< HTTPMessage > makeGetRequest()
Definition: TestUtils.cpp:98
uint64_t StreamID
Definition: HTTPCodec.h:49
HTTPMessage getUpgradeRequest(const std::string &upgradeHeader, HTTPMethod method, uint32_t bodyLen)
Definition: TestUtils.cpp:161
size_t parse(T *codec, const uint8_t *inputData, uint32_t length, int32_t atOnce=0, std::function< bool()> stopFn=[]{return false;})
Definition: TestUtils.h:28
std::unique_ptr< HTTPMessage > msg
Definition: TestUtils.h:404
void onChunkComplete(HTTPCodec::StreamID) override
Definition: TestUtils.h:146
void onCertificateRequest(uint16_t requestId, std::unique_ptr< folly::IOBuf > authRequest) override
Definition: TestUtils.h:227
static std::unique_ptr< IOBuf > copyBuffer(const void *buf, std::size_t size, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:1587
MATCHER_P(PtrBufHasLen, n,"")
Definition: TestUtils.h:410
HTTPMessage::HTTPPriority priority
Definition: TestUtils.h:400
std::unique_ptr< testing::NiceMock< MockHTTPCodec > > makeUpstreamParallelCodec()
Definition: TestUtils.cpp:72
HTTPMessage getPubRequest(const std::string &url)
Definition: TestUtils.cpp:128