739 lines
16 KiB
C
739 lines
16 KiB
C
/*
|
|
* Copyright (c) 2017 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#if defined(CONFIG_NET_DEBUG_HTTP)
|
|
#if defined(CONFIG_HTTPS)
|
|
#define SYS_LOG_DOMAIN "https/client"
|
|
#else
|
|
#define SYS_LOG_DOMAIN "http/client"
|
|
#endif
|
|
#define NET_SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG
|
|
#define NET_LOG_ENABLED 1
|
|
#endif
|
|
|
|
#include <zephyr.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <version.h>
|
|
|
|
#include <net/net_core.h>
|
|
#include <net/net_ip.h>
|
|
#include <net/http.h>
|
|
|
|
#include "../../ip/net_private.h"
|
|
|
|
#define BUF_ALLOC_TIMEOUT 100
|
|
|
|
#define RC_STR(rc) (rc == 0 ? "OK" : "ERROR")
|
|
|
|
#define HTTP_EOF "\r\n\r\n"
|
|
|
|
#define HTTP_HOST "Host"
|
|
#define HTTP_CONTENT_TYPE "Content-Type"
|
|
#define HTTP_CONTENT_LEN "Content-Length"
|
|
#define HTTP_CONT_LEN_SIZE 6
|
|
|
|
int client_reset(struct http_ctx *ctx)
|
|
{
|
|
http_parser_init(&ctx->http.parser, HTTP_RESPONSE);
|
|
|
|
memset(ctx->http.rsp.http_status, 0,
|
|
sizeof(ctx->http.rsp.http_status));
|
|
|
|
ctx->http.rsp.cl_present = 0;
|
|
ctx->http.rsp.content_length = 0;
|
|
ctx->http.rsp.processed = 0;
|
|
ctx->http.rsp.body_found = 0;
|
|
ctx->http.rsp.message_complete = 0;
|
|
ctx->http.rsp.body_start = NULL;
|
|
|
|
memset(ctx->http.rsp.response_buf, 0, ctx->http.rsp.response_buf_len);
|
|
ctx->http.rsp.data_len = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int http_request(struct http_ctx *ctx, struct http_request *req, s32_t timeout,
|
|
void *user_data)
|
|
{
|
|
const char *method = http_method_str(req->method);
|
|
int ret;
|
|
|
|
if (ctx->pending) {
|
|
net_pkt_unref(ctx->pending);
|
|
ctx->pending = NULL;
|
|
}
|
|
|
|
ret = http_add_header(ctx, method, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header(ctx, " ", user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header(ctx, req->url, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header(ctx, req->protocol, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header(ctx, HTTP_CRLF, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
if (req->host) {
|
|
ret = http_add_header_field(ctx, HTTP_HOST, req->host,
|
|
user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (req->header_fields) {
|
|
ret = http_add_header(ctx, req->header_fields, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (req->content_type_value) {
|
|
ret = http_add_header_field(ctx, HTTP_CONTENT_TYPE,
|
|
req->content_type_value,
|
|
user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (req->payload && req->payload_size) {
|
|
char content_len_str[HTTP_CONT_LEN_SIZE];
|
|
int i;
|
|
|
|
ret = snprintk(content_len_str, HTTP_CONT_LEN_SIZE,
|
|
"%u", req->payload_size);
|
|
if (ret <= 0 || ret >= HTTP_CONT_LEN_SIZE) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header_field(ctx, HTTP_CONTENT_LEN,
|
|
content_len_str, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = http_add_header(ctx, HTTP_CRLF, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < req->payload_size;) {
|
|
ret = http_send_chunk(ctx,
|
|
req->payload + i,
|
|
req->payload_size - i,
|
|
user_data);
|
|
if (ret < 0) {
|
|
NET_ERR("Cannot send data to peer (%d)", ret);
|
|
return ret;
|
|
}
|
|
|
|
i += ret;
|
|
}
|
|
} else {
|
|
ret = http_add_header(ctx, HTTP_EOF, user_data);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
http_send_flush(ctx, user_data);
|
|
|
|
out:
|
|
if (ctx->pending) {
|
|
net_pkt_unref(ctx->pending);
|
|
ctx->pending = NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if defined(CONFIG_NET_DEBUG_HTTP)
|
|
static void sprint_addr(char *buf, int len,
|
|
sa_family_t family,
|
|
struct sockaddr *addr)
|
|
{
|
|
if (family == AF_INET6) {
|
|
net_addr_ntop(AF_INET6, &net_sin6(addr)->sin6_addr, buf, len);
|
|
} else if (family == AF_INET) {
|
|
net_addr_ntop(AF_INET, &net_sin(addr)->sin_addr, buf, len);
|
|
} else {
|
|
NET_DBG("Invalid protocol family");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static inline void print_info(struct http_ctx *ctx,
|
|
enum http_method method)
|
|
{
|
|
#if defined(CONFIG_NET_DEBUG_HTTP)
|
|
char local[NET_IPV6_ADDR_LEN];
|
|
char remote[NET_IPV6_ADDR_LEN];
|
|
|
|
sprint_addr(local, NET_IPV6_ADDR_LEN,
|
|
ctx->app_ctx.default_ctx->local.sa_family,
|
|
&ctx->app_ctx.default_ctx->local);
|
|
|
|
sprint_addr(remote, NET_IPV6_ADDR_LEN,
|
|
ctx->app_ctx.default_ctx->remote.sa_family,
|
|
&ctx->app_ctx.default_ctx->remote);
|
|
|
|
NET_DBG("HTTP %s (%s) %s -> %s port %d",
|
|
http_method_str(method), ctx->http.req.host, local, remote,
|
|
ntohs(net_sin(&ctx->app_ctx.default_ctx->remote)->sin_port));
|
|
#endif
|
|
}
|
|
|
|
int http_client_send_req(struct http_ctx *ctx,
|
|
struct http_request *req,
|
|
http_response_cb_t cb,
|
|
u8_t *response_buf,
|
|
size_t response_buf_len,
|
|
void *user_data,
|
|
s32_t timeout)
|
|
{
|
|
int ret;
|
|
|
|
if (!response_buf || response_buf_len == 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ctx->http.rsp.response_buf = response_buf;
|
|
ctx->http.rsp.response_buf_len = response_buf_len;
|
|
|
|
client_reset(ctx);
|
|
|
|
if (!req->host) {
|
|
req->host = ctx->server;
|
|
}
|
|
|
|
ctx->http.req.host = req->host;
|
|
ctx->http.req.method = req->method;
|
|
ctx->http.req.user_data = user_data;
|
|
|
|
ctx->http.rsp.cb = cb;
|
|
|
|
ret = net_app_connect(&ctx->app_ctx, timeout);
|
|
if (ret < 0) {
|
|
NET_DBG("Cannot connect to server (%d)", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* We might wait longer than timeout if the first connection
|
|
* establishment takes long time (like with HTTPS)
|
|
*/
|
|
if (k_sem_take(&ctx->http.connect_wait, timeout)) {
|
|
NET_DBG("Connection timed out");
|
|
ret = -ETIMEDOUT;
|
|
goto out;
|
|
}
|
|
|
|
print_info(ctx, ctx->http.req.method);
|
|
|
|
ret = http_request(ctx, req, timeout, user_data);
|
|
if (ret < 0) {
|
|
NET_DBG("Send error (%d)", ret);
|
|
goto out;
|
|
}
|
|
|
|
if (timeout != 0 && k_sem_take(&ctx->http.req.wait, timeout)) {
|
|
ret = -ETIMEDOUT;
|
|
goto out;
|
|
}
|
|
|
|
if (timeout == 0) {
|
|
return -EINPROGRESS;
|
|
}
|
|
|
|
return 0;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void print_header_field(size_t len, const char *str)
|
|
{
|
|
#if defined(CONFIG_NET_DEBUG_HTTP)
|
|
#define MAX_OUTPUT_LEN 128
|
|
char output[MAX_OUTPUT_LEN];
|
|
|
|
/* The value of len does not count \0 so we need to increase it
|
|
* by one.
|
|
*/
|
|
if ((len + 1) > sizeof(output)) {
|
|
len = sizeof(output) - 1;
|
|
}
|
|
|
|
snprintk(output, len + 1, "%s", str);
|
|
|
|
NET_DBG("[%zd] %s", len, output);
|
|
#endif
|
|
}
|
|
|
|
static int on_url(struct http_parser *parser, const char *at, size_t length)
|
|
{
|
|
ARG_UNUSED(parser);
|
|
|
|
print_header_field(length, at);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_status(struct http_parser *parser, const char *at, size_t length)
|
|
{
|
|
u16_t len;
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
len = min(length, sizeof(ctx->http.rsp.http_status) - 1);
|
|
memcpy(ctx->http.rsp.http_status, at, len);
|
|
ctx->http.rsp.http_status[len] = 0;
|
|
|
|
NET_DBG("HTTP response status %s", ctx->http.rsp.http_status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_header_field(struct http_parser *parser, const char *at,
|
|
size_t length)
|
|
{
|
|
const char *content_len = HTTP_CONTENT_LEN;
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
u16_t len;
|
|
|
|
len = strlen(content_len);
|
|
if (length >= len && memcmp(at, content_len, len) == 0) {
|
|
ctx->http.rsp.cl_present = true;
|
|
}
|
|
|
|
print_header_field(length, at);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define MAX_NUM_DIGITS 16
|
|
|
|
static int on_header_value(struct http_parser *parser, const char *at,
|
|
size_t length)
|
|
{
|
|
char str[MAX_NUM_DIGITS];
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
if (ctx->http.rsp.cl_present) {
|
|
if (length <= MAX_NUM_DIGITS - 1) {
|
|
long int num;
|
|
|
|
memcpy(str, at, length);
|
|
str[length] = 0;
|
|
|
|
num = strtol(str, NULL, 10);
|
|
if (num == LONG_MIN || num == LONG_MAX) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
ctx->http.rsp.content_length = num;
|
|
}
|
|
|
|
ctx->http.rsp.cl_present = false;
|
|
}
|
|
|
|
print_header_field(length, at);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_body(struct http_parser *parser, const char *at, size_t length)
|
|
{
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
ctx->http.rsp.body_found = 1;
|
|
ctx->http.rsp.processed += length;
|
|
|
|
NET_DBG("Processed %zd length %zd", ctx->http.rsp.processed, length);
|
|
|
|
if (!ctx->http.rsp.body_start &&
|
|
(u8_t *)at != (u8_t *)ctx->http.rsp.response_buf) {
|
|
ctx->http.rsp.body_start = (u8_t *)at;
|
|
}
|
|
|
|
if (ctx->http.rsp.cb) {
|
|
NET_DBG("Calling callback for partitioned %zd len data",
|
|
ctx->http.rsp.data_len);
|
|
|
|
ctx->http.rsp.cb(ctx,
|
|
ctx->http.rsp.response_buf,
|
|
ctx->http.rsp.response_buf_len,
|
|
ctx->http.rsp.data_len,
|
|
HTTP_DATA_MORE,
|
|
ctx->http.req.user_data);
|
|
|
|
/* Re-use the result buffer and start to fill it again */
|
|
ctx->http.rsp.data_len = 0;
|
|
ctx->http.rsp.body_start = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_headers_complete(struct http_parser *parser)
|
|
{
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
if (parser->status_code >= 500 && parser->status_code < 600) {
|
|
NET_DBG("Status %d, skipping body", parser->status_code);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if ((ctx->http.req.method == HTTP_HEAD ||
|
|
ctx->http.req.method == HTTP_OPTIONS)
|
|
&& ctx->http.rsp.content_length > 0) {
|
|
NET_DBG("No body expected");
|
|
return 1;
|
|
}
|
|
|
|
NET_DBG("Headers complete");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_message_begin(struct http_parser *parser)
|
|
{
|
|
#if defined(CONFIG_NET_DEBUG_HTTP) && (CONFIG_SYS_LOG_NET_LEVEL > 2)
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
NET_DBG("-- HTTP %s response (headers) --",
|
|
http_method_str(ctx->http.req.method));
|
|
#else
|
|
ARG_UNUSED(parser);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int on_message_complete(struct http_parser *parser)
|
|
{
|
|
struct http_ctx *ctx = CONTAINER_OF(parser,
|
|
struct http_ctx,
|
|
http.parser);
|
|
|
|
NET_DBG("-- HTTP %s response (complete) --",
|
|
http_method_str(ctx->http.req.method));
|
|
|
|
if (ctx->http.rsp.cb) {
|
|
ctx->http.rsp.cb(ctx,
|
|
ctx->http.rsp.response_buf,
|
|
ctx->http.rsp.response_buf_len,
|
|
ctx->http.rsp.data_len,
|
|
HTTP_DATA_FINAL,
|
|
ctx->http.req.user_data);
|
|
}
|
|
|
|
ctx->http.rsp.message_complete = 1;
|
|
|
|
k_sem_give(&ctx->http.req.wait);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_chunk_header(struct http_parser *parser)
|
|
{
|
|
ARG_UNUSED(parser);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int on_chunk_complete(struct http_parser *parser)
|
|
{
|
|
ARG_UNUSED(parser);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void http_received(struct net_app_ctx *app_ctx,
|
|
struct net_pkt *pkt,
|
|
int status,
|
|
void *user_data)
|
|
{
|
|
struct http_ctx *ctx = user_data;
|
|
size_t start = ctx->http.rsp.data_len;
|
|
u16_t len = 0;
|
|
struct net_buf *frag, *prev_frag = NULL;
|
|
size_t recv_len;
|
|
size_t pkt_len;
|
|
|
|
recv_len = net_pkt_appdatalen(pkt);
|
|
if (recv_len == 0) {
|
|
/* don't print info about zero-length app data buffers */
|
|
goto quit;
|
|
}
|
|
|
|
if (status) {
|
|
NET_DBG("[%p] Status %d <%s>", ctx, status, RC_STR(status));
|
|
goto out;
|
|
}
|
|
|
|
/* Get rid of possible IP headers in the first fragment. */
|
|
frag = pkt->frags;
|
|
|
|
pkt_len = net_pkt_get_len(pkt);
|
|
|
|
if (recv_len < pkt_len) {
|
|
net_buf_pull(frag, pkt_len - recv_len);
|
|
net_pkt_set_appdata(pkt, frag->data);
|
|
}
|
|
|
|
NET_DBG("[%p] Received %zd bytes http data", ctx, recv_len);
|
|
|
|
while (frag) {
|
|
/* If this fragment cannot be copied to result buf,
|
|
* then parse what we have which will cause the callback to be
|
|
* called in function on_body(), and continue copying.
|
|
*/
|
|
if ((ctx->http.rsp.data_len + frag->len) >
|
|
ctx->http.rsp.response_buf_len) {
|
|
|
|
/* If the caller has not supplied a callback, then
|
|
* we cannot really continue if the request buffer
|
|
* overflows. Set the data_len to mark how many bytes
|
|
* should be needed in the response_buf.
|
|
*/
|
|
if (!ctx->cb.recv) {
|
|
ctx->http.rsp.data_len = recv_len;
|
|
goto out;
|
|
}
|
|
|
|
http_parser_execute(&ctx->http.parser,
|
|
&ctx->http.parser_settings,
|
|
ctx->http.rsp.response_buf + start,
|
|
len);
|
|
|
|
ctx->http.rsp.data_len = 0;
|
|
len = 0;
|
|
start = 0;
|
|
}
|
|
|
|
memcpy(ctx->http.rsp.response_buf + ctx->http.rsp.data_len,
|
|
frag->data, frag->len);
|
|
|
|
ctx->http.rsp.data_len += frag->len;
|
|
len += frag->len;
|
|
|
|
prev_frag = frag;
|
|
frag = frag->frags;
|
|
pkt->frags = frag;
|
|
|
|
prev_frag->frags = NULL;
|
|
net_pkt_frag_unref(prev_frag);
|
|
}
|
|
|
|
out:
|
|
http_parser_execute(&ctx->http.parser,
|
|
&ctx->http.parser_settings,
|
|
ctx->http.rsp.response_buf + start,
|
|
len);
|
|
|
|
net_pkt_unref(pkt);
|
|
return;
|
|
|
|
quit:
|
|
http_parser_init(&ctx->http.parser, HTTP_RESPONSE);
|
|
ctx->http.rsp.data_len = 0;
|
|
net_pkt_unref(pkt);
|
|
}
|
|
|
|
static void http_data_sent(struct net_app_ctx *app_ctx,
|
|
int status,
|
|
void *user_data_send,
|
|
void *user_data)
|
|
{
|
|
struct http_ctx *ctx = user_data;
|
|
|
|
if (!user_data_send) {
|
|
/* This is the token field in the net_context_send().
|
|
* If this is not set, then it is TCP ACK messages
|
|
* that are generated by the stack. We just ignore those.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
if (ctx->cb.send) {
|
|
ctx->cb.send(ctx, status, user_data_send, ctx->user_data);
|
|
}
|
|
}
|
|
|
|
static void http_connected(struct net_app_ctx *app_ctx,
|
|
int status,
|
|
void *user_data)
|
|
{
|
|
struct http_ctx *ctx = user_data;
|
|
|
|
if (status < 0) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->cb.connect) {
|
|
ctx->cb.connect(ctx, HTTP_CONNECTION, ctx->user_data);
|
|
}
|
|
|
|
if (ctx->is_connected) {
|
|
return;
|
|
}
|
|
|
|
ctx->is_connected = true;
|
|
|
|
k_sem_give(&ctx->http.connect_wait);
|
|
}
|
|
|
|
static void http_closed(struct net_app_ctx *app_ctx,
|
|
int status,
|
|
void *user_data)
|
|
{
|
|
struct http_ctx *ctx = user_data;
|
|
|
|
ARG_UNUSED(app_ctx);
|
|
ARG_UNUSED(status);
|
|
|
|
NET_DBG("[%p] connection closed", ctx);
|
|
|
|
ctx->is_connected = false;
|
|
|
|
if (ctx->cb.close) {
|
|
ctx->cb.close(ctx, 0, ctx->user_data);
|
|
}
|
|
}
|
|
|
|
int http_client_init(struct http_ctx *ctx,
|
|
const char *server,
|
|
u16_t server_port,
|
|
struct sockaddr *server_addr,
|
|
s32_t timeout)
|
|
{
|
|
int ret;
|
|
|
|
memset(ctx, 0, sizeof(*ctx));
|
|
|
|
ret = net_app_init_tcp_client(&ctx->app_ctx,
|
|
NULL, /* use any local address */
|
|
server_addr,
|
|
server,
|
|
server_port,
|
|
timeout,
|
|
ctx);
|
|
if (ret < 0) {
|
|
NET_DBG("Cannot init HTTP client (%d)", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = net_app_set_cb(&ctx->app_ctx, http_connected, http_received,
|
|
http_data_sent, http_closed);
|
|
if (ret < 0) {
|
|
NET_ERR("Cannot set callbacks (%d)", ret);
|
|
return ret;
|
|
}
|
|
|
|
ctx->http.parser_settings.on_body = on_body;
|
|
ctx->http.parser_settings.on_chunk_complete = on_chunk_complete;
|
|
ctx->http.parser_settings.on_chunk_header = on_chunk_header;
|
|
ctx->http.parser_settings.on_headers_complete = on_headers_complete;
|
|
ctx->http.parser_settings.on_header_field = on_header_field;
|
|
ctx->http.parser_settings.on_header_value = on_header_value;
|
|
ctx->http.parser_settings.on_message_begin = on_message_begin;
|
|
ctx->http.parser_settings.on_message_complete = on_message_complete;
|
|
ctx->http.parser_settings.on_status = on_status;
|
|
ctx->http.parser_settings.on_url = on_url;
|
|
|
|
k_sem_init(&ctx->http.req.wait, 0, 1);
|
|
k_sem_init(&ctx->http.connect_wait, 0, 1);
|
|
|
|
ctx->server = server;
|
|
ctx->is_init = true;
|
|
ctx->is_client = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int http_request_cancel(struct http_ctx *ctx)
|
|
{
|
|
if (!ctx->is_init) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!ctx->is_client) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
client_reset(ctx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_HTTPS)
|
|
int http_client_set_tls(struct http_ctx *ctx,
|
|
u8_t *request_buf,
|
|
size_t request_buf_len,
|
|
u8_t *personalization_data,
|
|
size_t personalization_data_len,
|
|
net_app_ca_cert_cb_t cert_cb,
|
|
const char *cert_host,
|
|
net_app_entropy_src_cb_t entropy_src_cb,
|
|
struct k_mem_pool *pool,
|
|
k_thread_stack_t *https_stack,
|
|
size_t https_stack_size)
|
|
{
|
|
int ret;
|
|
|
|
ret = net_app_client_tls(&ctx->app_ctx,
|
|
request_buf,
|
|
request_buf_len,
|
|
personalization_data,
|
|
personalization_data_len,
|
|
cert_cb,
|
|
cert_host,
|
|
entropy_src_cb,
|
|
pool,
|
|
https_stack,
|
|
https_stack_size);
|
|
if (ret < 0) {
|
|
NET_DBG("Cannot init TLS (%d)", ret);
|
|
return ret;
|
|
}
|
|
|
|
ctx->is_tls = true;
|
|
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_HTTPS */
|