The "null terminator" for the chunked transfer encoding must be added only if the payload is present. Change-Id: Id325a660f060b3a3468bcca16a079def11b8c3ef Signed-off-by: Flavio Santes <flavio.santes@intel.com>
128 lines
2.5 KiB
C
128 lines
2.5 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <net/http.h>
|
|
#include <misc/printk.h>
|
|
#include <net/nbuf.h>
|
|
#include <net/net_context.h>
|
|
|
|
#define HTTP_STATUS_200_OK "HTTP/1.1 200 OK\r\n" \
|
|
"Content-Type: text/html\r\n" \
|
|
"Transfer-Encoding: chunked\r\n" \
|
|
"\r\n"
|
|
|
|
#define HTTP_STATUS_400_BR "HTTP/1.1 400 Bad Request\r\n" \
|
|
"\r\n"
|
|
|
|
#define HTTP_STATUS_403_FBD "HTTP/1.1 403 Forbidden\r\n" \
|
|
"\r\n"
|
|
|
|
#define HTTP_STATUS_404_NF "HTTP/1.1 404 Not Found\r\n" \
|
|
"\r\n"
|
|
|
|
static inline uint16_t http_strlen(const char *str)
|
|
{
|
|
if (str) {
|
|
return strlen(str);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int http_add_header(struct net_buf *tx, int32_t timeout, const char *str)
|
|
{
|
|
if (net_nbuf_append(tx, strlen(str), (uint8_t *)str, timeout)) {
|
|
return 0;
|
|
}
|
|
|
|
return -ENOMEM;
|
|
}
|
|
|
|
static int http_add_chunk(struct net_buf *tx, int32_t timeout, const char *str)
|
|
{
|
|
char chunk_header[16];
|
|
char *rn = "\r\n";
|
|
uint16_t str_len;
|
|
|
|
str_len = http_strlen(str);
|
|
|
|
snprintk(chunk_header, sizeof(chunk_header), "%x\r\n", str_len);
|
|
|
|
if (!net_nbuf_append(tx, strlen(chunk_header), chunk_header, timeout)) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (str_len > 0) {
|
|
if (!net_nbuf_append(tx, str_len, (uint8_t *)str, timeout)) {
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
if (!net_nbuf_append(tx, strlen(rn), rn, timeout)) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int http_response(struct http_server_ctx *ctx, const char *http_header,
|
|
const char *html_payload)
|
|
{
|
|
struct net_buf *tx;
|
|
int rc = -EINVAL;
|
|
|
|
tx = net_nbuf_get_tx(ctx->net_ctx, ctx->timeout);
|
|
if (!tx) {
|
|
goto exit_routine;
|
|
}
|
|
|
|
rc = http_add_header(tx, ctx->timeout, http_header);
|
|
if (rc != 0) {
|
|
goto exit_routine;
|
|
}
|
|
|
|
if (html_payload) {
|
|
rc = http_add_chunk(tx, ctx->timeout, html_payload);
|
|
if (rc != 0) {
|
|
goto exit_routine;
|
|
}
|
|
|
|
/* like EOF */
|
|
rc = http_add_chunk(tx, ctx->timeout, NULL);
|
|
if (rc != 0) {
|
|
goto exit_routine;
|
|
}
|
|
}
|
|
|
|
rc = net_context_send(tx, NULL, 0, NULL, NULL);
|
|
if (rc != 0) {
|
|
goto exit_routine;
|
|
}
|
|
|
|
tx = NULL;
|
|
|
|
exit_routine:
|
|
/* unref can handle NULL buffers, so we are covered */
|
|
net_nbuf_unref(tx);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int http_response_400(struct http_server_ctx *ctx, const char *html_payload)
|
|
{
|
|
return http_response(ctx, HTTP_STATUS_400_BR, html_payload);
|
|
}
|
|
|
|
int http_response_403(struct http_server_ctx *ctx, const char *html_payload)
|
|
{
|
|
return http_response(ctx, HTTP_STATUS_403_FBD, html_payload);
|
|
}
|
|
|
|
int http_response_404(struct http_server_ctx *ctx, const char *html_payload)
|
|
{
|
|
return http_response(ctx, HTTP_STATUS_404_NF, html_payload);
|
|
}
|