zephyr/subsys/net/lib/http/http.c
Jukka Rissanen 86689030e8 net: Clarify logging in networking code
Remove network specific default and max log level setting
and start to use the zephyr logging values for those.

Remove LOG_MODULE_REGISTER() from net_core.h and place the
calls into .c files. This is done in order to avoid weird
compiler errors in some cases and to make the code look similar
as other subsystems.

Fixes #11343
Fixes #11659

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
2018-12-07 12:00:04 +02:00

291 lines
5.4 KiB
C

/*
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(net_http, CONFIG_HTTP_LOG_LEVEL);
#include <zephyr.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <stdlib.h>
#include <version.h>
#include <misc/printk.h>
#include <net/net_core.h>
#include <net/net_ip.h>
#include <net/http.h>
int http_set_cb(struct http_ctx *ctx,
http_connect_cb_t connect_cb,
http_recv_cb_t recv_cb,
http_send_cb_t send_cb,
http_close_cb_t close_cb)
{
if (!ctx) {
return -EINVAL;
}
if (!ctx->is_init) {
return -ENOENT;
}
ctx->cb.connect = connect_cb;
ctx->cb.recv = recv_cb;
ctx->cb.send = send_cb;
ctx->cb.close = close_cb;
return 0;
}
int http_close(struct http_ctx *ctx)
{
if (!ctx) {
return -EINVAL;
}
if (!ctx->is_init) {
return -ENOENT;
}
http_send_flush(ctx, NULL);
if (ctx->pending) {
net_pkt_unref(ctx->pending);
ctx->pending = NULL;
}
#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_NET_DEBUG_HTTP_CONN)
if (!ctx->is_client) {
http_server_conn_del(ctx);
}
#endif
#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_WEBSOCKET)
if (ctx->websocket.pending) {
net_pkt_unref(ctx->websocket.pending);
ctx->websocket.pending = NULL;
}
ctx->websocket.data_waiting = 0;
#endif
return net_app_close(&ctx->app_ctx);
}
int http_release(struct http_ctx *ctx)
{
if (!ctx) {
return -EINVAL;
}
if (!ctx->is_init) {
return -ENOENT;
}
ctx->is_tls = false;
#if defined(CONFIG_HTTP_SERVER) && defined(CONFIG_NET_DEBUG_HTTP_CONN)
if (!ctx->is_client) {
http_server_conn_del(ctx);
http_server_disable(ctx);
}
#endif
if (ctx->pending) {
net_pkt_unref(ctx->pending);
ctx->pending = NULL;
}
ctx->is_init = false;
return net_app_release(&ctx->app_ctx);
}
int http_send_msg_raw(struct http_ctx *ctx, struct net_pkt *pkt,
void *user_send_data)
{
int ret;
NET_DBG("[%p] Sending %zd bytes data", ctx, net_pkt_get_len(pkt));
ret = net_app_send_pkt(&ctx->app_ctx, pkt, NULL, 0, 0,
user_send_data);
if (!ret) {
/* We must let the system to send the packet, otherwise TCP
* might timeout before the packet is actually sent. This is
* easily seen if the application calls this functions many
* times in a row.
*/
k_yield();
}
return ret;
}
static inline struct net_pkt *get_net_pkt(struct http_ctx *ctx,
const struct sockaddr *dst)
{
if (!dst) {
return net_app_get_net_pkt(&ctx->app_ctx, AF_UNSPEC,
ctx->timeout);
}
return net_app_get_net_pkt_with_dst(&ctx->app_ctx, dst, ctx->timeout);
}
int http_prepare_and_send(struct http_ctx *ctx,
const char *payload,
size_t payload_len,
const struct sockaddr *dst,
void *user_send_data)
{
size_t added;
int ret;
do {
if (!ctx->pending) {
ctx->pending = get_net_pkt(ctx, dst);
if (!ctx->pending) {
return -ENOMEM;
}
}
ret = net_pkt_append(ctx->pending, payload_len, payload,
ctx->timeout);
if (!ret || ret > payload_len) {
ret = -EINVAL;
goto error;
}
added = ret;
payload_len -= added;
if (payload_len) {
payload += added;
/* Not all data could be added, send what we have now
* and allocate new stuff to be sent.
*/
ret = http_send_flush(ctx, user_send_data);
if (ret < 0) {
goto error;
}
}
} while (payload_len);
return 0;
error:
if (ctx->pending) {
net_pkt_unref(ctx->pending);
ctx->pending = NULL;
}
return ret;
}
int http_send_flush(struct http_ctx *ctx, void *user_send_data)
{
int ret;
if (!ctx->pending) {
return 0;
}
ret = http_send_msg_raw(ctx, ctx->pending, user_send_data);
if (ret < 0) {
return ret;
}
ctx->pending = NULL;
return ret;
}
int http_send_chunk(struct http_ctx *ctx, const char *buf, size_t len,
const struct sockaddr *dst, void *user_send_data)
{
char chunk_header[16];
int ret;
if (!buf) {
len = 0;
}
snprintk(chunk_header, sizeof(chunk_header), "%x" HTTP_CRLF,
(unsigned int)len);
ret = http_prepare_and_send(ctx, chunk_header, strlen(chunk_header),
dst, user_send_data);
if (ret < 0) {
return ret;
}
if (len) {
ret = http_prepare_and_send(ctx, buf, len, dst, user_send_data);
if (ret < 0) {
return ret;
}
}
ret = http_prepare_and_send(ctx, HTTP_CRLF, sizeof(HTTP_CRLF) - 1, dst,
user_send_data);
if (ret < 0) {
return ret;
}
return 0;
}
static int _http_add_header(struct http_ctx *ctx, s32_t timeout,
const char *name, const char *value,
const struct sockaddr *dst,
void *user_send_data)
{
int ret;
ret = http_prepare_and_send(ctx, name, strlen(name), dst,
user_send_data);
if (value && ret >= 0) {
ret = http_prepare_and_send(ctx, ": ", strlen(": "), dst,
user_send_data);
if (ret < 0) {
goto out;
}
ret = http_prepare_and_send(ctx, value, strlen(value), dst,
user_send_data);
if (ret < 0) {
goto out;
}
ret = http_prepare_and_send(ctx, HTTP_CRLF, strlen(HTTP_CRLF),
dst, user_send_data);
if (ret < 0) {
goto out;
}
}
out:
return ret;
}
int http_add_header(struct http_ctx *ctx, const char *field,
const struct sockaddr *dst,
void *user_send_data)
{
return _http_add_header(ctx, ctx->timeout, field, NULL, dst,
user_send_data);
}
int http_add_header_field(struct http_ctx *ctx, const char *name,
const char *value,
const struct sockaddr *dst,
void *user_send_data)
{
return _http_add_header(ctx, ctx->timeout, name, value, dst,
user_send_data);
}