http.c (3984B)
1 /*
2 * Copyright (c) 2019 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * This example demonstrates how easy it is to perform asynchronous
19 * HTTP client requests using the integrated libcurl support.
20 *
21 * In this example we setup 2 states for an HTTP request:
22 * 1) setup
23 * We initialize the HTTP request and fire it off.
24 * This will put our HTTP request to sleep and it be woken up
25 * by Kore when a response is available or something went wrong.
26 *
27 * 2) result
28 * After we have woken up we have access to the result.
29 */
30
31 #include <kore/kore.h>
32 #include <kore/http.h>
33 #include <kore/curl.h>
34
35 int http(struct http_request *);
36
37 static int state_setup(struct http_request *);
38 static int state_result(struct http_request *);
39
40 /* Our states. */
41 static struct http_state states[] = {
42 KORE_HTTP_STATE(state_setup),
43 KORE_HTTP_STATE(state_result)
44 };
45
46 /* Transcend into the HTTP state machine for a request. */
47 int
48 http(struct http_request *req)
49 {
50 return (http_state_run(states, 2, req));
51 }
52
53 /*
54 * Setup the HTTP client request using the integrated curl API and the easy
55 * to use HTTP client api.
56 */
57 static int
58 state_setup(struct http_request *req)
59 {
60 struct kore_curl *client;
61
62 client = http_state_create(req, sizeof(*client));
63
64 /* Initialize curl. */
65 if (!kore_curl_init(client, "https://kore.io", KORE_CURL_ASYNC)) {
66 http_response(req, 500, NULL, 0);
67 return (HTTP_STATE_COMPLETE);
68 }
69
70 /* Setup our HTTP client request. */
71 kore_curl_http_setup(client, HTTP_METHOD_GET, NULL, 0);
72
73 /* Add some headers. */
74 kore_curl_http_set_header(client, "x-source", "from-example");
75
76 /* We could opt to override some settings ourselves if we wanted. */
77 /* curl_easy_setopt(client->handle, CURLOPT_SSL_VERIFYHOST, 0); */
78 /* curl_easy_setopt(client->handle, CURLOPT_SSL_VERIFYPEER, 0); */
79
80 /*
81 * Bind the HTTP client request to our HTTP request so we get woken
82 * up once a response is available.
83 *
84 * This will put us to sleep.
85 */
86 kore_curl_bind_request(client, req);
87
88 /*
89 * Now fire off the request onto the event loop.
90 */
91 kore_curl_run(client);
92
93 /* Make sure we go onto the next state once woken up. */
94 req->fsm_state = 1;
95
96 /* Tell Kore we can't complete this immediately. */
97 return (HTTP_STATE_RETRY);
98 }
99
100 /*
101 * This state is called when a result for the HTTP request call is
102 * available to us.
103 */
104 static int
105 state_result(struct http_request *req)
106 {
107 size_t len;
108 const u_int8_t *body;
109 const char *header;
110 struct kore_curl *client;
111
112 /* Get the state attached to the HTTP request. */
113 client = http_state_get(req);
114
115 /* Check if we were successful, if not log an error. */
116 if (!kore_curl_success(client)) {
117 kore_curl_logerror(client);
118 http_response(req, 500, NULL, 0);
119 } else {
120 /*
121 * Success! We now have the body available to us.
122 */
123 kore_curl_response_as_bytes(client, &body, &len);
124
125 /* We could check the existence of a header: */
126 if (kore_curl_http_get_header(client, "server", &header))
127 printf("got server header: '%s'\n", header);
128
129 /*
130 * Respond to our client with the status and body from
131 * the HTTP client request we did.
132 */
133 http_response(req, client->http.status, body, len);
134 }
135
136 /* Cleanup. */
137 kore_curl_cleanup(client);
138
139 /* State is now finished. */
140 return (HTTP_STATE_COMPLETE);
141 }