diff --git a/include/net/http.h b/include/net/http.h index b6b0072e37d..373caf75cd7 100644 --- a/include/net/http.h +++ b/include/net/http.h @@ -114,12 +114,14 @@ enum http_verdict { * * @param ctx The context to use. * @param type Connection type (websocket or HTTP) + * @param dst Remote socket address * * @return HTTP_VERDICT_DROP if connection is to be dropped, * HTTP_VERDICT_ACCEPT if the application wants to accept the unknown URL. */ typedef enum http_verdict (*http_url_cb_t)(struct http_ctx *ctx, - enum http_connection_type type); + enum http_connection_type type, + const struct sockaddr *dst); /* Collection of URLs that this server will handle */ struct http_server_urls { @@ -149,12 +151,14 @@ struct http_server_urls { * pkt parameter is set to NULL. * @param flags Flags related to http. For example contains information * if the data is text or binary etc. + * @param dst Remote socket address from where HTTP packet is received. * @param user_data The user data given in init call. */ typedef void (*http_recv_cb_t)(struct http_ctx *ctx, struct net_pkt *pkt, int status, u32_t flags, + const struct sockaddr *dst, void *user_data); /** @@ -166,10 +170,12 @@ typedef void (*http_recv_cb_t)(struct http_ctx *ctx, * * @param ctx The context to use. * @param type Connection type (websocket or HTTP) + * @param dst Remote socket address where the connection is established. * @param user_data The user data given in init call. */ typedef void (*http_connect_cb_t)(struct http_ctx *ctx, enum http_connection_type type, + const struct sockaddr *dst, void *user_data); /** @@ -445,12 +451,6 @@ struct http_ctx { /** Network buffer allocation timeout */ s32_t timeout; - /** Websocket endpoint address */ - struct sockaddr *addr; - - /** Websocket endpoint port */ - u16_t port; - /** Is this context setup or not */ u8_t is_init : 1; @@ -906,13 +906,16 @@ int http_send_msg_raw(struct http_ctx *ctx, struct net_pkt *pkt, * @param ctx Http context. * @param payload Application data to send * @param payload_len Length of application data + * @param dst Remote socket address * @param user_send_data User specific data to this connection. This is passed * as a parameter to sent cb after the packet has been sent. * * @return 0 if ok, <0 if error. */ int http_prepare_and_send(struct http_ctx *ctx, const char *payload, - size_t payload_len, void *user_send_data); + size_t payload_len, + const struct sockaddr *dst, + void *user_send_data); /** * @brief Send HTTP data chunk to peer. @@ -920,13 +923,16 @@ int http_prepare_and_send(struct http_ctx *ctx, const char *payload, * @param ctx Http context. * @param payload Application data to send * @param payload_len Length of application data + * @param dst Remote socket address * @param user_send_data User specific data to this connection. This is passed * as a parameter to sent cb after the packet has been sent. * * @return 0 if ok, <0 if error. */ int http_send_chunk(struct http_ctx *ctx, const char *payload, - size_t payload_len, void *user_send_data); + size_t payload_len, + const struct sockaddr *dst, + void *user_send_data); /** * @brief Send any pending data immediately. @@ -946,11 +952,13 @@ int http_send_flush(struct http_ctx *ctx, void *user_send_data); * @param code HTTP error code * @param html_payload Extra payload, can be null * @param html_len Payload length + * @param dst Remote socket address * * @return 0 if ok, <0 if error. */ -int http_send_error(struct http_ctx *ctx, int code, u8_t *html_payload, - size_t html_len); +int http_send_error(struct http_ctx *ctx, int code, + u8_t *html_payload, size_t html_len, + const struct sockaddr *dst); /** * @brief Add HTTP header field to the message. @@ -961,6 +969,7 @@ int http_send_error(struct http_ctx *ctx, int code, u8_t *html_payload, * * @param ctx Http context. * @param http_header_field All or part of HTTP header to be added. + * @param dst Remote socket address. * @param user_send_data User data value that is used in send callback. * Note that this value is only used if this function call causes a HTTP * message to be sent. @@ -968,6 +977,7 @@ int http_send_error(struct http_ctx *ctx, int code, u8_t *html_payload, * @return <0 if error, other value tells how many bytes were added */ int http_add_header(struct http_ctx *ctx, const char *http_header_field, + const struct sockaddr *dst, void *user_send_data); /** @@ -980,6 +990,7 @@ int http_add_header(struct http_ctx *ctx, const char *http_header_field, * @param ctx Http context. * @param name Name of the header field * @param value Value of the header field + * @param dst Remote socket address * @param user_send_data User data value that is used in send callback. * Note that this value is only used if this function call causes a HTTP * message to be sent. @@ -987,7 +998,9 @@ int http_add_header(struct http_ctx *ctx, const char *http_header_field, * @return <0 if error, other value tells how many bytes were added */ int http_add_header_field(struct http_ctx *ctx, const char *name, - const char *value, void *user_send_data); + const char *value, + const struct sockaddr *dst, + void *user_send_data); /** * @brief Find a handler function for a given URL. diff --git a/include/net/http_parser.h b/include/net/http_parser.h index d0b43301b7f..922a37d913d 100644 --- a/include/net/http_parser.h +++ b/include/net/http_parser.h @@ -211,6 +211,11 @@ struct http_parser { void *data; /* A pointer to get hook to the "connection" or "socket" * object */ + + /* Remote socket address of http connection, where parser can initiate + * replies if necessary. + */ + const struct sockaddr *addr; }; diff --git a/samples/net/http_client/prj.conf b/samples/net/http_client/prj.conf index d814f54ee60..97c067a512a 100644 --- a/samples/net/http_client/prj.conf +++ b/samples/net/http_client/prj.conf @@ -17,7 +17,7 @@ CONFIG_NET_MAX_CONTEXTS=16 CONFIG_SYS_LOG_SHOW_COLOR=y CONFIG_SYS_LOG_NET_LEVEL=4 -CONFIG_NET_DEBUG_HTTP=y +CONFIG_NET_DEBUG_HTTP=n CONFIG_NET_DEBUG_APP=n CONFIG_NET_DEBUG_CORE=n CONFIG_NET_DEBUG_IF=n @@ -50,3 +50,5 @@ CONFIG_NET_STATISTICS=y CONFIG_NET_MGMT=y CONFIG_NET_MGMT_EVENT=y + +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/samples/net/http_client/src/main.c b/samples/net/http_client/src/main.c index cf065013b5f..2ecc8cb8215 100644 --- a/samples/net/http_client/src/main.c +++ b/samples/net/http_client/src/main.c @@ -424,6 +424,7 @@ static void http_received(struct http_ctx *ctx, struct net_pkt *pkt, int status, u32_t flags, + const struct sockaddr *dst, void *user_data) { if (!status) { diff --git a/samples/net/http_server/src/main.c b/samples/net/http_server/src/main.c index 32d3fa13f8c..c5a1a6009c3 100644 --- a/samples/net/http_server/src/main.c +++ b/samples/net/http_server/src/main.c @@ -108,22 +108,22 @@ void panic(const char *msg) static int http_response(struct http_ctx *ctx, const char *header, const char *payload, size_t payload_len, - char *str) + char *str, const struct sockaddr *dst) { int ret; - ret = http_add_header(ctx, header, str); + ret = http_add_header(ctx, header, dst, str); if (ret < 0) { NET_ERR("Cannot add HTTP header (%d)", ret); return ret; } - ret = http_add_header(ctx, HTTP_CRLF, str); + ret = http_add_header(ctx, HTTP_CRLF, dst, str); if (ret < 0) { return ret; } - ret = http_send_chunk(ctx, payload, payload_len, str); + ret = http_send_chunk(ctx, payload, payload_len, dst, str); if (ret < 0) { NET_ERR("Cannot send data to peer (%d)", ret); return ret; @@ -132,7 +132,8 @@ static int http_response(struct http_ctx *ctx, const char *header, return http_send_flush(ctx, str); } -static int http_response_soft_404(struct http_ctx *ctx) +static int http_response_soft_404(struct http_ctx *ctx, + const struct sockaddr *dst) { static const char *not_found = HTML_HEADER @@ -140,7 +141,7 @@ static int http_response_soft_404(struct http_ctx *ctx) HTML_FOOTER; return http_response(ctx, HTTP_STATUS_200_OK, not_found, - strlen(not_found), "Error"); + strlen(not_found), "Error", dst); } /* Prints the received HTTP header fields as an HTML list */ @@ -202,7 +203,8 @@ static void print_http_headers(struct http_ctx *ctx, "

Server: %s

"HTML_FOOTER, CONFIG_ARCH); } -int http_serve_headers(struct http_ctx *ctx) +int http_serve_headers(struct http_ctx *ctx, + const struct sockaddr *dst) { #define HTTP_MAX_BODY_STR_SIZE 1024 static char html_body[HTTP_MAX_BODY_STR_SIZE]; @@ -210,10 +212,11 @@ int http_serve_headers(struct http_ctx *ctx) print_http_headers(ctx, html_body, HTTP_MAX_BODY_STR_SIZE); return http_response(ctx, HTTP_STATUS_200_OK, html_body, - strlen(html_body), "Headers"); + strlen(html_body), "Headers", dst); } -static int http_serve_index_html(struct http_ctx *ctx) +static int http_serve_index_html(struct http_ctx *ctx, + const struct sockaddr *dst) { static const char index_html[] = { #include "index.html.inc" @@ -223,11 +226,12 @@ static int http_serve_index_html(struct http_ctx *ctx) sizeof(index_html)); return http_response(ctx, HTTP_STATUS_200_OK, index_html, - sizeof(index_html), "Index"); + sizeof(index_html), "Index", dst); } static void http_connected(struct http_ctx *ctx, enum http_connection_type type, + const struct sockaddr *dst, void *user_data) { char url[32]; @@ -242,21 +246,21 @@ static void http_connected(struct http_ctx *ctx, if (type == HTTP_CONNECTION) { if (strncmp(ctx->http.url, "/", ctx->http.url_len) == 0) { - http_serve_index_html(ctx); + http_serve_index_html(ctx, dst); http_close(ctx); return; } if (strncmp(ctx->http.url, "/index.html", ctx->http.url_len) == 0) { - http_serve_index_html(ctx); + http_serve_index_html(ctx, dst); http_close(ctx); return; } if (strncmp(ctx->http.url, "/headers", ctx->http.url_len) == 0) { - http_serve_headers(ctx); + http_serve_headers(ctx, dst); http_close(ctx); return; } @@ -265,7 +269,7 @@ static void http_connected(struct http_ctx *ctx, /* Give 404 error for all the other URLs we do not want to handle * right now. */ - http_response_soft_404(ctx); + http_response_soft_404(ctx, dst); http_close(ctx); } @@ -273,6 +277,7 @@ static void http_received(struct http_ctx *ctx, struct net_pkt *pkt, int status, u32_t flags, + const struct sockaddr *dst, void *user_data) { if (!status) { @@ -317,14 +322,15 @@ static const char *get_string(int str_len, const char *str) } static enum http_verdict default_handler(struct http_ctx *ctx, - enum http_connection_type type) + enum http_connection_type type, + const struct sockaddr *dst) { NET_DBG("No handler for %s URL %s", type == HTTP_CONNECTION ? "HTTP" : "WS", get_string(ctx->http.url_len, ctx->http.url)); if (type == HTTP_CONNECTION) { - http_response_soft_404(ctx); + http_response_soft_404(ctx, dst); } return HTTP_VERDICT_DROP; diff --git a/subsys/net/lib/http/http.c b/subsys/net/lib/http/http.c index 7bb6db717c9..e63cf259ae3 100644 --- a/subsys/net/lib/http/http.c +++ b/subsys/net/lib/http/http.c @@ -119,9 +119,21 @@ int http_send_msg_raw(struct http_ctx *ctx, struct net_pkt *pkt, 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; @@ -129,9 +141,7 @@ int http_prepare_and_send(struct http_ctx *ctx, do { if (!ctx->pending) { - ctx->pending = net_app_get_net_pkt(&ctx->app_ctx, - AF_UNSPEC, - ctx->timeout); + ctx->pending = get_net_pkt(ctx, dst); if (!ctx->pending) { return -ENOMEM; } @@ -189,7 +199,7 @@ int http_send_flush(struct http_ctx *ctx, void *user_send_data) } int http_send_chunk(struct http_ctx *ctx, const char *buf, size_t len, - void *user_send_data) + const struct sockaddr *dst, void *user_send_data) { char chunk_header[16]; int ret; @@ -202,19 +212,19 @@ int http_send_chunk(struct http_ctx *ctx, const char *buf, size_t len, (unsigned int)len); ret = http_prepare_and_send(ctx, chunk_header, strlen(chunk_header), - user_send_data); + dst, user_send_data); if (ret < 0) { return ret; } if (len) { - ret = http_prepare_and_send(ctx, buf, len, user_send_data); + 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), + ret = http_prepare_and_send(ctx, HTTP_CRLF, sizeof(HTTP_CRLF), dst, user_send_data); if (ret < 0) { return ret; @@ -225,26 +235,28 @@ int http_send_chunk(struct http_ctx *ctx, const char *buf, size_t len, 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), user_send_data); + ret = http_prepare_and_send(ctx, name, strlen(name), dst, + user_send_data); if (value && ret >= 0) { - ret = http_prepare_and_send(ctx, ": ", strlen(": "), + 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), + 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), - user_send_data); + dst, user_send_data); if (ret < 0) { goto out; } @@ -255,13 +267,18 @@ out: } 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, 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, void *user_send_data) + const char *value, + const struct sockaddr *dst, + void *user_send_data) { - return _http_add_header(ctx, ctx->timeout, name, value, user_send_data); + return _http_add_header(ctx, ctx->timeout, name, value, dst, + user_send_data); } diff --git a/subsys/net/lib/http/http_client.c b/subsys/net/lib/http/http_client.c index 12b69f8eade..61a4063887f 100644 --- a/subsys/net/lib/http/http_client.c +++ b/subsys/net/lib/http/http_client.c @@ -72,41 +72,41 @@ int http_request(struct http_ctx *ctx, struct http_request *req, s32_t timeout, ctx->pending = NULL; } - ret = http_add_header(ctx, method, user_data); + ret = http_add_header(ctx, method, NULL, user_data); if (ret < 0) { goto out; } - ret = http_add_header(ctx, " ", user_data); + ret = http_add_header(ctx, " ", NULL, user_data); if (ret < 0) { goto out; } - ret = http_add_header(ctx, req->url, user_data); + ret = http_add_header(ctx, req->url, NULL, user_data); if (ret < 0) { goto out; } - ret = http_add_header(ctx, req->protocol, user_data); + ret = http_add_header(ctx, req->protocol, NULL, user_data); if (ret < 0) { goto out; } - ret = http_add_header(ctx, HTTP_CRLF, user_data); + ret = http_add_header(ctx, HTTP_CRLF, NULL, user_data); if (ret < 0) { goto out; } if (req->host) { ret = http_add_header_field(ctx, HTTP_HOST, req->host, - user_data); + NULL, user_data); if (ret < 0) { goto out; } } if (req->header_fields) { - ret = http_add_header(ctx, req->header_fields, user_data); + ret = http_add_header(ctx, req->header_fields, NULL, user_data); if (ret < 0) { goto out; } @@ -115,7 +115,7 @@ int http_request(struct http_ctx *ctx, struct http_request *req, s32_t timeout, if (req->content_type_value) { ret = http_add_header_field(ctx, HTTP_CONTENT_TYPE, req->content_type_value, - user_data); + NULL, user_data); if (ret < 0) { goto out; } @@ -132,23 +132,25 @@ int http_request(struct http_ctx *ctx, struct http_request *req, s32_t timeout, } ret = http_add_header_field(ctx, HTTP_CONTENT_LEN, - content_len_str, user_data); + content_len_str, + NULL, user_data); if (ret < 0) { goto out; } - ret = http_add_header(ctx, HTTP_CRLF, user_data); + ret = http_add_header(ctx, HTTP_CRLF, NULL, user_data); if (ret < 0) { goto out; } ret = http_prepare_and_send(ctx, req->payload, - req->payload_size, user_data); + req->payload_size, + NULL, user_data); if (ret < 0) { goto out; } } else { - ret = http_add_header(ctx, HTTP_EOF, user_data); + ret = http_add_header(ctx, HTTP_EOF, NULL, user_data); if (ret < 0) { goto out; } @@ -606,8 +608,10 @@ static void http_connected(struct net_app_ctx *app_ctx, return; } - if (ctx->cb.connect) { - ctx->cb.connect(ctx, HTTP_CONNECTION, ctx->user_data); + if (ctx->cb.connect && app_ctx->default_ctx) { + ctx->cb.connect(ctx, HTTP_CONNECTION, + &app_ctx->default_ctx->remote, + ctx->user_data); } if (ctx->is_connected) { diff --git a/subsys/net/lib/http/http_server.c b/subsys/net/lib/http/http_server.c index e080b9e9ba3..e167bba1423 100644 --- a/subsys/net/lib/http/http_server.c +++ b/subsys/net/lib/http/http_server.c @@ -168,7 +168,8 @@ static void http_data_sent(struct net_app_ctx *app_ctx, } int http_send_error(struct http_ctx *ctx, int code, - u8_t *html_payload, size_t html_len) + u8_t *html_payload, size_t html_len, + const struct sockaddr *dst) { const char *msg; int ret; @@ -187,13 +188,14 @@ int http_send_error(struct http_ctx *ctx, int code, break; } - ret = http_add_header(ctx, msg, NULL); + ret = http_add_header(ctx, msg, dst, NULL); if (ret < 0) { goto quit; } if (html_payload) { - ret = http_prepare_and_send(ctx, html_payload, html_len, NULL); + ret = http_prepare_and_send(ctx, html_payload, html_len, dst, + NULL); if (ret < 0) { goto quit; } @@ -297,7 +299,8 @@ static struct net_context *get_server_ctx(struct net_app_ctx *ctx, static inline void new_client(struct http_ctx *ctx, enum http_connection_type type, - struct net_app_ctx *app_ctx) + struct net_app_ctx *app_ctx, + const struct sockaddr *dst) { #if defined(CONFIG_NET_DEBUG_HTTP) && (CONFIG_SYS_LOG_NET_LEVEL > 2) #if defined(CONFIG_NET_IPV6) @@ -311,7 +314,7 @@ static inline void new_client(struct http_ctx *ctx, struct net_context *net_ctx; const char *type_str = "HTTP"; - net_ctx = get_server_ctx(app_ctx, ctx->addr); + net_ctx = get_server_ctx(app_ctx, dst); if (net_ctx) { NET_INFO("[%p] %s connection from %s (%p)", ctx, type_str, sprint_ipaddr(buf, sizeof(buf), &net_ctx->remote), @@ -323,12 +326,13 @@ static inline void new_client(struct http_ctx *ctx, } static void url_connected(struct http_ctx *ctx, - enum http_connection_type type) + enum http_connection_type type, + const struct sockaddr *dst) { - new_client(ctx, type, &ctx->app_ctx); + new_client(ctx, type, &ctx->app_ctx, dst); if (ctx->cb.connect) { - ctx->cb.connect(ctx, type, ctx->user_data); + ctx->cb.connect(ctx, type, dst, ctx->user_data); } } @@ -471,7 +475,8 @@ struct http_root_url *http_url_find(struct http_ctx *ctx, return NULL; } -static int http_process_recv(struct http_ctx *ctx) +static int http_process_recv(struct http_ctx *ctx, + const struct sockaddr *dst) { struct http_root_url *root_url; int ret; @@ -493,7 +498,8 @@ static int http_process_recv(struct http_ctx *ctx) if (ctx->http.urls->default_cb) { ret = ctx->http.urls->default_cb(ctx, - HTTP_CONNECTION); + HTTP_CONNECTION, + dst); if (ret != HTTP_VERDICT_ACCEPT) { ret = -ECONNREFUSED; goto out; @@ -502,7 +508,7 @@ static int http_process_recv(struct http_ctx *ctx) } http_change_state(ctx, HTTP_STATE_OPEN); - url_connected(ctx, HTTP_CONNECTION); + url_connected(ctx, HTTP_CONNECTION, dst); ret = 0; @@ -538,6 +544,7 @@ static void http_received(struct net_app_ctx *app_ctx, struct http_ctx *ctx = user_data; size_t start = ctx->http.data_len; u16_t len = 0; + const struct sockaddr *dst = NULL; struct net_buf *frag; int parsed_len; size_t recv_len; @@ -566,6 +573,11 @@ static void http_received(struct net_app_ctx *app_ctx, NET_DBG("[%p] Received %zd bytes http data", ctx, recv_len); + if (net_pkt_context(pkt)) { + ctx->http.parser.addr = &net_pkt_context(pkt)->remote; + dst = &net_pkt_context(pkt)->remote; + } + if (ctx->state == HTTP_STATE_OPEN) { /* We have active websocket session and there is no longer * any HTTP traffic in the connection. Give the data to @@ -591,7 +603,7 @@ static void http_received(struct net_app_ctx *app_ctx, * overflows. Set the data_len to mark how many bytes * should be needed in the response_buf. */ - if (http_process_recv(ctx) < 0) { + if (http_process_recv(ctx, dst) < 0) { ctx->http.data_len = recv_len; goto out; } @@ -635,13 +647,13 @@ fail: } if (ctx->http.parser.http_errno != HPE_OK) { - http_send_error(ctx, 400, NULL, 0); + http_send_error(ctx, 400, NULL, 0, dst); } else { if (ctx->state == HTTP_STATE_HEADER_RECEIVED) { goto http_ready; } - http_process_recv(ctx); + http_process_recv(ctx, dst); } quit: @@ -654,14 +666,14 @@ quit: http_only: if (ctx->cb.recv) { - ctx->cb.recv(ctx, pkt, 0, 0, ctx->user_data); + ctx->cb.recv(ctx, pkt, 0, 0, dst, ctx->user_data); } return; http_ready: http_change_state(ctx, HTTP_STATE_OPEN); - url_connected(ctx, HTTP_CONNECT); + url_connected(ctx, HTTP_CONNECT, dst); net_pkt_unref(pkt); }