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