Skip to content

Commit

Permalink
net: http_server: Add support for specifying Content-Type
Browse files Browse the repository at this point in the history
Allow user to specify the Content-Type header field for the
HTTP response.

Signed-off-by: Jukka Rissanen <[email protected]>
  • Loading branch information
jukkar authored and nashif committed May 15, 2024
1 parent eff80ae commit 6d129b2
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
3 changes: 3 additions & 0 deletions include/zephyr/net/http/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ struct http_resource_detail {

/** Content encoding of the resource. */
const char *content_encoding;

/** Content type of the resource. */
const char *content_type;
};

/** @cond INTERNAL_HIDDEN */
Expand Down
45 changes: 34 additions & 11 deletions subsys/net/lib/http/http_server_http1.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ static int handle_http1_static_resource(
{
#define RESPONSE_TEMPLATE \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"%s%s\r\n" \
"Content-Length: %d\r\n"

/* Add couple of bytes to total response */
char http_response[sizeof(RESPONSE_TEMPLATE) +
sizeof("Content-Encoding: 01234567890123456789\r\n") +
sizeof("Content-Type: \r\n") + HTTP_SERVER_MAX_CONTENT_TYPE_LEN +
sizeof("xxxx") +
sizeof("\r\n")];
const char *data;
Expand All @@ -51,10 +52,17 @@ static int handle_http1_static_resource(
static_detail->common.content_encoding[0] != '\0') {
snprintk(http_response, sizeof(http_response),
RESPONSE_TEMPLATE "Content-Encoding: %s\r\n\r\n",
"Content-Type: ",
static_detail->common.content_type == NULL ?
"text/html" : static_detail->common.content_type,
len, static_detail->common.content_encoding);
} else {
snprintk(http_response, sizeof(http_response),
RESPONSE_TEMPLATE "\r\n", len);
RESPONSE_TEMPLATE "\r\n",
"Content-Type: ",
static_detail->common.content_type == NULL ?
"text/html" : static_detail->common.content_type,
len);
}

ret = http_server_sendall(client, http_response,
Expand All @@ -74,12 +82,28 @@ static int handle_http1_static_resource(

#define RESPONSE_TEMPLATE_CHUNKED \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n" \
"%s%s\r\n" \
"Transfer-Encoding: chunked\r\n\r\n"

#define RESPONSE_TEMPLATE_DYNAMIC \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html\r\n\r\n" \
"%s%s\r\n\r\n"

#define SEND_RESPONSE(_template, _content_type) ({ \
char http_response[sizeof(_template) + \
sizeof("Content-Type: \r\n") + \
HTTP_SERVER_MAX_CONTENT_TYPE_LEN + \
sizeof("xxxx") + \
sizeof("\r\n")]; \
snprintk(http_response, sizeof(http_response), \
_template "\r\n", \
"Content-Type: ", \
_content_type == NULL ? \
"text/html" : _content_type); \
ret = http_server_sendall(client, http_response, \
strnlen(http_response, \
sizeof(_template) - 1)); \
ret; })

static int dynamic_get_req(struct http_resource_detail_dynamic *dynamic_detail,
struct http_client_ctx *client)
Expand All @@ -89,8 +113,8 @@ static int dynamic_get_req(struct http_resource_detail_dynamic *dynamic_detail,
char *ptr;
char tmp[TEMP_BUF_LEN];

ret = http_server_sendall(client, RESPONSE_TEMPLATE_CHUNKED,
sizeof(RESPONSE_TEMPLATE_CHUNKED) - 1);
ret = SEND_RESPONSE(RESPONSE_TEMPLATE_CHUNKED,
dynamic_detail->common.content_type);
if (ret < 0) {
return ret;
}
Expand Down Expand Up @@ -167,8 +191,8 @@ static int dynamic_post_req(struct http_resource_detail_dynamic *dynamic_detail,
}

if (!client->headers_sent) {
ret = http_server_sendall(client, RESPONSE_TEMPLATE_CHUNKED,
sizeof(RESPONSE_TEMPLATE_CHUNKED) - 1);
ret = SEND_RESPONSE(RESPONSE_TEMPLATE_CHUNKED,
dynamic_detail->common.content_type);
if (ret < 0) {
return ret;
}
Expand Down Expand Up @@ -266,9 +290,8 @@ static int handle_http1_dynamic_resource(
switch (client->method) {
case HTTP_HEAD:
if (user_method & BIT(HTTP_HEAD)) {
ret = http_server_sendall(
client, RESPONSE_TEMPLATE_DYNAMIC,
sizeof(RESPONSE_TEMPLATE_DYNAMIC) - 1);
ret = SEND_RESPONSE(RESPONSE_TEMPLATE_DYNAMIC,
dynamic_detail->common.content_type);
if (ret < 0) {
return ret;
}
Expand Down
21 changes: 15 additions & 6 deletions subsys/net/lib/http/http_server_http2.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ static void encode_frame_header(uint8_t *buf, uint32_t payload_len,

static int send_headers_frame(struct http_client_ctx *client,
enum http_status status, uint32_t stream_id,
const char *content_encoding, uint8_t flags)
struct http_resource_detail *detail_common,
uint8_t flags)
{
uint8_t headers_frame[64];
uint8_t status_str[4];
Expand All @@ -168,14 +169,22 @@ static int send_headers_frame(struct http_client_ctx *client,
return ret;
}

if (content_encoding != NULL) {
if (detail_common && detail_common->content_encoding != NULL) {
ret = add_header_field(client, &buf, &buflen, "content-encoding",
"gzip");
if (ret < 0) {
return ret;
}
}

if (detail_common && detail_common->content_type != NULL) {
ret = add_header_field(client, &buf, &buflen, "content-type",
detail_common->content_type);
if (ret < 0) {
return ret;
}
}

payload_len = sizeof(headers_frame) - buflen - HTTP_SERVER_FRAME_HEADER_SIZE;
flags |= HTTP_SERVER_FLAG_END_HEADERS;

Expand Down Expand Up @@ -349,7 +358,7 @@ static int handle_http2_static_resource(
content_len = static_detail->static_data_len;

ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier,
static_detail->common.content_encoding, 0);
&static_detail->common, 0);
if (ret < 0) {
LOG_DBG("Cannot write to socket (%d)", ret);
goto out;
Expand All @@ -375,7 +384,7 @@ static int dynamic_get_req_v2(struct http_resource_detail_dynamic *dynamic_detai
char *ptr;

ret = send_headers_frame(client, HTTP_200_OK, frame->stream_identifier,
dynamic_detail->common.content_encoding, 0);
&dynamic_detail->common, 0);
if (ret < 0) {
LOG_DBG("Cannot write to socket (%d)", ret);
return ret;
Expand Down Expand Up @@ -481,7 +490,7 @@ static int dynamic_post_req_v2(struct http_resource_detail_dynamic *dynamic_deta
if (!client->headers_sent) {
ret = send_headers_frame(
client, HTTP_200_OK, frame->stream_identifier,
dynamic_detail->common.content_encoding, 0);
&dynamic_detail->common, 0);
if (ret < 0) {
LOG_DBG("Cannot write to socket (%d)", ret);
return ret;
Expand Down Expand Up @@ -518,7 +527,7 @@ static int dynamic_post_req_v2(struct http_resource_detail_dynamic *dynamic_deta
*/
ret = send_headers_frame(
client, HTTP_200_OK, frame->stream_identifier,
dynamic_detail->common.content_encoding,
&dynamic_detail->common,
HTTP_SERVER_FLAG_END_STREAM);
if (ret < 0) {
LOG_DBG("Cannot write to socket (%d)", ret);
Expand Down

0 comments on commit 6d129b2

Please sign in to comment.