This repository has been archived by the owner on Jun 15, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
/
http_server.h
290 lines (259 loc) · 10.3 KB
/
http_server.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* Simple HTTP server for ESP32.
* Copyright Ivan Grokhotkov, 2017.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file http_server.h
* @brief Simple HTTP server
*/
/* Pull in the definitions of HTTP methods */
#include "http_parser.h"
/**
* Bit masks for events to be passed to a handler
*/
#define HTTP_HANDLE_URI BIT(0) /*!< Called when URI is received */
#define HTTP_HANDLE_HEADERS BIT(1) /*!< Called when all headers are received */
#define HTTP_HANDLE_DATA BIT(2) /*!< Called each time a fragment of request body is received */
#define HTTP_HANDLE_RESPONSE BIT(3) /*!< Called at the end of the request to produce the response */
/** Opaque type representing single HTTP connection */
typedef struct http_context_* http_context_t;
/** Opaque type representing HTTP server */
typedef struct http_server_context_* http_server_t;
/** Callback type of HTTP request handler */
typedef void (* http_handler_fn_t)(http_context_t http_ctx, void* ctx);
/**
* @brief Configuration of the HTTP server
*/
typedef struct {
int port; /*!< TCP Port to listen on */
int task_affinity; /*!< Server task affinity (CPU number of tskNO_AFFINITY */
int task_stack_size; /*!< Server task stack size, in bytes */
int task_priority; /*!< Server task priority */
} http_server_options_t;
/** Default initializer for http_server_options_t */
#define HTTP_SERVER_OPTIONS_DEFAULT() {\
.port = 80, \
.task_affinity = tskNO_AFFINITY, \
.task_stack_size = 4096, \
.task_priority = 1, \
}
/**
* @brief initialize HTTP server, start listening
* @param options pointer to http server options, can point to a temporary
* @param[out] output, handle of the server; pass it to http_server_stop do
* delete the server.
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if out of RAM
* - ESP_FAIL if some other error
*/
esp_err_t http_server_start(const http_server_options_t* options, http_server_t* out_server);
/**
* @brief Stop the previously started server
* @param server handle obtained from http_server_start
* @return
* - ESP_OK on success
*/
esp_err_t http_server_stop(http_server_t server);
/**
* @brief Register a handler for certain URI
*
* The handler will be called when a client makes a request with matching URI
* and HTTP method.
*
* @note Currently only matches full URIs, doesn't support regex
*
* @param server Server handle to register the handler for
* @param uri_pattern URI pattern to match
* @param method one of HTTP_GET, HTTP_POST, HTTP_PUT, etc
* @param events a bit mask of HTTP_HANDLE_X events for which the handler
* should be called
* @param callback function to call
* @param callback_arg application context to pass to the callback
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory
*/
esp_err_t http_register_handler(http_server_t server, const char* uri_pattern, int method,
int events, http_handler_fn_t callback, void* callback_arg);
/**
* @brief Register a handler for application/x-www-form-urlencoded requests
*
* Unlike http_register_handler, handlers registered using this function will
* not receive HTTP_HANDLE_DATA events. Instead, request body will be parsed
* into key-value pairs, which can be retrieved while handling
* HTTP_HANDLE_RESPONSE event using http_request_get_form_value.
*
* @param server Server handle to register the handler for
* @param uri_pattern URI pattern to match
* @param method one of HTTP_GET, HTTP_POST, HTTP_PUT, etc
* @param events a bit mask of HTTP_HANDLE_X events for which the handler
* should be called. HTTP_HANDLE_DATA will not be passed to
* the callback.
* @param callback function to call
* @param callback_arg application context to pass to the callback
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if out of memory
*/
esp_err_t http_register_form_handler(http_server_t server, const char* uri_pattern, int method,
int events, http_handler_fn_t callback, void* callback_arg);
/**
* @brief Get value for given URL argument of form argument
* @param http_ctx context passed to the handler
* @param name name of URL or form argument
* @return pointer to the value, valid until the end of request
*/
const char* http_request_get_arg_value(http_context_t http_ctx, const char* name);
/**
* @brief Get request method
* @param http_ctx context passed to the handler
* @return one of HTTP_GET, HTTP_POST, etc
*/
int http_request_get_method(http_context_t http_ctx);
/**
* @brief Get URI present in the request
* @param http_ctx context passed to the handler
* @return pointer to the URI, valid until the end of request
*/
const char* http_request_get_uri(http_context_t http_ctx);
/**
* @brief Get request header
* @param http_ctx context passed to the handler
* @param name header name
* @return
* - If the header with given name is present in the request, returns
* pointer to the value; valid until request callback returns.
* - Otherwise, returns NULL
*/
const char* http_request_get_header(http_context_t ctx, const char* name);
/**
* @brief Get the event which caused a call to the handler
* @param ctx context passed to the handler
* @return one of HTTP_HANDLE_X values
*/
int http_request_get_event(http_context_t ctx);
/**
* @brief Get the request body fragment
* To be used when handling HTTP_HANDLE_DATA event.
*
* @param ctx context passed to the handler
* @param[out] out_data_ptr output, receives pointer to the body fragment
* @param[out] out_size output, receives the size of the body fragment
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if called for events other than HTTP_HANDLE_DATA
*/
esp_err_t http_request_get_data(http_context_t ctx, const char** out_data_ptr, size_t* out_size);
/**
* @brief structure describing a part of the response to be sent
*/
typedef struct {
const void* data; /*!< pointer to data to be sent */
size_t size; /*!< size of data to send; if data is a 0-terminated string, size can be left 0 */
bool data_is_persistent; /*!< set to true if data is in constant RAM */
} http_buffer_t;
#define HTTP_RESPONSE_SIZE_UNKNOWN SIZE_MAX
/**
* @brief Begin writing HTTP response
* @param http_ctx context passed to the handler
* @param code HTTP response code
* @param content_type string to send as a value in content-type header
* @param response_size either the size of the response body, or HTTP_RESPONSE_SIZE_UNKNOWN
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if can't allocate temporary buffer
* - other errors from LwIP
*/
esp_err_t http_response_begin(http_context_t http_ctx, int code,
const char* content_type, size_t response_size);
/**
* @brief Add HTTP header to the response
*
* This function may be called between http_response_begin and http_response_write.
*
* For multipart responses, calling it between http_response_begin and
* http_response_begin_multipart adds header to the list of headers in the original
* response (which is sent first). Calling it after http_response_begin_multipart
* adds the header to the list of headers sent for the current response part.
*
* 'name' and 'val' can point to temporary values. This function copies the
* both strings into internal storage.
*
* @param http_ctx context passed to the handler
* @param name Header name
* @param val Header value
* @return
* - ESP_OK on success
* - ESP_ERR_NO_MEM if can't allocate memory for the header
*/
esp_err_t http_response_set_header(http_context_t http_ctx,
const char* name, const char* val);
/**
* @brief Start one part of a multipart response
*
* For multipart responses, the sequence of calls is as follows:
*
* 1. http_response_begin (with size == HTTP_RESPONSE_SIZE_UNKNOWN)
* 2. (optional) http_response_set_header — for the overall response
* 3. http_response_begin_multipart (if part size is known, pass it in response_size argument)
* 4. (optional) http_repponse_set_header — for the current part
* 5. (optional) http_response_write — write response data
* 6. http_response_end_multipart — when done with the part
* 7. repeat from 3 as needed
*
* @param http_ctx context passed to the handler
* @param content_type value to be set in part's content-type header
* @param response_size either the size of part body, or HTTP_RESPONSE_SIZE_UNKNOWN
* @return
* - ESP_OK
* - ESP_ERR_NO_MEM if can't allocate memory
* - other errors from LwIP
*/
esp_err_t http_response_begin_multipart(http_context_t http_ctx,
const char* content_type, size_t response_size);
/**
* @brief Indicate that one part of the multipart response is finished
* @param http_ctx context passed to the handler
* @param boundary part boundary. Has to be the same as given in the content-type of the first response.
* @return
* - ESP_OK
* - other errors from LwIP
*/
esp_err_t http_response_end_multipart(http_context_t http_ctx, const char* boundary);
/**
* @brief Send a piece of HTTP response to the client
* @param http_ctx context passed to the handler
* @param buffer data to send, see \ref http_buffer_t
* @return
* - ESP_OK on success
* - other errors from LwIP
*/
esp_err_t http_response_write(http_context_t http_ctx, const http_buffer_t* buffer);
/**
* @brief Indicate that response is complete
* @param http_ctx context passed to the handler
* @return
* - ESP_OK on success
* - other errors in the future?
*/
esp_err_t http_response_end(http_context_t http_ctx);
#ifdef __cplusplus
}
#endif