blob: d41d4ad7233c23ea1e0eb7178aeb10c37ff34840 [file] [log] [blame]
/** @file
* @brief HTTP compression handling functions
*
* Helper functions to handle compression formats
*/
/*
* Copyright (c) 2025 Endress+Hauser
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <zephyr/net/http/server.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/util.h>
#include "headers/server_internal.h"
static int http_compression_match(enum http_compression *compression, const char *text,
enum http_compression expected);
void http_compression_parse_accept_encoding(const char *accept_encoding, size_t len,
uint8_t *supported_compression)
{
enum http_compression detected_compression;
char strbuf[HTTP_COMPRESSION_MAX_STRING_LEN + 1] = {0};
const char *start = accept_encoding;
const char *end = NULL;
bool priority_string = false;
*supported_compression = HTTP_NONE;
for (size_t i = 0; i < len; i++) {
if (accept_encoding[i] == 0) {
break;
} else if (accept_encoding[i] == ' ') {
start = &accept_encoding[i + 1];
continue;
} else if (accept_encoding[i] == ';') {
end = &accept_encoding[i];
priority_string = true;
} else if (accept_encoding[i] == ',') {
if (!priority_string) {
end = &accept_encoding[i];
}
priority_string = false;
} else if (i + 1 == len) {
end = &accept_encoding[i + 1];
}
if (end == NULL) {
continue;
}
if (end - start > HTTP_COMPRESSION_MAX_STRING_LEN) {
end = NULL;
start = end + 1;
continue;
}
memcpy(strbuf, start, end - start);
strbuf[end - start] = 0;
if (http_compression_from_text(&detected_compression, strbuf) == 0) {
WRITE_BIT(*supported_compression, detected_compression, true);
}
end = NULL;
start = end + 1;
}
}
const char *http_compression_text(enum http_compression compression)
{
switch (compression) {
case HTTP_NONE:
return "";
case HTTP_GZIP:
return "gzip";
case HTTP_COMPRESS:
return "compress";
case HTTP_DEFLATE:
return "deflate";
case HTTP_BR:
return "br";
case HTTP_ZSTD:
return "zstd";
}
return "";
}
int http_compression_from_text(enum http_compression *compression, const char *text)
{
__ASSERT_NO_MSG(compression);
__ASSERT_NO_MSG(text);
for (enum http_compression i = 0; compression_value_is_valid(i); ++i) {
if (http_compression_match(compression, text, i) == 0) {
return 0;
}
}
return 1;
}
bool compression_value_is_valid(enum http_compression compression)
{
switch (compression) {
case HTTP_NONE:
case HTTP_GZIP:
case HTTP_COMPRESS:
case HTTP_DEFLATE:
case HTTP_BR:
case HTTP_ZSTD:
return true;
}
return false;
}
static int http_compression_match(enum http_compression *compression, const char *text,
enum http_compression expected)
{
__ASSERT_NO_MSG(compression);
__ASSERT_NO_MSG(text);
if (strcasecmp(http_compression_text(expected), text) == 0) {
*compression = expected;
return 0;
} else {
return 1;
}
}