| #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); |
| } |
| } |
| }; |