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