Add HTTP_CookieJar object to HTTP_Client

This commit is contained in:
2025-11-23 17:38:53 +01:00
parent 6cb5bdacd2
commit fc49b55225
2 changed files with 91 additions and 0 deletions
+69
View File
@@ -21,6 +21,8 @@ int http_client_init(HTTP_Client *client)
client->input_buffer_limit = 1<<20;
client->output_buffer_limit = 1<<20;
client->cookie_jar.count = 0;
client->num_conns = 0;
for (int i = 0; i < HTTP_CLIENT_CAPACITY; i++) {
client->conns[i].state = HTTP_CLIENT_CONN_FREE;
@@ -40,6 +42,9 @@ void http_client_free(HTTP_Client *client)
{
socket_manager_free(&client->sockets);
for (int i = 0; i < cookie_jar->count; i++)
free(client->cookie_jar.items[i].name.ptr);
for (int i = 0, j = 0; j < client->num_conns; i++) {
HTTP_ClientConn *conn = &client->conns[i];
if (conn->state == HTTP_CLIENT_CONN_FREE)
@@ -187,6 +192,9 @@ void http_request_builder_url(HTTP_RequestBuilder builder,
}
byte_queue_write(&conn->output, "\r\n", 2);
// TODO: Find all entries from the cookie jar that should
// be sent to this server and append headers for them
conn->state = HTTP_CLIENT_CONN_WAIT_HEADER;
}
@@ -298,6 +306,65 @@ int http_request_builder_send(HTTP_RequestBuilder builder)
return 0;
}
static void save_cookies(HTTP_CookieJar *cookie_jar, HTTP_Header *headers, int num_headers)
{
for (int i = 0; i < num_headers; i++) {
if (http_streqcase(headers[i].name, HTTP_STR("Set-Cookie"))) {
HTTP_SetCookie parsed;
if (http_parse_set_cookie(headers[i].value, &parsed) < 0)
continue; // Ignore invalid Set-Cookie headers
if (cookie_jar->count == HTTP_COOKIE_JAR_CAPACITY)
break;
HTTP_CookieJarEntry entry;
entry.name = parsed.name;
entry.value = parsed.value;
if (parsed.have_domain) {
// TODO: Check that the server can set a cookie for this domain
entry.domain = parsed.domain;
} else {
// TODO: Set the domain to the specific one used for this interaction
entry.domain = xxx;
}
if (parsed.have_path) {
entry.path = parsed.path;
} else {
// TODO: Set the path to the current endpoint minus one level
entry.path = xxx;
}
entry.secure = parsed.secure;
// Now copy all fields
char *p = malloc(entry.name.len + entry.value.len + entry.domain.len + entry.path.len);
if (p == NULL)
break;
memcpy(p, entry.name.ptr, entry.name.len);
entry.name.ptr = p;
p += entry.name.len;
memcpy(p, entry.value.ptr, entry.value.len);
entry.value.ptr = p;
p += entry.value.len;
memcpy(p, entry.domain.ptr, entry.domain.len);
entry.domain.ptr = p;
p += entry.domain.len;
memcpy(p, entry.path.ptr, entry.path.len);
entry.path.ptr = p;
p += entry.path.len;
cookie_jar->items[cookie_jar->count++] = entry;
}
}
}
// Look at the input buffer to see if a complete response
// was buffered. If it was, change the connection's status
// to COMPLETE and push it to the ready queue.
@@ -330,6 +397,8 @@ check_response_buffer(HTTP_Client *client, HTTP_ClientConn *conn)
conn->state = HTTP_CLIENT_CONN_COMPLETE;
conn->response.context = conn;
save_cookies(&client->cookie_jar, conn->response.headers, conn->response.num_headers);
// Push to the ready queue
assert(client->num_ready < HTTP_CLIENT_CAPACITY);
int tail = (client->ready_head + client->num_ready) % HTTP_CLIENT_CAPACITY;
+22
View File
@@ -5,6 +5,25 @@
#define HTTP_CLIENT_CAPACITY (1<<7)
#endif
#ifndef HTTP_COOKIE_JAR_CAPACITY
// Maximum number of cookies that can be associated to a
// single client.
#define HTTP_COOKIE_JAR_CAPACITY 128
#endif
typedef struct {
HTTP_String name;
HTTP_String value;
HTTP_String domain;
HTTP_String path;
bool secure;
} HTTP_CookieJarEntry;
typedef struct {
int count;
HTTP_CookieJarEntry items[HTTP_COOKIE_JAR_CAPACITY];
} HTTP_CookieJar;
typedef enum {
HTTP_CLIENT_CONN_FREE,
HTTP_CLIENT_CONN_WAIT_LINE,
@@ -54,6 +73,9 @@ struct HTTP_Client {
uint32_t input_buffer_limit;
uint32_t output_buffer_limit;
// List of cookies created during this session
HTTP_CookieJar cookie_jar;
// Array of connections. The counter contains the
// number of structs such that state!=FREE.
int num_conns;