net: http: Add timeout to HTTP server response

Allow the caller to delay the closing of the HTTP connection
for a number of milliseconds. The purpose for this is that
the client can send still some data back to us for a short
period of time.

This is needed for example for Basic authentication so that
server is able to receive authentication values back.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-05-18 15:41:09 +03:00
commit 31faeca511
2 changed files with 86 additions and 5 deletions

View file

@ -567,6 +567,13 @@ struct http_server_ctx {
/** From which net_context the request came from */
struct net_context *net_ctx;
/** HTTP request timer. After sending a response to the
* client, it is possible to wait for any request back via
* the same socket. If no response is received, then this
* timeout is activated and connection is tore down.
*/
struct k_delayed_work timer;
/** HTTP parser */
struct http_parser parser;
@ -596,6 +603,9 @@ struct http_server_ctx {
/** URL's length */
u16_t url_len;
/** Has the request timer been cancelled. */
u8_t timer_cancelled;
} req;
#if defined(CONFIG_HTTPS)
@ -833,6 +843,25 @@ int http_server_del_default(struct http_server_urls *urls);
/**
* @brief Send HTTP response to client.
*
* @detail After sending a response, an optional timeout is started
* which will wait for any new requests from the peer.
*
* @param ctx HTTP context.
* @param http_header HTTP headers to send.
* @param html_payload HTML payload to send.
* @param timeout Timeout to wait until the connection is shutdown.
*
* @return 0 if ok, <0 if error.
*/
int http_response_wait(struct http_server_ctx *ctx, const char *http_header,
const char *html_payload, s32_t timeout);
/**
* @brief Send HTTP response to client.
*
* @detail The connection to peer is torn down right after the response
* is sent.
*
* @param ctx HTTP context.
* @param http_header HTTP headers to send.
* @param html_payload HTML payload to send.

View file

@ -107,17 +107,57 @@ static int http_add_chunk(struct net_pkt *pkt, s32_t timeout, const char *str)
return 0;
}
static void req_timer_cancel(struct http_server_ctx *ctx)
{
ctx->req.timer_cancelled = true;
k_delayed_work_cancel(&ctx->req.timer);
NET_DBG("Context %p request timer cancelled", ctx);
}
static void req_timeout(struct k_work *work)
{
struct http_server_ctx *ctx = CONTAINER_OF(work,
struct http_server_ctx,
req.timer);
if (ctx->req.timer_cancelled) {
return;
}
NET_DBG("Context %p request timeout", ctx);
net_context_unref(ctx->req.net_ctx);
}
static void pkt_sent(struct net_context *context,
int status,
void *token,
void *user_data)
{
/* We can just close the context after the packet is sent. */
net_context_unref(context);
s32_t timeout = POINTER_TO_INT(token);
struct http_server_ctx *ctx = user_data;
req_timer_cancel(ctx);
if (timeout == K_NO_WAIT) {
/* We can just close the context after the packet is sent. */
net_context_unref(context);
} else if (timeout > 0) {
NET_DBG("Context %p starting timer", ctx);
k_delayed_work_submit(&ctx->req.timer, timeout);
ctx->req.timer_cancelled = false;
}
/* Note that if the timeout is K_FOREVER, we do not close
* the connection.
*/
}
int http_response(struct http_server_ctx *ctx, const char *http_header,
const char *html_payload)
int http_response_wait(struct http_server_ctx *ctx, const char *http_header,
const char *html_payload, s32_t timeout)
{
struct net_pkt *pkt;
int ret = -EINVAL;
@ -147,7 +187,7 @@ int http_response(struct http_server_ctx *ctx, const char *http_header,
net_pkt_set_appdatalen(pkt, net_buf_frags_len(pkt->frags));
ret = ctx->send_data(pkt, pkt_sent, 0, NULL, ctx);
ret = ctx->send_data(pkt, pkt_sent, 0, INT_TO_POINTER(timeout), ctx);
if (ret != 0) {
goto exit_routine;
}
@ -162,6 +202,12 @@ exit_routine:
return ret;
}
int http_response(struct http_server_ctx *ctx, const char *http_header,
const char *html_payload)
{
return http_response_wait(ctx, http_header, html_payload, K_NO_WAIT);
}
int http_response_400(struct http_server_ctx *ctx, const char *html_payload)
{
return http_response(ctx, HTTP_STATUS_400_BR, html_payload);
@ -818,6 +864,8 @@ bool http_server_disable(struct http_server_ctx *http_ctx)
NET_ASSERT(http_ctx);
req_timer_cancel(http_ctx);
old = http_ctx->enabled;
http_ctx->enabled = false;
@ -865,6 +913,8 @@ int http_server_init(struct http_server_ctx *http_ctx,
http_ctx->recv_cb = http_recv;
http_ctx->send_data = net_context_send;
k_delayed_work_init(&http_ctx->req.timer, req_timeout);
parser_init(http_ctx);
return 0;
@ -1509,6 +1559,8 @@ int https_server_init(struct http_server_ctx *ctx,
ctx->send_data = https_send;
ctx->recv_cb = ssl_received;
k_delayed_work_init(&ctx->req.timer, req_timeout);
parser_init(ctx);
/* Then mbedtls specific initialization */