1 #pragma once 2 3 extern "C" 4 { 5 #include <nghttp2/nghttp2.h> 6 } 7 8 #include "logging.hpp" 9 10 #include <span> 11 12 /* This file contains RAII compatible adapters for nghttp2 structures. They 13 * attempt to be as close to a direct call as possible, while keeping the RAII 14 * lifetime safety for the various classes.*/ 15 16 struct nghttp2_session; 17 18 struct nghttp2_session_callbacks 19 { 20 friend nghttp2_session; 21 nghttp2_session_callbacks() 22 { 23 nghttp2_session_callbacks_new(&ptr); 24 } 25 26 ~nghttp2_session_callbacks() 27 { 28 nghttp2_session_callbacks_del(ptr); 29 } 30 31 nghttp2_session_callbacks(const nghttp2_session_callbacks&) = delete; 32 nghttp2_session_callbacks& 33 operator=(const nghttp2_session_callbacks&) = delete; 34 nghttp2_session_callbacks(nghttp2_session_callbacks&&) = delete; 35 nghttp2_session_callbacks& operator=(nghttp2_session_callbacks&&) = delete; 36 37 void setSendCallback(nghttp2_send_callback sendCallback) 38 { 39 nghttp2_session_callbacks_set_send_callback(ptr, sendCallback); 40 } 41 42 void setOnFrameRecvCallback(nghttp2_on_frame_recv_callback recvCallback) 43 { 44 nghttp2_session_callbacks_set_on_frame_recv_callback(ptr, recvCallback); 45 } 46 47 void setOnStreamCloseCallback(nghttp2_on_stream_close_callback onClose) 48 { 49 nghttp2_session_callbacks_set_on_stream_close_callback(ptr, onClose); 50 } 51 52 void setOnHeaderCallback(nghttp2_on_header_callback onHeader) 53 { 54 nghttp2_session_callbacks_set_on_header_callback(ptr, onHeader); 55 } 56 57 void setOnBeginHeadersCallback( 58 nghttp2_on_begin_headers_callback onBeginHeaders) 59 { 60 nghttp2_session_callbacks_set_on_begin_headers_callback(ptr, 61 onBeginHeaders); 62 } 63 64 void setSendDataCallback(nghttp2_send_data_callback onSendData) 65 { 66 nghttp2_session_callbacks_set_send_data_callback(ptr, onSendData); 67 } 68 void setBeforeFrameSendCallback( 69 nghttp2_before_frame_send_callback beforeSendFrame) 70 { 71 nghttp2_session_callbacks_set_before_frame_send_callback( 72 ptr, beforeSendFrame); 73 } 74 void 75 setAfterFrameSendCallback(nghttp2_on_frame_send_callback afterSendFrame) 76 { 77 nghttp2_session_callbacks_set_on_frame_send_callback(ptr, 78 afterSendFrame); 79 } 80 void setAfterFrameNoSendCallback( 81 nghttp2_on_frame_not_send_callback afterSendFrame) 82 { 83 nghttp2_session_callbacks_set_on_frame_not_send_callback( 84 ptr, afterSendFrame); 85 } 86 87 void setOnDataChunkRecvCallback( 88 nghttp2_on_data_chunk_recv_callback afterDataChunkRecv) 89 { 90 nghttp2_session_callbacks_set_on_data_chunk_recv_callback( 91 ptr, afterDataChunkRecv); 92 } 93 94 private: 95 nghttp2_session_callbacks* get() 96 { 97 return ptr; 98 } 99 100 nghttp2_session_callbacks* ptr = nullptr; 101 }; 102 103 struct nghttp2_session 104 { 105 explicit nghttp2_session(nghttp2_session_callbacks& callbacks) 106 { 107 if (nghttp2_session_server_new(&ptr, callbacks.get(), nullptr) != 0) 108 { 109 BMCWEB_LOG_ERROR("nghttp2_session_server_new failed"); 110 return; 111 } 112 } 113 114 ~nghttp2_session() 115 { 116 nghttp2_session_del(ptr); 117 } 118 119 // explicitly uncopyable 120 nghttp2_session(const nghttp2_session&) = delete; 121 nghttp2_session& operator=(const nghttp2_session&) = delete; 122 123 nghttp2_session(nghttp2_session&& other) noexcept : ptr(other.ptr) 124 { 125 other.ptr = nullptr; 126 } 127 128 nghttp2_session& operator=(nghttp2_session&& other) noexcept = delete; 129 130 int submitSettings(std::span<nghttp2_settings_entry> iv) 131 { 132 return nghttp2_submit_settings(ptr, NGHTTP2_FLAG_NONE, iv.data(), 133 iv.size()); 134 } 135 void setUserData(void* object) 136 { 137 nghttp2_session_set_user_data(ptr, object); 138 } 139 140 ssize_t memRecv(std::span<const uint8_t> buffer) 141 { 142 return nghttp2_session_mem_recv(ptr, buffer.data(), buffer.size()); 143 } 144 145 std::span<const uint8_t> memSend() 146 { 147 const uint8_t* bytes = nullptr; 148 ssize_t size = nghttp2_session_mem_send(ptr, &bytes); 149 return {bytes, static_cast<size_t>(size)}; 150 } 151 152 int submitResponse(int32_t streamId, std::span<const nghttp2_nv> headers, 153 const nghttp2_data_provider* dataPrd) 154 { 155 return nghttp2_submit_response(ptr, streamId, headers.data(), 156 headers.size(), dataPrd); 157 } 158 159 private: 160 nghttp2_session* ptr = nullptr; 161 }; 162 163 class nghttp2_hd_inflater 164 { 165 nghttp2_hd_inflater* ptr = nullptr; 166 167 public: 168 nghttp2_hd_inflater() 169 { 170 if (nghttp2_hd_inflate_new(&ptr) != 0) 171 { 172 BMCWEB_LOG_ERROR("nghttp2_hd_inflater_new failed"); 173 } 174 } 175 176 ssize_t hd2(nghttp2_nv* nvOut, int* inflateFlags, const uint8_t* in, 177 size_t inlen, int inFinal) 178 { 179 return nghttp2_hd_inflate_hd2(ptr, nvOut, inflateFlags, in, inlen, 180 inFinal); 181 } 182 183 int endHeaders() 184 { 185 return nghttp2_hd_inflate_end_headers(ptr); 186 } 187 188 nghttp2_hd_inflater(const nghttp2_hd_inflater&) = delete; 189 nghttp2_hd_inflater& operator=(const nghttp2_hd_inflater&) = delete; 190 nghttp2_hd_inflater& operator=(nghttp2_hd_inflater&&) = delete; 191 nghttp2_hd_inflater(nghttp2_hd_inflater&& other) = delete; 192 193 ~nghttp2_hd_inflater() 194 { 195 if (ptr != nullptr) 196 { 197 nghttp2_hd_inflate_del(ptr); 198 } 199 } 200 }; 201