blob: f10b2b8218bf0b41f5c9b2f5dd0bdbb34712b5da [file] [log] [blame]
#include "quiche/http2/adapter/nghttp2_data_provider.h"
#include "quiche/http2/adapter/http2_visitor_interface.h"
#include "quiche/http2/adapter/nghttp2_util.h"
namespace http2 {
namespace adapter {
namespace callbacks {
namespace {
const size_t kFrameHeaderSize = 9;
}
ssize_t DataFrameSourceReadCallback(nghttp2_session* /* session */,
int32_t /* stream_id */, uint8_t* /* buf */,
size_t length, uint32_t* data_flags,
nghttp2_data_source* source,
void* /* user_data */) {
*data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
auto* frame_source = static_cast<DataFrameSource*>(source->ptr);
auto [result_length, done] = frame_source->SelectPayloadLength(length);
if (result_length == 0 && !done) {
return NGHTTP2_ERR_DEFERRED;
} else if (result_length == DataFrameSource::kError) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if (done) {
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
if (!frame_source->send_fin()) {
*data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
}
return result_length;
}
int DataFrameSourceSendCallback(nghttp2_session* /* session */,
nghttp2_frame* /* frame */,
const uint8_t* framehd, size_t length,
nghttp2_data_source* source,
void* /* user_data */) {
auto* frame_source = static_cast<DataFrameSource*>(source->ptr);
frame_source->Send(ToStringView(framehd, kFrameHeaderSize), length);
return 0;
}
} // namespace callbacks
std::unique_ptr<nghttp2_data_provider> MakeDataProvider(
DataFrameSource* source) {
if (source == nullptr) {
return nullptr;
}
auto provider = absl::make_unique<nghttp2_data_provider>();
provider->source.ptr = source;
provider->read_callback = &callbacks::DataFrameSourceReadCallback;
return provider;
}
} // namespace adapter
} // namespace http2