xref: /openbmc/bmcweb/http/nghttp2_adapters.hpp (revision cd7dbb308f3e867e70a4e6de7880f889e8556eb7)
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