1 /** @file
2  * @brief HTTP client API
3  *
4  * An API for applications do HTTP requests
5  */
6 
7 /*
8  * Copyright (c) 2019 Intel Corporation
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #ifndef ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_
14 #define ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_
15 
16 /**
17  * @brief HTTP client API
18  * @defgroup http_client HTTP client API
19  * @ingroup networking
20  * @{
21  */
22 
23 #include <kernel.h>
24 #include <net/net_ip.h>
25 #include <net/http_parser.h>
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 #if !defined(HTTP_CRLF)
32 #define HTTP_CRLF "\r\n"
33 #endif
34 
35 #if !defined(HTTP_STATUS_STR_SIZE)
36 #define HTTP_STATUS_STR_SIZE	32
37 #endif
38 
39 /* Is there more data to come */
40 enum http_final_call {
41 	HTTP_DATA_MORE = 0,
42 	HTTP_DATA_FINAL = 1,
43 };
44 
45 struct http_request;
46 struct http_response;
47 
48 /**
49  * @typedef http_payload_cb_t
50  * @brief Callback used when data needs to be sent to the server.
51  *
52  * @param sock Socket id of the connection
53  * @param req HTTP request information
54  * @param user_data User specified data specified in http_client_req()
55  *
56  * @return >=0 amount of data sent, in this case http_client_req() should
57  *             continue sending data,
58  *         <0  if http_client_req() should return the error code to the
59  *             caller.
60  */
61 typedef int (*http_payload_cb_t)(int sock,
62 				 struct http_request *req,
63 				 void *user_data);
64 
65 /**
66  * @typedef http_header_cb_t
67  * @brief Callback can be used if application wants to construct additional
68  * HTTP headers when the HTTP request is sent. Usage of this is optional.
69  *
70  * @param sock Socket id of the connection
71  * @param req HTTP request information
72  * @param user_data User specified data specified in http_client_req()
73  *
74  * @return >=0 amount of data sent, in this case http_client_req() should
75  *             continue sending data,
76  *         <0  if http_client_req() should return the error code to the
77  *             caller.
78  */
79 typedef int (*http_header_cb_t)(int sock,
80 				struct http_request *req,
81 				void *user_data);
82 
83 /**
84  * @typedef http_response_cb_t
85  * @brief Callback used when data is received from the server.
86  *
87  * @param rsp HTTP response information
88  * @param final_data Does this data buffer contain all the data or
89  *        is there still more data to come.
90  * @param user_data User specified data specified in http_client_req()
91  */
92 typedef void (*http_response_cb_t)(struct http_response *rsp,
93 				   enum http_final_call final_data,
94 				   void *user_data);
95 
96 /**
97  * HTTP response from the server.
98  */
99 struct http_response {
100 	/** HTTP parser settings for the application usage */
101 	const struct http_parser_settings *http_cb;
102 
103 	/** User provided HTTP response callback which is
104 	 * called when a response is received to a sent HTTP
105 	 * request.
106 	 */
107 	http_response_cb_t cb;
108 
109 	/** Where the body starts */
110 	uint8_t *body_start;
111 
112 	/** Where the response is stored, this is to be
113 	 * provided by the user.
114 	 */
115 	uint8_t *recv_buf;
116 
117 	/** Response buffer maximum length */
118 	size_t recv_buf_len;
119 
120 	/** Length of the data in the result buf. If the value
121 	 * is larger than recv_buf_len, then it means that
122 	 * the data is truncated and could not be fully copied
123 	 * into recv_buf. This can only happen if the user
124 	 * did not set the response callback. If the callback
125 	 * is set, then the HTTP client API will call response
126 	 * callback many times so that all the data is
127 	 * delivered to the user.
128 	 */
129 	size_t data_len;
130 
131 	/** HTTP Content-Length field value */
132 	size_t content_length;
133 
134 	/** Content length parsed. This should be the same as
135 	 * the content_length field if parsing was ok.
136 	 */
137 	size_t processed;
138 
139 	/* https://tools.ietf.org/html/rfc7230#section-3.1.2
140 	 * The status-code element is a 3-digit integer code
141 	 *
142 	 * The reason-phrase element exists for the sole
143 	 * purpose of providing a textual description
144 	 * associated with the numeric status code. A client
145 	 * SHOULD ignore the reason-phrase content.
146 	 */
147 	char http_status[HTTP_STATUS_STR_SIZE];
148 
149 	/** Numeric HTTP status code which corresponds to the
150 	 * textual description.
151 	 */
152 	uint16_t http_status_code;
153 
154 	uint8_t cl_present : 1;
155 	uint8_t body_found : 1;
156 	uint8_t message_complete : 1;
157 };
158 
159 /** HTTP client internal data that the application should not touch
160  */
161 struct http_client_internal_data {
162 	/** Work for handling timeout */
163 	struct k_work_delayable work;
164 
165 	/** HTTP parser context */
166 	struct http_parser parser;
167 
168 	/** HTTP parser settings */
169 	struct http_parser_settings parser_settings;
170 
171 	/** HTTP response specific data (filled by http_client_req() when
172 	 * data is received)
173 	 */
174 	struct http_response response;
175 
176 	/** User data */
177 	void *user_data;
178 
179 	/** HTTP socket */
180 	int sock;
181 
182 	/** Request timeout */
183 	k_timeout_t timeout;
184 };
185 
186 /**
187  * HTTP client request. This contains all the data that is needed when doing
188  * a HTTP request.
189  */
190 struct http_request {
191 	/** HTTP client request internal data */
192 	struct http_client_internal_data internal;
193 
194 	/* User should fill in following parameters */
195 
196 	/** The HTTP method: GET, HEAD, OPTIONS, POST, ... */
197 	enum http_method method;
198 
199 	/** User supplied callback function to call when response is
200 	 * received.
201 	 */
202 	http_response_cb_t response;
203 
204 	/** User supplied list of HTTP callback functions if the
205 	 * calling application wants to know the parsing status or the HTTP
206 	 * fields. This is optional and normally not needed.
207 	 */
208 	const struct http_parser_settings *http_cb;
209 
210 	/** User supplied buffer where received data is stored */
211 	uint8_t *recv_buf;
212 
213 	/** Length of the user supplied receive buffer */
214 	size_t recv_buf_len;
215 
216 	/** The URL for this request, for example: /index.html */
217 	const char *url;
218 
219 	/** The HTTP protocol, for example "HTTP/1.1" */
220 	const char *protocol;
221 
222 	/** The HTTP header fields (application specific)
223 	 * The Content-Type may be specified here or in the next field.
224 	 * Depending on your application, the Content-Type may vary, however
225 	 * some header fields may remain constant through the application's
226 	 * life cycle. This is a NULL terminated list of header fields.
227 	 */
228 	const char **header_fields;
229 
230 	/** The value of the Content-Type header field, may be NULL */
231 	const char *content_type_value;
232 
233 	/** Hostname to be used in the request */
234 	const char *host;
235 
236 	/** Port number to be used in the request */
237 	const char *port;
238 
239 	/** User supplied callback function to call when payload
240 	 * needs to be sent. This can be NULL in which case the payload field
241 	 * in http_request is used. The idea of this payload callback is to
242 	 * allow user to send more data that is practical to store in allocated
243 	 * memory.
244 	 */
245 	http_payload_cb_t payload_cb;
246 
247 	/** Payload, may be NULL */
248 	const char *payload;
249 
250 	/** Payload length is used to calculate Content-Length. Set to 0
251 	 * for chunked transfers.
252 	 */
253 	size_t payload_len;
254 
255 	/** User supplied callback function to call when optional headers need
256 	 * to be sent. This can be NULL, in which case the optional_headers
257 	 * field in http_request is used. The idea of this optional_headers
258 	 * callback is to allow user to send more HTTP header data that is
259 	 * practical to store in allocated memory.
260 	 */
261 	http_header_cb_t optional_headers_cb;
262 
263 	/** A NULL terminated list of any optional headers that
264 	 * should be added to the HTTP request. May be NULL.
265 	 * If the optional_headers_cb is specified, then this field is ignored.
266 	 * Note that there are two similar fields that contain headers,
267 	 * the header_fields above and this optional_headers. This is done
268 	 * like this to support Websocket use case where Websocket will use
269 	 * header_fields variable and any optional application specific
270 	 * headers will be placed into this field.
271 	 */
272 	const char **optional_headers;
273 };
274 
275 /**
276  * @brief Do a HTTP request. The callback is called when data is received
277  * from the HTTP server. The caller must have created a connection to the
278  * server before calling this function so connect() call must have be done
279  * successfully for the socket.
280  *
281  * @param sock Socket id of the connection.
282  * @param req HTTP request information
283  * @param timeout Max timeout to wait for the data. The timeout value cannot be
284  *        0 as there would be no time to receive the data.
285  *        The timeout value is in milliseconds.
286  * @param user_data User specified data that is passed to the callback.
287  *
288  * @return <0 if error, >=0 amount of data sent to the server
289  */
290 int http_client_req(int sock, struct http_request *req,
291 		    int32_t timeout, void *user_data);
292 
293 #ifdef __cplusplus
294 }
295 #endif
296 
297 /**
298  * @}
299  */
300 
301 #endif /* ZEPHYR_INCLUDE_NET_HTTP_CLIENT_H_ */
302