blob: 40c8f9a23d32cd71a9ccfd113727d4070a479245 [file] [log] [blame]
/** @file
* @brief HTTP client API
*
* An API for applications do HTTP requests
*/
/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_
#define ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_
/**
* @brief HTTP client API
* @defgroup http_client HTTP client API
* @ingroup networking
* @{
*/
#include <kernel.h>
#include <net/net_ip.h>
#include <net/http_parser.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(HTTP_CRLF)
#define HTTP_CRLF "\r\n"
#endif
#if !defined(HTTP_STATUS_STR_SIZE)
#define HTTP_STATUS_STR_SIZE 32
#endif
/* Is there more data to come */
enum http_final_call {
HTTP_DATA_MORE = 0,
HTTP_DATA_FINAL = 1,
};
struct http_request;
struct http_response;
/**
* @typedef http_payload_cb_t
* @brief Callback used when data needs to be sent to the server.
*
* @param sock Socket id of the connection
* @param req HTTP request information
* @param user_data User specified data specified in http_client_req()
*
* @return >=0 amount of data sent, in this case http_client_req() should
* continue sending data,
* <0 if http_client_req() should return the error code to the
* caller.
*/
typedef int (*http_payload_cb_t)(int sock,
struct http_request *req,
void *user_data);
/**
* @typedef http_header_cb_t
* @brief Callback can be used if application wants to construct additional
* HTTP headers when the HTTP request is sent. Usage of this is optional.
*
* @param sock Socket id of the connection
* @param req HTTP request information
* @param user_data User specified data specified in http_client_req()
*
* @return >=0 amount of data sent, in this case http_client_req() should
* continue sending data,
* <0 if http_client_req() should return the error code to the
* caller.
*/
typedef int (*http_header_cb_t)(int sock,
struct http_request *req,
void *user_data);
/**
* @typedef http_response_cb_t
* @brief Callback used when data is received from the server.
*
* @param rsp HTTP response information
* @param final_data Does this data buffer contain all the data or
* is there still more data to come.
* @param user_data User specified data specified in http_client_req()
*/
typedef void (*http_response_cb_t)(struct http_response *rsp,
enum http_final_call final_data,
void *user_data);
/**
* HTTP response from the server.
*/
struct http_response {
/** HTTP parser settings for the application usage */
const struct http_parser_settings *http_cb;
/** User provided HTTP response callback which is
* called when a response is received to a sent HTTP
* request.
*/
http_response_cb_t cb;
/** Where the body starts */
uint8_t *body_start;
/** Where the response is stored, this is to be
* provided by the user.
*/
uint8_t *recv_buf;
/** Response buffer maximum length */
size_t recv_buf_len;
/** Length of the data in the result buf. If the value
* is larger than recv_buf_len, then it means that
* the data is truncated and could not be fully copied
* into recv_buf. This can only happen if the user
* did not set the response callback. If the callback
* is set, then the HTTP client API will call response
* callback many times so that all the data is
* delivered to the user.
*/
size_t data_len;
/** HTTP Content-Length field value */
size_t content_length;
/** Content length parsed. This should be the same as
* the content_length field if parsing was ok.
*/
size_t processed;
/* https://tools.ietf.org/html/rfc7230#section-3.1.2
* The status-code element is a 3-digit integer code
*
* The reason-phrase element exists for the sole
* purpose of providing a textual description
* associated with the numeric status code. A client
* SHOULD ignore the reason-phrase content.
*/
char http_status[HTTP_STATUS_STR_SIZE];
/** Numeric HTTP status code which corresponds to the
* textual description.
*/
uint16_t http_status_code;
uint8_t cl_present : 1;
uint8_t body_found : 1;
uint8_t message_complete : 1;
};
/** HTTP client internal data that the application should not touch
*/
struct http_client_internal_data {
/** Work for handling timeout */
struct k_work_delayable work;
/** HTTP parser context */
struct http_parser parser;
/** HTTP parser settings */
struct http_parser_settings parser_settings;
/** HTTP response specific data (filled by http_client_req() when
* data is received)
*/
struct http_response response;
/** User data */
void *user_data;
/** HTTP socket */
int sock;
/** Request timeout */
k_timeout_t timeout;
};
/**
* HTTP client request. This contains all the data that is needed when doing
* a HTTP request.
*/
struct http_request {
/** HTTP client request internal data */
struct http_client_internal_data internal;
/* User should fill in following parameters */
/** The HTTP method: GET, HEAD, OPTIONS, POST, ... */
enum http_method method;
/** User supplied callback function to call when response is
* received.
*/
http_response_cb_t response;
/** User supplied list of HTTP callback functions if the
* calling application wants to know the parsing status or the HTTP
* fields. This is optional and normally not needed.
*/
const struct http_parser_settings *http_cb;
/** User supplied buffer where received data is stored */
uint8_t *recv_buf;
/** Length of the user supplied receive buffer */
size_t recv_buf_len;
/** The URL for this request, for example: /index.html */
const char *url;
/** The HTTP protocol, for example "HTTP/1.1" */
const char *protocol;
/** The HTTP header fields (application specific)
* The Content-Type may be specified here or in the next field.
* Depending on your application, the Content-Type may vary, however
* some header fields may remain constant through the application's
* life cycle. This is a NULL terminated list of header fields.
*/
const char **header_fields;
/** The value of the Content-Type header field, may be NULL */
const char *content_type_value;
/** Hostname to be used in the request */
const char *host;
/** Port number to be used in the request */
const char *port;
/** User supplied callback function to call when payload
* needs to be sent. This can be NULL in which case the payload field
* in http_request is used. The idea of this payload callback is to
* allow user to send more data that is practical to store in allocated
* memory.
*/
http_payload_cb_t payload_cb;
/** Payload, may be NULL */
const char *payload;
/** Payload length is used to calculate Content-Length. Set to 0
* for chunked transfers.
*/
size_t payload_len;
/** User supplied callback function to call when optional headers need
* to be sent. This can be NULL, in which case the optional_headers
* field in http_request is used. The idea of this optional_headers
* callback is to allow user to send more HTTP header data that is
* practical to store in allocated memory.
*/
http_header_cb_t optional_headers_cb;
/** A NULL terminated list of any optional headers that
* should be added to the HTTP request. May be NULL.
* If the optional_headers_cb is specified, then this field is ignored.
* Note that there are two similar fields that contain headers,
* the header_fields above and this optional_headers. This is done
* like this to support Websocket use case where Websocket will use
* header_fields variable and any optional application specific
* headers will be placed into this field.
*/
const char **optional_headers;
};
/**
* @brief Do a HTTP request. The callback is called when data is received
* from the HTTP server. The caller must have created a connection to the
* server before calling this function so connect() call must have be done
* successfully for the socket.
*
* @param sock Socket id of the connection.
* @param req HTTP request information
* @param timeout Max timeout to wait for the data. The timeout value cannot be
* 0 as there would be no time to receive the data.
* The timeout value is in milliseconds.
* @param user_data User specified data that is passed to the callback.
*
* @return <0 if error, >=0 amount of data sent to the server
*/
int http_client_req(int sock, struct http_request *req,
int32_t timeout, void *user_data);
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_ */