Skip to content

Commit 4cc905c

Browse files
mrodgers-witekiocarlescufi
authored andcommitted
net: lib: http_server: allow application to send headers/response code
Allow the application to send headers and response codes from a dynamic resource callback by filling out a response context structure. This also allows simple requests to be completed in a single execution of the callback, by setting the final_chunk flag. Signed-off-by: Matt Rodgers <[email protected]>
1 parent f88784a commit 4cc905c

File tree

8 files changed

+443
-235
lines changed

8 files changed

+443
-235
lines changed

include/zephyr/net/http/server.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <zephyr/kernel.h>
2626
#include <zephyr/net/http/parser.h>
2727
#include <zephyr/net/http/hpack.h>
28+
#include <zephyr/net/http/status.h>
2829
#include <zephyr/net/socket.h>
2930
#include <zephyr/sys/iterable_sections.h>
3031

@@ -161,6 +162,22 @@ enum http_data_status {
161162
HTTP_SERVER_DATA_FINAL = 1,
162163
};
163164

165+
/** @brief HTTP header representation */
166+
struct http_header {
167+
const char *name; /**< Pointer to header name NULL-terminated string. */
168+
const char *value; /**< Pointer to header value NULL-terminated string. */
169+
};
170+
171+
/** @brief HTTP response context */
172+
struct http_response_ctx {
173+
enum http_status status; /** HTTP status code to include in response */
174+
const struct http_header *headers; /** Array of HTTP headers */
175+
size_t header_count; /** Length of headers array */
176+
const uint8_t *body; /** Pointer to body data */
177+
size_t body_len; /** Length of body data */
178+
bool final_chunk; /** Flag set to true when the application has no more data to send */
179+
};
180+
164181
/**
165182
* @typedef http_resource_dynamic_cb_t
166183
* @brief Callback used when data is received. Data to be sent to client
@@ -170,6 +187,7 @@ enum http_data_status {
170187
* @param status HTTP data status, indicate whether more data is expected or not.
171188
* @param data_buffer Data received.
172189
* @param data_len Amount of data received.
190+
* @param response_ctx
173191
* @param user_data User specified data.
174192
*
175193
* @return >0 amount of data to be sent to client, let server to call this
@@ -181,6 +199,7 @@ typedef int (*http_resource_dynamic_cb_t)(struct http_client_ctx *client,
181199
enum http_data_status status,
182200
uint8_t *data_buffer,
183201
size_t data_len,
202+
struct http_response_ctx *response_ctx,
184203
void *user_data);
185204

186205
/**
@@ -328,12 +347,6 @@ struct http2_frame {
328347
};
329348

330349
#if defined(CONFIG_HTTP_SERVER_CAPTURE_HEADERS)
331-
/** @brief HTTP header representation */
332-
struct http_header {
333-
const char *name; /**< Pointer to header name NULL-terminated string. */
334-
const char *value; /**< Pointer to header value NULL-terminated string. */
335-
};
336-
337350
/** @brief Status of captured headers */
338351
enum http_header_status {
339352
HTTP_HEADER_STATUS_OK, /**< All available headers were successfully captured. */

samples/net/sockets/http_server/src/main.c

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ static struct http_resource_detail_static main_js_gz_resource_detail = {
7272
};
7373

7474
static int echo_handler(struct http_client_ctx *client, enum http_data_status status,
75-
uint8_t *buffer, size_t len, void *user_data)
75+
uint8_t *buffer, size_t len, struct http_response_ctx *response_ctx,
76+
void *user_data)
7677
{
7778
#define MAX_TEMP_PRINT_LEN 32
7879
static char print_str[MAX_TEMP_PRINT_LEN];
@@ -98,10 +99,12 @@ static int echo_handler(struct http_client_ctx *client, enum http_data_status st
9899
processed = 0;
99100
}
100101

101-
/* This will echo data back to client as the buffer and recv_buffer
102-
* point to same area.
103-
*/
104-
return len;
102+
/* Echo data back to client */
103+
response_ctx->body = buffer;
104+
response_ctx->body_len = len;
105+
response_ctx->final_chunk = (status == HTTP_SERVER_DATA_FINAL);
106+
107+
return 0;
105108
}
106109

