Add http_get, http_post, and the first client example

This commit is contained in:
2025-07-20 19:56:52 +02:00
parent 22e9dee5dc
commit f7892beb90
4 changed files with 150 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
#include <chttp.h>
// This is an example of how to use cHTTP to perform
// a basic GET request.
int main(void)
{
http_global_init();
// List any headers the request should hold
HTTP_String headers[] = {
HTTP_STR("User-Agent: cHTTP"),
};
// Request handle that will be necessary to
// free the request's resources when we are
// done with the result.
HTTP_RequestHandle handle;
// Perform the request. This will block the thread
// until an error occurs or the request completes.
HTTP_Response *res = http_get(
HTTP_STR("http://example.com/index.html"),
headers, HTTP_COUNT(headers),
&handle
);
// The http_get function returns NULL if the request
// couldn't be performed.
if (res == NULL) return -1;
// If the request succeded (note that responses with
// status 4xx and 5xx are not considered as errors in
// this context) the returned value holds the parsed
// version of the response and the output handle is set.
printf("status code: %d\n", res->status);
for (int i = 0; i < res->num_headers; i++) {
HTTP_Header header = res->headers[i];
printf(
"header %d: [%.*s] [%.*s]\n",
i,
HTTP_UNPACK(header.name),
HTTP_UNPACK(header.value)
);
}
printf("body: %.*s\n", res->body.len, res->body.ptr);
// When we are done reading from the response object
// we must free the request's resources.
http_request_free(handle);
// All done. Deinitialize the library.
http_global_free();
return 0;
}
+3
View File
@@ -47,6 +47,9 @@ HTTP_String http_trim(HTTP_String s);
// Returns the number of items of a static array. // Returns the number of items of a static array.
#define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0])) #define HTTP_COUNT(X) (sizeof(X) / sizeof((X)[0]))
// TODO: comment
#define HTTP_UNPACK(X) (X).len, (X).ptr
// Macro used to make invariants of the code more explicit. // Macro used to make invariants of the code more explicit.
// //
// Say you have some function that operates on two integers // Say you have some function that operates on two integers
+79
View File
@@ -371,3 +371,82 @@ void http_request_free(HTTP_RequestHandle handle)
conn->state = CLIENT_CONNECTION_FREE; conn->state = CLIENT_CONNECTION_FREE;
client->num_conns--; client->num_conns--;
} }
static HTTP_Client *default_client___; // TODO: deinitialize the default client when http_global_free is called
static HTTP_Client *get_default_client(void)
{
if (default_client___ == NULL)
default_client___ = http_client_init();
return default_client___;
}
HTTP_Response *http_get(HTTP_String url, HTTP_String *headers, int num_headers, HTTP_RequestHandle *phandle)
{
HTTP_Client *client = get_default_client();
if (client == NULL)
return NULL;
HTTP_RequestHandle handle;
int ret = http_client_request(client, &handle);
if (ret < 0)
return NULL;
http_request_line(handle, HTTP_METHOD_GET, url);
for (int i = 0; i < num_headers; i++)
http_request_header(handle, headers[i]);
http_request_submit(handle);
ret = http_client_wait(client, NULL); // TODO: it's assumed there is only one request pending
if (ret < 0) {
http_request_free(handle); // TODO: currently free only works on completed request handles
return NULL;
}
HTTP_Response *res = http_request_result(handle);
if (res == NULL) {
http_request_free(handle);
return NULL;
}
*phandle = handle;
return res;
}
HTTP_Response *http_post(HTTP_String url, HTTP_String *headers, int num_headers, HTTP_String body, HTTP_RequestHandle *phandle)
{
HTTP_Client *client = get_default_client();
if (client == NULL)
return NULL;
HTTP_RequestHandle handle;
int ret = http_client_request(client, &handle);
if (ret < 0)
return NULL;
http_request_line(handle, HTTP_METHOD_GET, url);
for (int i = 0; i < num_headers; i++)
http_request_header(handle, headers[i]);
http_request_body(handle, body);
http_request_submit(handle);
ret = http_client_wait(client, NULL); // TODO: it's assumed there is only one request pending
if (ret < 0) {
http_request_free(handle); // TODO: currently free only works on completed request handles
return NULL;
}
HTTP_Response *res = http_request_result(handle);
if (res == NULL) {
http_request_free(handle);
return NULL;
}
*phandle = handle;
return res;
}
+10
View File
@@ -94,4 +94,14 @@ HTTP_Response *http_request_result(HTTP_RequestHandle handle);
// TODO: allow aborting pending requests // TODO: allow aborting pending requests
void http_request_free(HTTP_RequestHandle handle); void http_request_free(HTTP_RequestHandle handle);
// TODO: comment
HTTP_Response *http_get(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_RequestHandle *phandle);
// TODO: comment
HTTP_Response *http_post(HTTP_String url,
HTTP_String *headers, int num_headers,
HTTP_String body, HTTP_RequestHandle *phandle);
#endif // CLIENT_INCLUDED #endif // CLIENT_INCLUDED