Mstdlib-1.24.0
m_net_http_simple.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2019 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_NET_HTTP_SIMPLE_H__
25#define __M_NET_HTTP_SIMPLE_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/mstdlib.h>
30#include <mstdlib/mstdlib_io.h>
31#include <mstdlib/mstdlib_formats.h>
32#include <mstdlib/mstdlib_tls.h>
33
34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
35
36__BEGIN_DECLS
37
38/*! \addtogroup m_net_http_simple HTTP Simple Net
39 * \ingroup m_net
40 *
41 * Simple HTTP network interface
42 *
43 * Allows for sending a request to a remote system and
44 * receiving a response. The response will be delivered
45 * as an M_http_simple_read_t via a callback.
46 *
47 * Redirects, and TLS upgrade/downgrades are handled
48 * internally by the module.
49 *
50 * Redirects have a default limit of 16 but this can
51 * be changed. It is imperative that the limit never
52 * be disabled or be set excessively large. Loop tracking
53 * is not supported and exiting redirect loops is handled
54 * by the redirect limit.
55 *
56 * Since this buffers data in memory the maximum received
57 * data size can be configured to prevent running out
58 * of memory. The default if not set is 50 MB.
59 *
60 * By default there is no timeout waiting for the
61 * operation to complete. It will wait indefinitely
62 * unless timeouts are explicitly set.
63 *
64 * Each instance of an M_net_http_simple_t can only be
65 * used once. Upon completion or cancel the object is internally
66 * destroyed and all references are invalidated.
67 *
68 * Example:
69 *
70 * \code{.c}
71 * #include <mstdlib/mstdlib.h>
72 * #include <mstdlib/mstdlib_io.h>
73 * #include <mstdlib/mstdlib_net.h>
74 * #include <mstdlib/mstdlib_formats.h>
75 *
76 * M_event_t *el;
77 *
78 * static void done_cb(M_net_error_t net_error, M_http_error_t http_error, const M_http_simple_read_t *simple, const char *error, void *thunk)
79 * {
80 * M_hash_dict_t *headers;
81 * M_hash_dict_enum_t *he;
82 * const char *key;
83 * const char *val;
84 * const unsigned char *data;
85 * size_t len;
86 *
87 * if (net_error != M_NET_ERROR_SUCCESS) {
88 * M_printf("Net Error: %s: %s\n", M_net_errcode_to_str(net_error), error);
89 * M_event_done(el);
90 * return;
91 * }
92 *
93 * if (http_error != M_HTTP_ERROR_SUCCESS) {
94 * M_printf("HTTP Error: %s: %s\n", M_http_errcode_to_str(http_error), error);
95 * M_event_done(el);
96 * return;
97 * }
98 *
99 * M_printf("---\n");
100 *
101 * M_printf("Status code: %u - %s\n", M_http_simple_read_status_code(simple), M_http_simple_read_reason_phrase(simple));
102 *
103 * M_printf("---\n");
104 *
105 * M_printf("Headers:\n");
106 * headers = M_http_simple_read_headers_dict(simple);
107 * M_hash_dict_enumerate(headers, &he);
108 * while (M_hash_dict_enumerate_next(headers, he, &key, &val)) {
109 * M_printf("\t%s: %s\n", key, val);
110 * }
111 * M_hash_dict_enumerate_free(he);
112 * M_hash_dict_destroy(headers);
113 *
114 * M_printf("---\n");
115 *
116 * M_printf("Body:\n");
117 * data = M_http_simple_read_body(simple, &len);
118 * M_printf("%.*s\n", (int)len, data);
119 *
120 * M_printf("---\n");
121 *
122 * M_event_done(el);
123 * }
124 *
125 * static void trace_cb(void *cb_arg, M_io_trace_type_t type, M_event_type_t event_type, const unsigned char *data, size_t data_len)
126 * {
127 * const char *io_type = "UNKNOWN";
128 * char *dump = NULL;
129 *
130 * switch (type) {
131 * case M_IO_TRACE_TYPE_READ:
132 * io_type = "READ";
133 * break;
134 * case M_IO_TRACE_TYPE_WRITE:
135 * io_type = "WRITE";
136 * break;
137 * case M_IO_TRACE_TYPE_EVENT:
138 * return;
139 * }
140 *
141 * dump = M_str_hexdump(M_STR_HEXDUMP_NONE, 0, "\t", data, data_len);
142 * if (M_str_isempty(dump)) {
143 * M_free(dump);
144 * dump = M_strdup("\t<No Data>");
145 * }
146 *
147 * M_printf("%s\n%s\n", io_type, dump);
148 * M_free(dump);
149 * }
150 *
151 * static M_bool iocreate_cb(M_io_t *io, char *error, size_t errlen, void *thunk)
152 * {
153 * (void)error;
154 * (void)errlen;
155 * (void)thunk;
156 *
157 * M_io_add_trace(io, NULL, trace_cb, io, NULL, NULL);
158 * return M_TRUE;
159 * }
160 *
161 * int main(int argc, char **argv)
162 * {
163 * M_net_http_simple_t *hs;
164 * M_dns_t *dns;
165 * M_tls_clientctx_t *ctx;
166 *
167 * el = M_event_create(M_EVENT_FLAG_NONE);
168 * dns = M_dns_create(el);
169 *
170 * ctx = M_tls_clientctx_create();
171 * M_tls_clientctx_set_default_trust(ctx);
172 * //M_tls_clientctx_set_verify_level(ctx, M_TLS_VERIFY_NONE);
173 *
174 * hs = M_net_http_simple_create(el, dns, done_cb);
175 * M_net_http_simple_set_timeouts(hs, 2000, 0, 0);
176 * M_net_http_simple_set_tlsctx(hs, ctx);
177 * M_net_http_simple_set_message(hs, M_HTTP_METHOD_GET, NULL, "text/plain", "utf-8", NULL, NULL, 0);
178 *
179 * M_net_http_simple_set_iocreate(hs, iocreate_cb);
180 *
181 * if (M_net_http_simple_send(hs, "http://google.com/", NULL)) {
182 * M_event_loop(el, M_TIMEOUT_INF);
183 * } else {
184 * M_net_http_simple_cancel(hs);
185 * M_printf("Send failed\n");
186 * }
187 *
188 * M_tls_clientctx_destroy(ctx);
189 * M_dns_destroy(dns);
190 * M_event_destroy(el);
191 * return 0;
192 * }
193 * \endcode
194 *
195 * @{
196 *
197 */
198
199struct M_net_http_simple;
200typedef struct M_net_http_simple M_net_http_simple_t;
201
202/*! Done callback called when the request has completed.
203 *
204 * Once this callback returns the M_net_http_simple_t object that called this
205 * callback is destroyed internally. All external references are thus
206 * invalidated.
207 *
208 * \param[in] net_error Indicates where there was a network problem of some type or
209 * if the network operation succeeded. If set to anything other
210 * than M_NET_ERROR_SUCCESS http_error and simple should not
211 * be vaulted because HTTP data was never received and parsed.
212 * \param[in] http_error Status of the HTTP response data parse.
213 * \param[in] simple The parsed HTTP data object. Will only
214 * be non-NULL when net_error is M_NET_ERROR_SUCCESS and
215 * http_error is M_HTTP_ERROR_SUCCESS.
216 * \param[in] error Textual error message when either net_error or http_error indicate
217 * an error condition.
218 * \param[in] thunk Thunk parameter provided to send call.
219 */
220typedef void (*M_net_http_simple_done_cb)(M_net_error_t net_error, M_http_error_t http_error, const M_http_simple_read_t *simple, const char *error, void *thunk);
221
222
223/*! Callback to set additional I/O layers on the internal network request I/O object.
224 *
225 * The primary use for this callback is to add tracing or bandwidth shaping. TLS
226 * should not be added here because it is handled internally.
227 *
228 * Due to redirects multiple connection to multiple servers may need to be established.
229 * The callback may be called multiple times. Once for each I/O object created to
230 * establish a connection with a given server.
231 *
232 * \param[in] io The base I/O object to add layers on top of.
233 * \param[in] error Error buffer to set a textual error message when returning a failure response.
234 * \param[in] errlen Size of error buffer.
235 * \param[in] thunk Thunk parameter provided to send call.
236 *
237 * \return M_TRUE on success. M_FALSE if setting up the I/O object failed and the operation should abort.
238 */
239typedef M_bool (*M_net_http_simple_iocreate_cb)(M_io_t *io, char *error, size_t errlen, void *thunk);
240
241
242/*! Create an HTTP simple network object.
243 *
244 * \param[in] el Event loop to operate on.
245 * \param[in] dns DNS object. Must be valid for the duration of this object's life.
246 * \param[in] done_cb Callback that's called on completion of the request.
247 *
248 * \return HTTP network object on success. Otherwise NULL on error.
249 */
251
252
253/*! Cancel the operation that's in progress.
254 *
255 * The hs object is invalided by this call.
256 * The registered done callback will not be called.
257 *
258 * Can be used to cancel an operation that has not yet been sent
259 * in order to destroy the hs object.
260 *
261 * \param[in] hs HTTP simple network object.
262 */
264
265/*! Set proxy server authentication.
266 *
267 * \param[in] hs HTTP simple network object.
268 * \param[in] user For use in basic credential user:pass
269 * \param[in] pass For use in basic credential user:pass
270 *
271 */
272M_API void M_net_http_simple_set_proxy_authentication(M_net_http_simple_t *hs, const char *user, const char *pass);
273
274/*! Set proxy server.
275 *
276 * \param[in] hs HTTP simple network object.
277 * \param[in] proxy_server URL to proxy request through.
278 *
279 */
280M_API void M_net_http_simple_set_proxy(M_net_http_simple_t *hs, const char *proxy_server);
281
282
283/*! Set operation timeouts.
284 *
285 * On timeout the operation will abort.
286 *
287 * No timeouts are set by default. Set to 0 to disable a timeout.
288 *
289 * \param[in] hs HTTP simple network object.
290 * \param[in] connect_ms Connect timeout in milliseconds. Will trigger when a connection
291 * has not been established within this time.
292 * \param[in] stall_ms Stall timeout in milliseconds. Will trigger when the time between read
293 * and write events has been exceeded. This helps prevent a server from causing
294 * a denial of service by sending 1 byte at a time with a large internal between
295 * each one.
296 * \param[in] overall_ms Overall time the operation can take in milliseconds. When exceeded the operation
297 * will abort.
298 */
299M_API void M_net_http_simple_set_timeouts(M_net_http_simple_t *hs, M_uint64 connect_ms, M_uint64 stall_ms, M_uint64 overall_ms);
300
301
302/*! Set the maximum number of allowed redirects
303 *
304 * Default 16 redirects.
305 *
306 * \param[in] hs HTTP simple network object.
307 * \param[in] max Maximum number of redirects. 0 will disable redirects.
308 */
310
311
312/*! Set max receive data size
313 *
314 * Default 50 MB.
315 *
316 * \param[in] hs HTTP simple network object.
317 * \param[in] max Maximum number of bytes that can be received. 0 will disable redirects.
318 * Use the value (1024*1024*50) bytes to set a 50 MB limit.
319 */
321
322
323/*! Set the TLS client context for use with HTTPS connections.
324 *
325 * It is highly recommend a TLS client context be provided even
326 * if the initial connection address is not HTTPS. It is possible
327 * for a redirect to imitate a redirect upgrade to a TLS connection.
328 *
329 * Even if the system is known to not support HTTPS it's possible it
330 * will be changed to require it in the future. Providing the client
331 * context will prevent connections from failing in the future due
332 * to this type of server side change.
333 *
334 * The context is only applied when necessary.
335 *
336 * \param[in] hs HTTP simple network object.
337 * \param[in] ctx The TLS client context. The context does not have to persist after being set here.
338 */
340
341
342/*! Set the I/O create callback.
343 *
344 * The callback is called when the hs object internally creates an I/O connection with a remote system.
345 *
346 * \param[in] hs HTTP simple network object.
347 * \param[in] iocreate_cb I/O create callback.
348 */
350
351
352/*! Set message data that should be sent with the request.
353 *
354 * This is optional. If this function is not called M_net_http_simple_send
355 * will issue a GET with no data.
356 *
357 * \param[in] hs HTTP simple network object.
358 * \param[in] method HTTP method.
359 * \param[in] user_agent User agent to identify the request using. Optional.
360 * \param[in] content_type Type of data being sent. Optional if no data is being sent. Or if set in headers.
361 * \param[in] charset Character set of data being sent. Only applies to textual data and should not be
362 * be set for binary. Optional depending on content type or if included in headers.
363 * \param[in] headers Additional headers to send with the request. Optional.
364 * \param[in] message The data to send. Optional.
365 * \param[in] message_len The length of the data. Required if message is not NULL otherwise should be 0.
366 */
367M_API void M_net_http_simple_set_message(M_net_http_simple_t *hs, M_http_method_t method, const char *user_agent, const char *content_type, const char *charset, const M_hash_dict_t *headers, const unsigned char *message, size_t message_len);
368
369
370/*! Start sending the request async.
371 *
372 * On success, the `hs` object is freed internally once the send completes
373 * and the done callback is called. It **must** not be reused.
374 *
375 * On failure of this call it can be called again if the error can be corrected.
376 * Otherwise if this fails M_net_http_simple_cancel needs to be called to
377 * cleanup the `hs` object.
378 *
379 * \param[in] hs HTTP simple network object.
380 * \param[in] url The **full** URL to send the request to. Must include http:// or https://.
381 * \param[in] thunk Thunk parameter that will be passed to the done callback. If allocated, must
382 * _not_ be freed before the done callback is called. Unless this function returns
383 * M_FALSE which prevents the done callback from running. For example, allocating a
384 * thunk and freeing in the done callback. Or freeing when this returns M_FALSE.
385 *
386 * \return M_TRUE when successfully starting the send process. `hs` will be freed internally.
387 * Otherwise, M_FALSE if sending could not commence. Will not call the done callback when M_FALSE.
388 * If not attempting again, allocated memory needs to be freed. An allocated `thunk` should be freed
389 * if necessary (would have been freed in the done callback). M_net_http_simple_cancel should be
390 * called on the `hs` object
391 */
392M_API M_bool M_net_http_simple_send(M_net_http_simple_t *hs, const char *url, void *thunk) M_WARN_UNUSED_RESULT;
393
394/*! @} */
395
396__END_DECLS
397
398#endif /* __M_NET_HTTP_SIMPLE_H__ */
struct M_dns M_dns_t
Definition: m_dns.h:43
struct M_event M_event_t
Definition: m_event.h:210
struct M_hash_dict M_hash_dict_t
Definition: m_hash_dict.h:52
struct M_http_simple_read M_http_simple_read_t
Definition: m_http.h:785
M_http_error_t
Definition: m_http.h:84
M_http_method_t
Definition: m_http.h:136
struct M_io M_io_t
Definition: m_io.h:59
M_net_error_t
Definition: m_net.h:44
M_bool M_net_http_simple_send(M_net_http_simple_t *hs, const char *url, void *thunk) M_WARN_UNUSED_RESULT
struct M_net_http_simple M_net_http_simple_t
Definition: m_net_http_simple.h:200
void M_net_http_simple_set_message(M_net_http_simple_t *hs, M_http_method_t method, const char *user_agent, const char *content_type, const char *charset, const M_hash_dict_t *headers, const unsigned char *message, size_t message_len)
void M_net_http_simple_cancel(M_net_http_simple_t *hs)
void M_net_http_simple_set_proxy(M_net_http_simple_t *hs, const char *proxy_server)
void M_net_http_simple_set_tlsctx(M_net_http_simple_t *hs, M_tls_clientctx_t *ctx)
void(* M_net_http_simple_done_cb)(M_net_error_t net_error, M_http_error_t http_error, const M_http_simple_read_t *simple, const char *error, void *thunk)
Definition: m_net_http_simple.h:220
void M_net_http_simple_set_timeouts(M_net_http_simple_t *hs, M_uint64 connect_ms, M_uint64 stall_ms, M_uint64 overall_ms)
void M_net_http_simple_set_proxy_authentication(M_net_http_simple_t *hs, const char *user, const char *pass)
M_net_http_simple_t * M_net_http_simple_create(M_event_t *el, M_dns_t *dns, M_net_http_simple_done_cb done_cb)
void M_net_http_simple_set_max_receive_size(M_net_http_simple_t *hs, M_uint64 max)
void M_net_http_simple_set_max_redirects(M_net_http_simple_t *hs, M_uint64 max)
void M_net_http_simple_set_iocreate(M_net_http_simple_t *hs, M_net_http_simple_iocreate_cb iocreate_cb)
M_bool(* M_net_http_simple_iocreate_cb)(M_io_t *io, char *error, size_t errlen, void *thunk)
Definition: m_net_http_simple.h:239
struct M_tls_clientctx M_tls_clientctx_t
Definition: m_tls.h:45