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 private: 88 nghttp2_session_callbacks* get() 89 { 90 return ptr; 91 } 92 93 nghttp2_session_callbacks* ptr = nullptr; 94 }; 95 96 struct nghttp2_session 97 { 98 explicit nghttp2_session(nghttp2_session_callbacks& callbacks) 99 { 100 if (nghttp2_session_server_new(&ptr, callbacks.get(), nullptr) != 0) 101 { 102 BMCWEB_LOG_ERROR("nghttp2_session_server_new failed"); 103 return; 104 } 105 } 106 107 ~nghttp2_session() 108 { 109 nghttp2_session_del(ptr); 110 } 111 112 // explicitly uncopyable 113 nghttp2_session(const nghttp2_session&) = delete; 114 nghttp2_session& operator=(const nghttp2_session&) = delete; 115 116 nghttp2_session(nghttp2_session&& other) noexcept : ptr(other.ptr) 117 { 118 other.ptr = nullptr; 119 } 120 121 nghttp2_session& operator=(nghttp2_session&& other) noexcept = delete; 122 123 int submitSettings(std::span<nghttp2_settings_entry> iv) 124 { 125 return nghttp2_submit_settings(ptr, NGHTTP2_FLAG_NONE, iv.data(), 126 iv.size()); 127 } 128 void setUserData(void* object) 129 { 130 nghttp2_session_set_user_data(ptr, object); 131 } 132 133 ssize_t memRecv(std::span<const uint8_t> buffer) 134 { 135 return nghttp2_session_mem_recv(ptr, buffer.data(), buffer.size()); 136 } 137 138 std::span<const uint8_t> memSend() 139 { 140 const uint8_t* bytes = nullptr; 141 ssize_t size = nghttp2_session_mem_send(ptr, &bytes); 142 return {bytes, static_cast<size_t>(size)}; 143 } 144 145 int submitResponse(int32_t streamId, std::span<const nghttp2_nv> headers, 146 const nghttp2_data_provider* dataPrd) 147 { 148 return nghttp2_submit_response(ptr, streamId, headers.data(), 149 headers.size(), dataPrd); 150 } 151 152 private: 153 nghttp2_session* ptr = nullptr; 154 }; 155 156 class nghttp2_hd_inflater 157 { 158 nghttp2_hd_inflater* ptr = nullptr; 159 160 public: 161 nghttp2_hd_inflater() 162 { 163 if (nghttp2_hd_inflate_new(&ptr) != 0) 164 { 165 BMCWEB_LOG_ERROR("nghttp2_hd_inflater_new failed"); 166 } 167 } 168 169 ssize_t hd2(nghttp2_nv* nvOut, int* inflateFlags, const uint8_t* in, 170 size_t inlen, int inFinal) 171 { 172 return nghttp2_hd_inflate_hd2(ptr, nvOut, inflateFlags, in, inlen, 173 inFinal); 174 } 175 176 int endHeaders() 177 { 178 return nghttp2_hd_inflate_end_headers(ptr); 179 } 180 181 nghttp2_hd_inflater(const nghttp2_hd_inflater&) = delete; 182 nghttp2_hd_inflater& operator=(const nghttp2_hd_inflater&) = delete; 183 nghttp2_hd_inflater& operator=(nghttp2_hd_inflater&&) = delete; 184 nghttp2_hd_inflater(nghttp2_hd_inflater&& other) = delete; 185 186 ~nghttp2_hd_inflater() 187 { 188 if (ptr != nullptr) 189 { 190 nghttp2_hd_inflate_del(ptr); 191 } 192 } 193 }; 194