blob: 9ac6ef6879423b6e8b9a74b1b2080ea36968ffca [file] [log] [blame]
#include "quiche/http2/adapter/nghttp2_util.h"
#include "quiche/http2/adapter/nghttp2_test_utils.h"
#include "quiche/http2/adapter/test_utils.h"
#include "quiche/common/platform/api/quiche_test.h"
namespace http2 {
namespace adapter {
namespace test {
namespace {
// This send callback assumes |source|'s pointer is a TestDataSource, and
// |user_data| is a std::string.
int FakeSendCallback(nghttp2_session*, nghttp2_frame* /*frame*/,
const uint8_t* framehd, size_t length,
nghttp2_data_source* source, void* user_data) {
auto* dest = static_cast<std::string*>(user_data);
// Appends the frame header to the string.
absl::StrAppend(dest, ToStringView(framehd, 9));
auto* test_source = static_cast<TestDataSource*>(source->ptr);
absl::string_view payload = test_source->ReadNext(length);
// Appends the frame payload to the string.
absl::StrAppend(dest, payload);
return 0;
}
TEST(MakeZeroCopyDataFrameSource, EmptyPayload) {
std::string result;
const absl::string_view kEmptyBody = "";
TestDataSource body1{kEmptyBody};
// The TestDataSource is wrapped in the nghttp2_data_provider data type.
nghttp2_data_provider provider = body1.MakeDataProvider();
// This call transforms it back into a DataFrameSource, which is compatible
// with the Http2Adapter API.
std::unique_ptr<DataFrameSource> frame_source =
MakeZeroCopyDataFrameSource(provider, &result, FakeSendCallback);
auto [length, eof] = frame_source->SelectPayloadLength(100);
EXPECT_EQ(length, 0);
EXPECT_TRUE(eof);
frame_source->Send("ninebytes", 0);
EXPECT_EQ(result, "ninebytes");
}
TEST(MakeZeroCopyDataFrameSource, ShortPayload) {
std::string result;
const absl::string_view kShortBody =
"<html><head><title>Example Page!</title></head>"
"<body><div><span><table><tr><th><blink>Wow!!"
"</blink></th></tr></table></span></div></body>"
"</html>";
TestDataSource body1{kShortBody};
// The TestDataSource is wrapped in the nghttp2_data_provider data type.
nghttp2_data_provider provider = body1.MakeDataProvider();
// This call transforms it back into a DataFrameSource, which is compatible
// with the Http2Adapter API.
std::unique_ptr<DataFrameSource> frame_source =
MakeZeroCopyDataFrameSource(provider, &result, FakeSendCallback);
auto [length, eof] = frame_source->SelectPayloadLength(200);
EXPECT_EQ(length, kShortBody.size());
EXPECT_TRUE(eof);
frame_source->Send("ninebytes", length);
EXPECT_EQ(result, absl::StrCat("ninebytes", kShortBody));
}
TEST(MakeZeroCopyDataFrameSource, MultiFramePayload) {
std::string result;
const absl::string_view kShortBody =
"<html><head><title>Example Page!</title></head>"
"<body><div><span><table><tr><th><blink>Wow!!"
"</blink></th></tr></table></span></div></body>"
"</html>";
TestDataSource body1{kShortBody};
// The TestDataSource is wrapped in the nghttp2_data_provider data type.
nghttp2_data_provider provider = body1.MakeDataProvider();
// This call transforms it back into a DataFrameSource, which is compatible
// with the Http2Adapter API.
std::unique_ptr<DataFrameSource> frame_source =
MakeZeroCopyDataFrameSource(provider, &result, FakeSendCallback);
auto ret = frame_source->SelectPayloadLength(50);
EXPECT_EQ(ret.first, 50);
EXPECT_FALSE(ret.second);
frame_source->Send("ninebyte1", ret.first);
ret = frame_source->SelectPayloadLength(50);
EXPECT_EQ(ret.first, 50);
EXPECT_FALSE(ret.second);
frame_source->Send("ninebyte2", ret.first);
ret = frame_source->SelectPayloadLength(50);
EXPECT_EQ(ret.first, 44);
EXPECT_TRUE(ret.second);
frame_source->Send("ninebyte3", ret.first);
EXPECT_EQ(result,
"ninebyte1<html><head><title>Example Page!</title></head><bo"
"ninebyte2dy><div><span><table><tr><th><blink>Wow!!</blink><"
"ninebyte3/th></tr></table></span></div></body></html>");
}
} // namespace
} // namespace test
} // namespace adapter
} // namespace http2