1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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.
7 */
8
9 #include <proxygen/lib/http/session/test/HQSessionTestCommon.h>
10 #include <quic/codec/QuicInteger.h>
11
12 #include <folly/Random.h>
13 #include <folly/String.h>
14
15 using namespace proxygen;
16 using namespace proxygen::hq;
17
encodeQuicIntegerWithAtLeast(uint64_t value,uint8_t atLeast,folly::io::QueueAppender & appender)18 size_t encodeQuicIntegerWithAtLeast(uint64_t value,
19 uint8_t atLeast,
20 folly::io::QueueAppender& appender) {
21 CHECK(atLeast == 1 || atLeast == 2 || atLeast == 4 || atLeast == 8);
22
23 CHECK_LE(value, quic::kEightByteLimit);
24 uint8_t numBytes = 0;
25 if (value <= quic::kOneByteLimit) {
26 numBytes = 1;
27 } else if (value <= quic::kTwoByteLimit) {
28 numBytes = 2;
29 } else if (value <= quic::kFourByteLimit) {
30 numBytes = 4;
31 } else if (value <= quic::kEightByteLimit) {
32 numBytes = 8;
33 }
34 CHECK_NE(numBytes, 0);
35 numBytes = std::max(numBytes, atLeast);
36 CHECK(numBytes == 1 || numBytes == 2 || numBytes == 4 || numBytes == 8);
37 if (numBytes == 1) {
38 uint8_t modified = static_cast<uint8_t>(value);
39 appender.writeBE(modified);
40 return sizeof(modified);
41 } else if (numBytes == 2) {
42 uint16_t reduced = static_cast<uint16_t>(value);
43 uint16_t modified = reduced | 0x4000;
44 appender.writeBE(modified);
45 return sizeof(modified);
46 } else if (numBytes == 4) {
47 uint32_t reduced = static_cast<uint32_t>(value);
48 uint32_t modified = reduced | 0x80000000;
49 appender.writeBE(modified);
50 return sizeof(modified);
51 } else if (numBytes == 8) {
52 uint64_t modified = value | 0xC000000000000000;
53 appender.writeBE(modified);
54 return sizeof(modified);
55 }
56 CHECK(false);
57 }
58
generateStreamPreface(folly::IOBufQueue & writeBuf,UnidirectionalStreamType type)59 size_t generateStreamPreface(folly::IOBufQueue& writeBuf,
60 UnidirectionalStreamType type) {
61 folly::io::QueueAppender appender(&writeBuf, 8);
62 uint8_t size = 1 << (folly::Random::rand32() % 4);
63 auto bytesWritten = encodeQuicIntegerWithAtLeast(
64 static_cast<hq::StreamTypeType>(type), size, appender);
65 CHECK_GE(bytesWritten, size);
66 return bytesWritten;
67 }
68
paramsToTestName(const testing::TestParamInfo<TestParams> & info)69 std::string paramsToTestName(const testing::TestParamInfo<TestParams>& info) {
70 std::vector<std::string> paramsV;
71 folly::split("-", info.param.alpn_, paramsV);
72 if (info.param.numBytesOnPushStream < kUnlimited) {
73 paramsV.push_back("_" +
74 folly::to<std::string>(info.param.numBytesOnPushStream));
75 }
76 if (info.param.unidirectionalStreamsCredit != kDefaultUnidirStreamCredit) {
77 paramsV.push_back(
78 "_" + folly::to<std::string>(info.param.unidirectionalStreamsCredit));
79 }
80 if (!info.param.createQPACKStreams_) {
81 paramsV.push_back("_noqpack");
82 }
83 if (info.param.datagrams_) {
84 paramsV.push_back("_datagrams");
85 }
86 return folly::join("", paramsV);
87 }
88
parseStreamPreface(folly::io::Cursor & cursor,std::string alpn)89 folly::Optional<std::pair<UnidirectionalStreamType, size_t>> parseStreamPreface(
90 folly::io::Cursor& cursor, std::string alpn) {
91 CHECK(!ALPN_H1Q_FB_V1);
92 auto res = quic::decodeQuicInteger(cursor);
93 if (!res) {
94 return folly::none;
95 }
96 auto prefaceEnum = UnidirectionalStreamType(res->first);
97 switch (prefaceEnum) {
98 case UnidirectionalStreamType::H1Q_CONTROL:
99 if (ALPN_H1Q_FB_V2) {
100 return std::make_pair(prefaceEnum, res->second);
101 } else {
102 return folly::none;
103 }
104 break;
105 case UnidirectionalStreamType::CONTROL:
106 case UnidirectionalStreamType::PUSH:
107 case UnidirectionalStreamType::QPACK_ENCODER:
108 case UnidirectionalStreamType::QPACK_DECODER:
109 if (ALPN_HQ) {
110 return std::make_pair(prefaceEnum, res->second);
111 } else {
112 return folly::none;
113 }
114 break;
115 default:
116 break;
117 }
118 return folly::none;
119 }
120
parseReadData(HQUnidirectionalCodec * codec,folly::IOBufQueue & readBuf,std::unique_ptr<folly::IOBuf> buf)121 void parseReadData(HQUnidirectionalCodec* codec,
122 folly::IOBufQueue& readBuf,
123 std::unique_ptr<folly::IOBuf> buf) {
124 readBuf.append(std::move(buf));
125 auto ret = codec->onUnidirectionalIngress(readBuf.move());
126 readBuf.append(std::move(ret));
127 }
128
createControlStream(quic::MockQuicSocketDriver * socketDriver,quic::StreamId id,UnidirectionalStreamType streamType)129 void createControlStream(quic::MockQuicSocketDriver* socketDriver,
130 quic::StreamId id,
131 UnidirectionalStreamType streamType) {
132 folly::IOBufQueue writeBuf{folly::IOBufQueue::cacheChainLength()};
133 auto length = generateStreamPreface(writeBuf, streamType);
134 CHECK_EQ(length, writeBuf.chainLength());
135 socketDriver->sock_->setControlStream(id);
136 for (size_t i = 0; i < length; i++) {
137 socketDriver->addReadEvent(
138 id, writeBuf.splitAtMost(1), std::chrono::milliseconds(0));
139 }
140 }
141