zephyr/subsys/net/lib/http/http_server.c
Paul Sokolovsky 25307d5331 net: net_pkt_append: Refactor to return length of data actually added
For stream-based protocols (TCP), adding less data than requested
("short write") is generally not a problem - the rest of data can
be sent in the next packet. So, make net_pkt_append() return length
of written data instead of just bool flag, which makes it closer
to the behavior of POSIX send()/write() calls.

There're many users of older net_pkt_append() in the codebase
however, so net_pkt_append_all() convenience function is added which
keeps returning a boolean flag. All current users were converted to
this function, except for two:

samples/net/http_server/src/ssl_utils.c
samples/net/mbedtls_sslclient/src/tcp.c

Both are related to TLS and implement mbedTLS "tx callback", which
follows POSIX short-write semantics. Both cases also had a code to
workaround previous boolean-only behavior of net_pkt_append() - after
calling it, they measured length of the actual data added (but only
in case of successful return of net_pkt_append(), so that didn't
really help). So, these 2 cases are already improved.

Jira: ZEP-1984

Change-Id: Ibaf7c029b15e91b516d73dab3612eed190ee982b
Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
2017-04-28 15:01:09 +03:00

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/net_pkt.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 u16_t http_strlen(const char *str)
{
if (str) {
return strlen(str);
}
return 0;
}
static int http_add_header(struct net_pkt *tx, s32_t timeout, const char *str)
{
if (net_pkt_append_all(tx, strlen(str), (u8_t *)str, timeout)) {
return 0;
}
return -ENOMEM;
}
static int http_add_chunk(struct net_pkt *tx, s32_t timeout, const char *str)
{
char chunk_header[16];
char *rn = "\r\n";
u16_t str_len;
str_len = http_strlen(str);
snprintk(chunk_header, sizeof(chunk_header), "%x\r\n", str_len);
if (!net_pkt_append_all(tx, strlen(chunk_header), chunk_header,
timeout)) {
return -ENOMEM;
}
if (str_len > 0) {
if (!net_pkt_append_all(tx, str_len, (u8_t *)str, timeout)) {
return -ENOMEM;
}
}
if (!net_pkt_append_all(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_pkt *tx;
int rc = -EINVAL;
tx = net_pkt_get_tx(ctx->net_ctx, ctx->timeout);
if (!tx) {
return rc;
}
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:
net_pkt_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);
}