kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

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 }