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