1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 #pragma once 4 5 extern "C" 6 { 7 #include <nghttp2/nghttp2.h> 8 } 9 10 #include "logging.hpp" 11 12 #include <bit> 13 #include <span> 14 #include <string_view> 15 16 /* This file contains RAII compatible adapters for nghttp2 structures. They 17 * attempt to be as close to a direct call as possible, while keeping the RAII 18 * lifetime safety for the various classes. Because of this, they use the same 19 * naming as nghttp2, so ignore naming violations. 20 */ 21 22 // NOLINTBEGIN(readability-identifier-naming, 23 // readability-make-member-function-const) 24 25 struct nghttp2_session; 26 27 struct nghttp2_session_callbacks 28 { 29 friend nghttp2_session; nghttp2_session_callbacksnghttp2_session_callbacks30 nghttp2_session_callbacks() 31 { 32 nghttp2_session_callbacks_new(&ptr); 33 } 34 ~nghttp2_session_callbacksnghttp2_session_callbacks35 ~nghttp2_session_callbacks() 36 { 37 nghttp2_session_callbacks_del(ptr); 38 } 39 40 nghttp2_session_callbacks(const nghttp2_session_callbacks&) = delete; 41 nghttp2_session_callbacks& operator=(const nghttp2_session_callbacks&) = 42 delete; 43 nghttp2_session_callbacks(nghttp2_session_callbacks&&) = delete; 44 nghttp2_session_callbacks& operator=(nghttp2_session_callbacks&&) = delete; 45 setSendCallbacknghttp2_session_callbacks46 void setSendCallback(nghttp2_send_callback sendCallback) 47 { 48 nghttp2_session_callbacks_set_send_callback(ptr, sendCallback); 49 } 50 setOnFrameRecvCallbacknghttp2_session_callbacks51 void setOnFrameRecvCallback(nghttp2_on_frame_recv_callback recvCallback) 52 { 53 nghttp2_session_callbacks_set_on_frame_recv_callback(ptr, recvCallback); 54 } 55 setOnStreamCloseCallbacknghttp2_session_callbacks56 void setOnStreamCloseCallback(nghttp2_on_stream_close_callback onClose) 57 { 58 nghttp2_session_callbacks_set_on_stream_close_callback(ptr, onClose); 59 } 60 setOnHeaderCallbacknghttp2_session_callbacks61 void setOnHeaderCallback(nghttp2_on_header_callback onHeader) 62 { 63 nghttp2_session_callbacks_set_on_header_callback(ptr, onHeader); 64 } 65 setOnBeginHeadersCallbacknghttp2_session_callbacks66 void setOnBeginHeadersCallback( 67 nghttp2_on_begin_headers_callback onBeginHeaders) 68 { 69 nghttp2_session_callbacks_set_on_begin_headers_callback( 70 ptr, onBeginHeaders); 71 } 72 setSendDataCallbacknghttp2_session_callbacks73 void setSendDataCallback(nghttp2_send_data_callback onSendData) 74 { 75 nghttp2_session_callbacks_set_send_data_callback(ptr, onSendData); 76 } setBeforeFrameSendCallbacknghttp2_session_callbacks77 void setBeforeFrameSendCallback( 78 nghttp2_before_frame_send_callback beforeSendFrame) 79 { 80 nghttp2_session_callbacks_set_before_frame_send_callback( 81 ptr, beforeSendFrame); 82 } setAfterFrameSendCallbacknghttp2_session_callbacks83 void setAfterFrameSendCallback( 84 nghttp2_on_frame_send_callback afterSendFrame) 85 { 86 nghttp2_session_callbacks_set_on_frame_send_callback(ptr, 87 afterSendFrame); 88 } setAfterFrameNoSendCallbacknghttp2_session_callbacks89 void setAfterFrameNoSendCallback( 90 nghttp2_on_frame_not_send_callback afterSendFrame) 91 { 92 nghttp2_session_callbacks_set_on_frame_not_send_callback( 93 ptr, afterSendFrame); 94 } 95 setOnDataChunkRecvCallbacknghttp2_session_callbacks96 void setOnDataChunkRecvCallback( 97 nghttp2_on_data_chunk_recv_callback afterDataChunkRecv) 98 { 99 nghttp2_session_callbacks_set_on_data_chunk_recv_callback( 100 ptr, afterDataChunkRecv); 101 } 102 103 private: getnghttp2_session_callbacks104 nghttp2_session_callbacks* get() 105 { 106 return ptr; 107 } 108 109 nghttp2_session_callbacks* ptr = nullptr; 110 }; 111 112 struct nghttp2_session 113 { nghttp2_sessionnghttp2_session114 explicit nghttp2_session(nghttp2_session_callbacks& callbacks) 115 { 116 if (nghttp2_session_server_new(&ptr, callbacks.get(), nullptr) != 0) 117 { 118 BMCWEB_LOG_ERROR("nghttp2_session_server_new failed"); 119 return; 120 } 121 } 122 ~nghttp2_sessionnghttp2_session123 ~nghttp2_session() 124 { 125 nghttp2_session_del(ptr); 126 } 127 128 // explicitly uncopyable 129 nghttp2_session(const nghttp2_session&) = delete; 130 nghttp2_session& operator=(const nghttp2_session&) = delete; 131 nghttp2_sessionnghttp2_session132 nghttp2_session(nghttp2_session&& other) noexcept : ptr(other.ptr) 133 { 134 other.ptr = nullptr; 135 } 136 137 nghttp2_session& operator=(nghttp2_session&& other) noexcept = delete; 138 submitSettingsnghttp2_session139 int submitSettings(std::span<nghttp2_settings_entry> iv) 140 { 141 return nghttp2_submit_settings(ptr, NGHTTP2_FLAG_NONE, iv.data(), 142 iv.size()); 143 } 144 sessionUpgrade2nghttp2_session145 int sessionUpgrade2(std::string_view settingsPayload, bool headRequest) 146 { 147 return nghttp2_session_upgrade2( 148 ptr, std::bit_cast<uint8_t*>(settingsPayload.data()), 149 settingsPayload.size(), headRequest ? 1 : 0, nullptr); 150 } 151 setUserDatanghttp2_session152 void setUserData(void* object) 153 { 154 nghttp2_session_set_user_data(ptr, object); 155 } 156 memRecvnghttp2_session157 ssize_t memRecv(std::span<const uint8_t> buffer) 158 { 159 return nghttp2_session_mem_recv(ptr, buffer.data(), buffer.size()); 160 } 161 memSendnghttp2_session162 std::span<const uint8_t> memSend() 163 { 164 const uint8_t* bytes = nullptr; 165 ssize_t size = nghttp2_session_mem_send(ptr, &bytes); 166 return {bytes, static_cast<size_t>(size)}; 167 } 168 submitResponsenghttp2_session169 int submitResponse(int32_t streamId, std::span<const nghttp2_nv> headers, 170 const nghttp2_data_provider* dataPrd) 171 { 172 return nghttp2_submit_response(ptr, streamId, headers.data(), 173 headers.size(), dataPrd); 174 } 175 176 private: 177 nghttp2_session* ptr = nullptr; 178 }; 179 180 struct nghttp2_hd_inflater_ex 181 { 182 nghttp2_hd_inflater* ptr = nullptr; 183 184 public: nghttp2_hd_inflater_exnghttp2_hd_inflater_ex185 nghttp2_hd_inflater_ex() 186 { 187 if (nghttp2_hd_inflate_new(&ptr) != 0) 188 { 189 BMCWEB_LOG_ERROR("nghttp2_hd_inflater_new failed"); 190 } 191 } 192 hd2nghttp2_hd_inflater_ex193 ssize_t hd2(nghttp2_nv* nvOut, int* inflateFlags, const uint8_t* in, 194 size_t inlen, int inFinal) 195 { 196 return nghttp2_hd_inflate_hd2(ptr, nvOut, inflateFlags, in, inlen, 197 inFinal); 198 } 199 endHeadersnghttp2_hd_inflater_ex200 int endHeaders() 201 { 202 return nghttp2_hd_inflate_end_headers(ptr); 203 } 204 205 nghttp2_hd_inflater_ex(const nghttp2_hd_inflater_ex&) = delete; 206 nghttp2_hd_inflater_ex& operator=(const nghttp2_hd_inflater_ex&) = delete; 207 nghttp2_hd_inflater_ex& operator=(nghttp2_hd_inflater_ex&&) = delete; 208 nghttp2_hd_inflater_ex(nghttp2_hd_inflater_ex&& other) = delete; 209 ~nghttp2_hd_inflater_exnghttp2_hd_inflater_ex210 ~nghttp2_hd_inflater_ex() 211 { 212 if (ptr != nullptr) 213 { 214 nghttp2_hd_inflate_del(ptr); 215 } 216 } 217 }; 218 // NOLINTEND(readability-identifier-naming, 219 // readability-make-member-function-const) 220