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