107110
static struct http_resource_detail_dynamic echo_resource_detail = {
@@ -116,42 +119,30 @@ static struct http_resource_detail_dynamic echo_resource_detail = {
116119
};
117120

118121
static int uptime_handler(struct http_client_ctx *client, enum http_data_status status,
119-
uint8_t *buffer, size_t len, void *user_data)
122+
uint8_t *buffer, size_t len, struct http_response_ctx *response_ctx,
123+
void *user_data)
120124
{
121-
static bool response_sent;
122-
123-
LOG_DBG("Uptime handler status %d, response_sent %d", status, response_sent);
124-
125-
switch (status) {
126-
case HTTP_SERVER_DATA_ABORTED: {
127-
response_sent = false;
128-
return 0;
129-
}
125+
int ret;
126+
static uint8_t uptime_buf[sizeof(STRINGIFY(INT64_MAX))];
130127

131-
case HTTP_SERVER_DATA_MORE: {
132-
/* A payload is not expected with the GET request. Ignore any data and wait until
133-
* final callback before sending response
134-
*/
135-
return 0;
136-
}
128+
LOG_DBG("Uptime handler status %d", status);
137129

138-
case HTTP_SERVER_DATA_FINAL: {
139-
if (response_sent) {
140-
/* Response already sent, return 0 to indicate to server that the callback
141-
* does not need to be called again.
142-
*/
143-
response_sent = false;
144-
return 0;
130+
/* A payload is not expected with the GET request. Ignore any data and wait until
131+
* final callback before sending response
132+
*/
133+
if (status == HTTP_SERVER_DATA_FINAL) {
134+
ret = snprintf(uptime_buf, sizeof(uptime_buf), "%" PRId64, k_uptime_get());
135+
if (ret < 0) {
136+
LOG_ERR("Failed to snprintf uptime, err %d", ret);
137+
return ret;
145138
}
146139

147-
response_sent = true;
148-
return snprintf(buffer, sizeof(uptime_buf), "%" PRId64, k_uptime_get());
149-
}
150-
default: {
151-
LOG_WRN("Unexpected status %d", status);
152-
return -1;
153-
}
140+
response_ctx->body = uptime_buf;
141+
response_ctx->body_len = ret;
142+
response_ctx->final_chunk = true;
154143
}
144+
145+
return 0;
155146
}
156147

157148
static struct http_resource_detail_dynamic uptime_resource_detail = {
@@ -189,7 +180,8 @@ static void parse_led_post(uint8_t *buf, size_t len)
189180
}
190181

191182
static int led_handler(struct http_client_ctx *client, enum http_data_status status,
192-
uint8_t *buffer, size_t len, void *user_data)
183+
uint8_t *buffer, size_t len, struct http_response_ctx *response_ctx,
184+
void *user_data)
193185
{
194186
static uint8_t post_payload_buf[32];
195187
static size_t cursor;

subsys/net/lib/http/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ config HTTP_SERVER_MAX_HEADER_LEN
107107
internal header processing, and only needs to be increased if the
108108
application wishes to access headers of a greater length.
109109

110+
config HTTP_SERVER_HTTP2_MAX_HEADER_FRAME_LEN
111+
int "Maximum HTTP/2 response header frame length"
112+
default 64
113+
range 64 2048
114+
help
115+
This setting determines the maximum length of an HTTP/2 header frame
116+
(applies to response headers only, not request headers). The default
117+
value is sufficient for the standard headers included with a response,
118+
and only needs to be increased if the application wishes to send
119+
additional response headers.
120+
110121
config HTTP_SERVER_CAPTURE_HEADERS
111122
bool "Allow capturing HTTP headers for application use"
112123
help

subsys/net/lib/http/headers/server_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ void http_server_get_content_type_from_extension(char *url, char *content_type,
4343
size_t content_type_size);
4444
int http_server_find_file(char *fname, size_t fname_size, size_t *file_size, bool *gzipped);
4545
void http_client_timer_restart(struct http_client_ctx *client);
46+
bool http_response_is_final(struct http_response_ctx *rsp, enum http_data_status status);
47+
bool http_response_is_provided(struct http_response_ctx *rsp);
4648

4749
/* TODO Could be static, but currently used in tests. */
4850
int parse_http_frame_header(struct http_client_ctx *client, const uint8_t *buffer,

subsys/net/lib/http/http_server_core.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ static void client_release_resources(struct http_client_ctx *client)
290290
{
291291
struct http_resource_detail *detail;
292292
struct http_resource_detail_dynamic *dynamic_detail;
293+
struct http_response_ctx response_ctx;
293294

294295
HTTP_SERVICE_FOREACH(service) {
295296
HTTP_SERVICE_FOREACH_RESOURCE(service, resource) {
@@ -315,8 +316,8 @@ static void client_release_resources(struct http_client_ctx *client)
315316
continue;
316317
}
317318

318-
dynamic_detail->cb(client, HTTP_SERVER_DATA_ABORTED,
319-
NULL, 0, dynamic_detail->user_data);
319+
dynamic_detail->cb(client, HTTP_SERVER_DATA_ABORTED, NULL, 0, &response_ctx,
320+
dynamic_detail->user_data);
320321
}
321322
}
322323
}
@@ -784,6 +785,29 @@ int http_server_sendall(struct http_client_ctx *client, const void *buf, size_t
784785
return 0;
785786
}
786787

788+
bool http_response_is_final(struct http_response_ctx *rsp, enum http_data_status status)
789+
{
790+
if (status != HTTP_SERVER_DATA_FINAL) {
791+
return false;
792+
}
793+
794+
if (rsp->final_chunk ||
795+
(rsp->status == 0 && rsp->header_count == 0 && rsp->body_len == 0)) {
796+
return true;
797+
}
798+
799+
return false;
800+
}
801+
802+
bool http_response_is_provided(struct http_response_ctx *rsp)
803+
{
804+
if (rsp->status != 0 || rsp->header_count > 0 || rsp->body_len > 0) {
805+
return true;
806+
}
807+
808+
return false;
809+
}
810+
787811
int http_server_start(void)
788812
{
789813
if (server_running) {

0 commit comments

Comments
 (0)