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