-
Notifications
You must be signed in to change notification settings - Fork 80
/
http_server.h
274 lines (240 loc) · 10.5 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
/*
Serval DNA - HTTP Server API
Copyright (C) 2013 Serval Project Inc.
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 2
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __SERVAL_DNA__HTTP_SERVER_H
#define __SERVAL_DNA__HTTP_SERVER_H
#include <stdint.h> // for uint16_t, uint8_t
#include <limits.h>
#include "lang.h" // for bool_t
#include "os.h" // for time_ms_t
#include "idebug.h" // for struct idebug
#include "strbuf.h"
#include "strbuf_helpers.h" // for struct json_atom
#include "fdqueue.h" // for struct sched_ent
#include "socket.h" // for struct socket_address
/* Generic HTTP request handling.
*
* @author Andrew Bettison <[email protected]>
*/
extern const char HTTP_VERB_GET[];
extern const char HTTP_VERB_POST[];
extern const char HTTP_VERB_PUT[];
extern const char HTTP_VERB_HEAD[];
extern const char HTTP_VERB_DELETE[];
extern const char HTTP_VERB_TRACE[];
extern const char HTTP_VERB_OPTIONS[];
extern const char HTTP_VERB_CONNECT[];
extern const char HTTP_VERB_PATCH[];
typedef uint64_t http_size_t;
#define PRIhttp_size_t PRIu64
struct http_request;
struct http_range {
enum http_range_type { NIL = 0, CLOSED, OPEN, SUFFIX } type;
http_size_t first; // only for CLOSED or OPEN
http_size_t last; // only for CLOSED or SUFFIX
};
unsigned http_range_close(struct http_range *dst, const struct http_range *src, unsigned nranges, http_size_t content_length);
http_size_t http_range_bytes(const struct http_range *range, unsigned nranges);
#define CONTENT_LENGTH_UNKNOWN UINT64_MAX
struct mime_content_type {
char type[64];
char subtype[64];
char multipart_boundary[71];
char charset[31];
char format[31];
};
int mime_content_types_are_equal(const struct mime_content_type *a, const struct mime_content_type *b);
extern const struct mime_content_type CONTENT_TYPE_FAVICON;
extern const struct mime_content_type CONTENT_TYPE_TEXT;
extern const struct mime_content_type CONTENT_TYPE_HTML;
extern const struct mime_content_type CONTENT_TYPE_JSON;
extern const struct mime_content_type CONTENT_TYPE_BLOB;
struct http_client_authorization {
enum http_authorization_scheme { NOAUTH = 0, BASIC } scheme;
union {
struct http_client_credentials_basic {
const char *user;
const char *password;
} basic;
} credentials;
};
struct http_www_authenticate {
enum http_authorization_scheme scheme;
const char *realm;
};
struct http_origin {
uint8_t null;
char scheme[10]; // enough for "https"
char hostname[40]; // enough for "localhost"
uint16_t port;
};
struct http_request_headers {
http_size_t content_length;
struct mime_content_type content_type;
unsigned short content_range_count;
struct http_origin origin;
struct http_range content_ranges[5];
struct http_client_authorization authorization;
bool_t expect:1;
bool_t chunked:1;
};
struct http_response_headers {
uint8_t minor_version;
http_size_t content_length;
http_size_t content_range_start; // range_end = range_start + content_length - 1
http_size_t resource_length; // size of entire resource
const char *location; // used with 301 and 302 responses
const struct mime_content_type *content_type; // one of the CONTENT_TYPE_ consts declared above
const char *boundary;
struct http_origin allow_origin;
const char *allow_methods;
const char *allow_headers;
struct http_www_authenticate www_authenticate;
};
struct http_content_generator_result {
size_t generated;
size_t need;
};
typedef int (HTTP_CONTENT_GENERATOR)(struct http_request *, unsigned char *, size_t, struct http_content_generator_result *);
struct http_response {
uint16_t status_code;
const char *reason;
struct {
const char *label;
struct json_atom value;
} result_extra[4];
struct http_response_headers header;
const char *content;
HTTP_CONTENT_GENERATOR *content_generator; // callback to produce more content
};
#define MIME_FILENAME_MAXLEN 127
struct mime_content_disposition {
char type[64];
char name[64];
char filename[MIME_FILENAME_MAXLEN + 1];
http_size_t size;
time_t creation_date;
time_t modification_date;
time_t read_date;
};
struct mime_part_headers {
http_size_t content_length;
struct mime_content_type content_type;
struct mime_content_disposition content_disposition;
};
struct http_mime_handler {
// All these functions may abort the request processing by returning an HTTP
// filure status code in the range 400-599 or by initiating an HTTP response
// directly (changing the phase from RECEIVE to TRANSMIT). They can return
// zero to indicate that parsing should proceed.
int (*handle_mime_preamble)(struct http_request *, char *, size_t);
int (*handle_mime_part_start)(struct http_request *);
int (*handle_mime_part_header)(struct http_request *, const struct mime_part_headers *);
int (*handle_mime_body)(struct http_request *, char *, size_t);
int (*handle_mime_part_end)(struct http_request *);
int (*handle_mime_epilogue)(struct http_request *, char *, size_t);
};
struct http_request;
void http_request_init(struct http_request *r, int sockfd);
void http_request_free_response_buffer(struct http_request *r);
int http_request_set_response_bufsize(struct http_request *r, size_t bufsiz);
void http_request_finalise(struct http_request *r);
void http_request_pause_response(struct http_request *r, time_ms_t until);
void http_request_resume_response(struct http_request *r);
void http_request_response_static(struct http_request *r, int result, const struct mime_content_type *content_type, const char *body, uint64_t bytes);
void http_request_response_generated(struct http_request *r, int result, const struct mime_content_type *content_type, HTTP_CONTENT_GENERATOR *);
void http_request_simple_response(struct http_request *r, uint16_t result, const char *body);
typedef int (HTTP_CONTENT_GENERATOR_STRBUF_CHUNKER)(struct http_request *, strbuf);
int generate_http_content_from_strbuf_chunks(struct http_request *, char *, size_t, struct http_content_generator_result *, HTTP_CONTENT_GENERATOR_STRBUF_CHUNKER *);
typedef int HTTP_REQUEST_PARSER(struct http_request *);
typedef void HTTP_RENDERER(const struct http_request *, strbuf);
struct http_request {
struct sched_ent alarm; // MUST BE FIRST ELEMENT
// The following control the lifetime of this struct.
enum http_request_phase { RECEIVE, TRANSMIT, PAUSE, DONE } phase;
void (*finalise)(struct http_request *);
void (*release)(void*);
// Identify request from others being run. Monotonic counter feeds it. Only
// used for debugging when we write post-<uuid>.log files for multi-part form
// requests.
unsigned int uuid;
// These indirect debug flags allow different instances of HTTP servers to
// control their debug output independently of each other.
struct idebug debug;
struct idebug disable_tx;
// The following are used for parsing the HTTP request.
time_ms_t initiate_time; // time connection was initiated
time_ms_t idle_timeout; // disconnect if no bytes received for this long
struct socket_address client_addr; // caller may supply this
// The parsed HTTP request is accumulated into the following fields.
const char *verb; // points to nul terminated static string, "GET", "PUT", etc.
const char *path; // points into buffer; nul terminated
struct query_parameter {
const char *name; // points into buffer; nul terminated
const char *value; // points into buffer; nul terminated
}
query_parameters[10]; // can make this as big as needed, but not dynamic
uint8_t version_major; // m from from HTTP/m.n
uint8_t version_minor; // n from HTTP/m.n
struct http_request_headers request_header;
// Parsing is done by setting 'parser' to point to a series of parsing
// functions as the parsing state progresses.
HTTP_REQUEST_PARSER *parser; // current parser function
HTTP_REQUEST_PARSER *decoder; // decode any transfer encoding
// The caller may set these up, and they are invoked by the parser as request
// parsing reaches different stages.
HTTP_REQUEST_PARSER *handle_first_line; // called after first line is parsed
HTTP_REQUEST_PARSER *handle_headers; // called after all HTTP headers are parsed
HTTP_REQUEST_PARSER *handle_content_end; // called after all content is received
// The following are used for managing the buffer during RECEIVE phase.
char *reserved; // end of reserved data in buffer[]
char *received; // start of received data in buffer[]
char *end_decoded; // end of decoded data in buffer[]
char *decode_ptr; // end of received data in buffer[]
char *end_received; // end of received data in buffer[]
char *parsed; // start of unparsed data in buffer[]
char *cursor; // for parsing
http_size_t request_content_remaining;
enum chunk_state {CHUNK_SIZE, CHUNK_DATA, CHUNK_NEWLINE} chunk_state;
uint64_t chunk_size;
// The following are used for parsing a multipart body.
enum mime_state { START, PREAMBLE, HEADER, BODY, EPILOGUE } form_data_state;
struct http_mime_handler form_data;
struct mime_part_headers part_header;
http_size_t part_body_length;
// The following are used for constructing the response that will be sent in
// TRANSMIT phase.
struct http_response response;
HTTP_RENDERER *render_extra_headers;
// The following are used during TRANSMIT phase to control buffering and
// sending.
http_size_t response_length; // total response bytes (header + content)
http_size_t response_sent; // for counting up to response_length
char *response_buffer;
size_t response_buffer_need;
size_t response_buffer_size;
size_t response_buffer_length;
size_t response_buffer_sent;
void (*response_free_buffer)(void*);
// This buffer is used during RECEIVE and TRANSMIT phase.
char buffer[8 * 1024];
};
/* Return the nul-terminated string value of a given query parameter: NULL if
* no such parameter was supplied; HTTP_REQUEST_PARAM_NOVALUE if the parameter
* was supplied without an '=value' part.
*/
const char *http_request_get_query_param(struct http_request *r, const char *name);
extern const char HTTP_REQUEST_PARAM_NOVALUE[];
#endif // __SERVAL_DNA__HTTP_SERVER_H