blob: 3235372157864170c79680a561f3bf76d5f4d22f [file] [log] [blame]
#pragma once
extern "C"
{
#include <nghttp2/nghttp2.h>
}
#include "logging.hpp"
#include <span>
/* This file contains RAII compatible adapters for nghttp2 structures. They
* attempt to be as close to a direct call as possible, while keeping the RAII
* lifetime safety for the various classes.*/
struct nghttp2_session;
struct nghttp2_session_callbacks
{
friend nghttp2_session;
nghttp2_session_callbacks()
{
nghttp2_session_callbacks_new(&ptr);
}
~nghttp2_session_callbacks()
{
nghttp2_session_callbacks_del(ptr);
}
nghttp2_session_callbacks(const nghttp2_session_callbacks&) = delete;
nghttp2_session_callbacks&
operator=(const nghttp2_session_callbacks&) = delete;
nghttp2_session_callbacks(nghttp2_session_callbacks&&) = delete;
nghttp2_session_callbacks& operator=(nghttp2_session_callbacks&&) = delete;
void setSendCallback(nghttp2_send_callback sendCallback)
{
nghttp2_session_callbacks_set_send_callback(ptr, sendCallback);
}
void setOnFrameRecvCallback(nghttp2_on_frame_recv_callback recvCallback)
{
nghttp2_session_callbacks_set_on_frame_recv_callback(ptr, recvCallback);
}
void setOnStreamCloseCallback(nghttp2_on_stream_close_callback onClose)
{
nghttp2_session_callbacks_set_on_stream_close_callback(ptr, onClose);
}
void setOnHeaderCallback(nghttp2_on_header_callback onHeader)
{
nghttp2_session_callbacks_set_on_header_callback(ptr, onHeader);
}
void setOnBeginHeadersCallback(
nghttp2_on_begin_headers_callback onBeginHeaders)
{
nghttp2_session_callbacks_set_on_begin_headers_callback(ptr,
onBeginHeaders);
}
void setSendDataCallback(nghttp2_send_data_callback onSendData)
{
nghttp2_session_callbacks_set_send_data_callback(ptr, onSendData);
}
void setBeforeFrameSendCallback(
nghttp2_before_frame_send_callback beforeSendFrame)
{
nghttp2_session_callbacks_set_before_frame_send_callback(
ptr, beforeSendFrame);
}
void
setAfterFrameSendCallback(nghttp2_on_frame_send_callback afterSendFrame)
{
nghttp2_session_callbacks_set_on_frame_send_callback(ptr,
afterSendFrame);
}
void setAfterFrameNoSendCallback(
nghttp2_on_frame_not_send_callback afterSendFrame)
{
nghttp2_session_callbacks_set_on_frame_not_send_callback(
ptr, afterSendFrame);
}
void setOnDataChunkRecvCallback(
nghttp2_on_data_chunk_recv_callback afterDataChunkRecv)
{
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
ptr, afterDataChunkRecv);
}
private:
nghttp2_session_callbacks* get()
{
return ptr;
}
nghttp2_session_callbacks* ptr = nullptr;
};
struct nghttp2_session
{
explicit nghttp2_session(nghttp2_session_callbacks& callbacks)
{
if (nghttp2_session_server_new(&ptr, callbacks.get(), nullptr) != 0)
{
BMCWEB_LOG_ERROR("nghttp2_session_server_new failed");
return;
}
}
~nghttp2_session()
{
nghttp2_session_del(ptr);
}
// explicitly uncopyable
nghttp2_session(const nghttp2_session&) = delete;
nghttp2_session& operator=(const nghttp2_session&) = delete;
nghttp2_session(nghttp2_session&& other) noexcept : ptr(other.ptr)
{
other.ptr = nullptr;
}
nghttp2_session& operator=(nghttp2_session&& other) noexcept = delete;
int submitSettings(std::span<nghttp2_settings_entry> iv)
{
return nghttp2_submit_settings(ptr, NGHTTP2_FLAG_NONE, iv.data(),
iv.size());
}
void setUserData(void* object)
{
nghttp2_session_set_user_data(ptr, object);
}
ssize_t memRecv(std::span<const uint8_t> buffer)
{
return nghttp2_session_mem_recv(ptr, buffer.data(), buffer.size());
}
std::span<const uint8_t> memSend()
{
const uint8_t* bytes = nullptr;
ssize_t size = nghttp2_session_mem_send(ptr, &bytes);
return {bytes, static_cast<size_t>(size)};
}
int submitResponse(int32_t streamId, std::span<const nghttp2_nv> headers,
const nghttp2_data_provider* dataPrd)
{
return nghttp2_submit_response(ptr, streamId, headers.data(),
headers.size(), dataPrd);
}
private:
nghttp2_session* ptr = nullptr;
};
class nghttp2_hd_inflater
{
nghttp2_hd_inflater* ptr = nullptr;
public:
nghttp2_hd_inflater()
{
if (nghttp2_hd_inflate_new(&ptr) != 0)
{
BMCWEB_LOG_ERROR("nghttp2_hd_inflater_new failed");
}
}
ssize_t hd2(nghttp2_nv* nvOut, int* inflateFlags, const uint8_t* in,
size_t inlen, int inFinal)
{
return nghttp2_hd_inflate_hd2(ptr, nvOut, inflateFlags, in, inlen,
inFinal);
}
int endHeaders()
{
return nghttp2_hd_inflate_end_headers(ptr);
}
nghttp2_hd_inflater(const nghttp2_hd_inflater&) = delete;
nghttp2_hd_inflater& operator=(const nghttp2_hd_inflater&) = delete;
nghttp2_hd_inflater& operator=(nghttp2_hd_inflater&&) = delete;
nghttp2_hd_inflater(nghttp2_hd_inflater&& other) = delete;
~nghttp2_hd_inflater()
{
if (ptr != nullptr)
{
nghttp2_hd_inflate_del(ptr);
}
}
};