X Tutup
#include "ServerHttp2.h" #include "../../transfer/http2/HPack.h" #include #include namespace HttpServer { ServerHttp2::ServerHttp2( Socket::Adapter *sock, Http2::OutStream *stream ) noexcept : ServerProtocol(sock), stream(stream) { } ServerHttp2::~ServerHttp2() noexcept { delete this->stream; } static uint8_t getPaddingSize(const size_t dataSize) { if (0 == dataSize) { return 0; } std::random_device rd; uint8_t padding = uint8_t(rd()); while (dataSize <= padding) { padding /= 2; } return padding; } bool ServerHttp2::sendHeaders( const Http::StatusCode status, std::vector > &headers, const std::chrono::milliseconds &timeout, const bool endStream ) const { std::vector buf; buf.reserve(4096); buf.resize( Http2::FRAME_HEADER_SIZE + sizeof(uint8_t) ); headers.emplace( headers.begin(), ":status", std::to_string(static_cast(status) ) ); HPack::pack(buf, headers, this->stream->dynamic_table); size_t data_size = ( buf.size() - Http2::FRAME_HEADER_SIZE - sizeof(uint8_t) ); const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); if (data_size + padding_size > this->stream->settings.max_frame_size) { data_size = this->stream->settings.max_frame_size - padding_size; } const uint32_t frame_size = static_cast( data_size + padding_size ); buf.resize( frame_size + Http2::FRAME_HEADER_SIZE ); Http2::FrameFlag flags = Http2::FrameFlag::END_HEADERS; if (endStream) { flags |= Http2::FrameFlag::END_STREAM; } flags |= Http2::FrameFlag::PADDED; buf[Http2::FRAME_HEADER_SIZE] = char(padding); if (padding) { std::fill( buf.end() - padding, buf.end(), 0 ); } this->stream->setHttp2FrameHeader( reinterpret_cast(buf.data() ), frame_size, Http2::FrameType::HEADERS, flags ); const std::unique_lock lock(*this->stream->mtx); return this->sock->nonblock_send(buf.data(), buf.size(), timeout) > 0; } void ServerHttp2::sendWindowUpdate( const uint32_t size, const std::chrono::milliseconds &timeout ) const { std::array buf; uint8_t *addr = buf.data(); addr = this->stream->setHttp2FrameHeader( addr, sizeof(uint32_t), Http2::FrameType::WINDOW_UPDATE, Http2::FrameFlag::EMPTY ); *reinterpret_cast(addr) = ::htonl(size); const std::unique_lock lock(*this->stream->mtx); this->sock->nonblock_send(buf.data(), buf.size(), timeout); } long ServerHttp2::sendData( const void *src, const size_t size, const std::chrono::milliseconds &timeout, const bool endStream ) const noexcept { const uint8_t *data = reinterpret_cast(src); std::vector buf; buf.reserve( this->stream->settings.max_frame_size + Http2::FRAME_HEADER_SIZE ); size_t total = 0; while (total < size) { size_t data_size = (size - total < this->stream->settings.max_frame_size) ? size - total : this->stream->settings.max_frame_size; const uint8_t padding = getPaddingSize(data_size); const uint16_t padding_size = padding + sizeof(uint8_t); if (data_size + padding_size > this->stream->settings.max_frame_size) { data_size = this->stream->settings.max_frame_size - padding_size; } const uint32_t frame_size = static_cast( data_size + padding_size ); buf.resize(frame_size + Http2::FRAME_HEADER_SIZE); if (this->stream->window_size_out - long(this->stream->settings.max_frame_size) <= 0) { size_t update_size = this->stream->settings.initial_window_size + (size - total) - size_t(this->stream->window_size_out); if (update_size > Http2::MAX_WINDOW_UPDATE) { update_size = Http2::MAX_WINDOW_UPDATE; } this->sendWindowUpdate(uint32_t(update_size), timeout); this->stream->window_size_out += update_size; } Http2::FrameFlag flags = Http2::FrameFlag::EMPTY; if (endStream && (total + data_size >= size) ) { flags |= Http2::FrameFlag::END_STREAM; } size_t cur = Http2::FRAME_HEADER_SIZE; if (padding_size) { flags |= Http2::FrameFlag::PADDED; buf[cur] = padding; ++cur; } this->stream->setHttp2FrameHeader( buf.data(), frame_size, Http2::FrameType::DATA, flags ); std::copy( data, data + data_size, buf.data() + cur ); if (padding) { std::fill( buf.end() - padding, buf.end(), 0 ); } this->stream->lock(); const long sended = this->sock->nonblock_send( buf.data(), buf.size(), timeout ); this->stream->unlock(); if (sended <= 0) { total = 0; break; } this->stream->window_size_out -= frame_size; data += data_size; total += data_size; } return long(total); } }
X Tutup