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