kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

http.h (14143B)



      1 /*
      2  * Copyright (c) 2013 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #if !defined(KORE_NO_HTTP)
     18 
     19 #ifndef __H_HTTP_H
     20 #define __H_HTTP_H
     21 
     22 #include <sys/types.h>
     23 #include <sys/queue.h>
     24 
     25 #include "sha2.h"
     26 
     27 #if defined(__cplusplus)
     28 extern "C" {
     29 #endif
     30 
     31 /* Keep the http_populate_get symbol around. */
     32 #define http_populate_get	http_populate_qs
     33 
     34 #define HTTP_KEEPALIVE_TIME	20
     35 #define HTTP_HSTS_ENABLE	31536000
     36 #define HTTP_HEADER_MAX_LEN	4096
     37 #define HTTP_BODY_MAX_LEN	1024000
     38 #define HTTP_URI_LEN		2000
     39 #define HTTP_USERAGENT_LEN	256
     40 #define HTTP_REFERER_LEN	256
     41 #define HTTP_REQ_HEADER_MAX	25
     42 #define HTTP_MAX_QUERY_ARGS	20
     43 #define HTTP_MAX_COOKIES	10
     44 #define HTTP_MAX_COOKIENAME	255
     45 #define HTTP_HEADER_BUFSIZE	1024
     46 #define HTTP_COOKIE_BUFSIZE	1024
     47 #define HTTP_DATE_MAXSIZE	255
     48 #define HTTP_REQUEST_LIMIT	1000
     49 #define HTTP_REQUEST_MS		10
     50 #define HTTP_BODY_DISK_PATH	"tmp_files"
     51 #define HTTP_BODY_DISK_OFFLOAD	0
     52 #define HTTP_BODY_PATH_MAX	256
     53 #define HTTP_BOUNDARY_MAX	80
     54 #define HTTP_HEADER_TIMEOUT	10
     55 #define HTTP_BODY_TIMEOUT	60
     56 
     57 #define HTTP_ARG_TYPE_RAW	0
     58 #define HTTP_ARG_TYPE_BYTE	1
     59 #define HTTP_ARG_TYPE_INT16	2
     60 #define HTTP_ARG_TYPE_UINT16	3
     61 #define HTTP_ARG_TYPE_INT32	4
     62 #define HTTP_ARG_TYPE_UINT32	5
     63 #define HTTP_ARG_TYPE_STRING	6
     64 #define HTTP_ARG_TYPE_INT64	7
     65 #define HTTP_ARG_TYPE_UINT64	8
     66 #define HTTP_ARG_TYPE_FLOAT	9
     67 #define HTTP_ARG_TYPE_DOUBLE	10
     68 
     69 #define HTTP_STATE_ERROR	0
     70 #define HTTP_STATE_CONTINUE	1
     71 #define HTTP_STATE_COMPLETE	2
     72 #define HTTP_STATE_RETRY	3
     73 
     74 struct http_runlock_queue {
     75 	struct http_request		*req;
     76 	LIST_ENTRY(http_runlock_queue)	list;
     77 };
     78 
     79 struct http_runlock {
     80 	struct http_request		*owner;
     81 	LIST_HEAD(, http_runlock_queue)	queue;
     82 };
     83 
     84 struct http_header {
     85 	char			*header;
     86 	char			*value;
     87 
     88 	TAILQ_ENTRY(http_header)	list;
     89 };
     90 
     91 #define HTTP_COOKIE_HTTPONLY	0x0001
     92 #define HTTP_COOKIE_SECURE	0x0002
     93 
     94 struct http_cookie {
     95 	char				*name;
     96 	char				*value;
     97 	char				*path;
     98 	char				*domain;
     99 	u_int32_t			maxage;
    100 	time_t				expires;
    101 	u_int16_t			flags;
    102 
    103 	TAILQ_ENTRY(http_cookie)	list;
    104 };
    105 
    106 struct http_arg {
    107 	char			*name;
    108 	char			*s_value;
    109 
    110 	TAILQ_ENTRY(http_arg)	list;
    111 };
    112 
    113 #define COPY_ARG_TYPE(v, t)				\
    114 	do {						\
    115 		*(t *)nout = v;				\
    116 	} while (0)
    117 
    118 #define COPY_ARG_INT64(type, sign)					\
    119 	do {								\
    120 		int err;						\
    121 		type nval;						\
    122 		nval = (type)kore_strtonum64(data, sign, &err);		\
    123 		if (err != KORE_RESULT_OK)				\
    124 			return (KORE_RESULT_ERROR);			\
    125 		COPY_ARG_TYPE(nval, type);				\
    126 	} while (0)
    127 
    128 #define COPY_ARG_DOUBLE(min, max, type)					\
    129 	do {								\
    130 		int err;						\
    131 		type nval;						\
    132 		nval = kore_strtodouble(data, min, max, &err);		\
    133 		if (err != KORE_RESULT_OK)				\
    134 			return (KORE_RESULT_ERROR);			\
    135 		COPY_ARG_TYPE(nval, type);				\
    136 	} while (0)
    137 
    138 #define COPY_ARG_INT(min, max, type)					\
    139 	do {								\
    140 		int err;						\
    141 		int64_t nval;						\
    142 		nval = kore_strtonum(data, 10, min, max, &err);		\
    143 		if (err != KORE_RESULT_OK)				\
    144 			return (KORE_RESULT_ERROR);			\
    145 		COPY_ARG_TYPE(nval, type);				\
    146 	} while (0)
    147 
    148 #define COPY_AS_INTTYPE_64(type, sign)					\
    149 	do {								\
    150 		if (nout == NULL)					\
    151 			return (KORE_RESULT_ERROR);			\
    152 		COPY_ARG_INT64(type, sign);				\
    153 	} while (0)
    154 
    155 #define COPY_AS_INTTYPE(min, max, type)					\
    156 	do {								\
    157 		if (nout == NULL)					\
    158 			return (KORE_RESULT_ERROR);			\
    159 		COPY_ARG_INT(min, max, type);				\
    160 	} while (0)
    161 
    162 #define http_argument_get_string(r, n, o)				\
    163 	http_argument_get(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
    164 
    165 #define http_argument_get_byte(r, n, o)					\
    166 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
    167 
    168 #define http_argument_get_uint16(r, n, o)				\
    169 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
    170 
    171 #define http_argument_get_int16(r, n, o)				\
    172 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
    173 
    174 #define http_argument_get_uint32(r, n, o)				\
    175 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
    176 
    177 #define http_argument_get_int32(r, n, o)				\
    178 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
    179 
    180 #define http_argument_get_uint64(r, n, o)				\
    181 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
    182 
    183 #define http_argument_get_int64(r, n, o)				\
    184 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
    185 
    186 #define http_argument_get_float(r, n, o)				\
    187 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
    188 
    189 #define http_argument_get_double(r, n, o)				\
    190 	http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
    191 
    192 #define http_request_header_byte(r, n, o)				\
    193 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
    194 
    195 #define http_request_header_uint16(r, n, o)				\
    196 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
    197 
    198 #define http_request_header_int16(r, n, o)				\
    199 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
    200 
    201 #define http_request_header_uint32(r, n, o)				\
    202 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
    203 
    204 #define http_request_header_int32(r, n, o)				\
    205 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
    206 
    207 #define http_request_header_uint64(r, n, o)				\
    208 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
    209 
    210 #define http_request_header_int64(r, n, o)				\
    211 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
    212 
    213 #define http_request_header_float(r, n, o)				\
    214 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
    215 
    216 #define http_request_header_double(r, n, o)				\
    217 	http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
    218 
    219 struct http_file {
    220 	char			*name;
    221 	char			*filename;
    222 	size_t			position;
    223 	size_t			offset;
    224 	size_t			length;
    225 	struct http_request	*req;
    226 	TAILQ_ENTRY(http_file)	list;
    227 };
    228 
    229 #define HTTP_METHOD_GET		0x0001
    230 #define HTTP_METHOD_POST	0x0002
    231 #define HTTP_METHOD_PUT		0x0004
    232 #define HTTP_METHOD_DELETE	0x0010
    233 #define HTTP_METHOD_HEAD	0x0020
    234 #define HTTP_METHOD_OPTIONS	0x0040
    235 #define HTTP_METHOD_PATCH	0x0080
    236 
    237 #define HTTP_METHOD_ALL		(HTTP_METHOD_GET | HTTP_METHOD_POST | \
    238     HTTP_METHOD_PUT | HTTP_METHOD_DELETE | HTTP_METHOD_HEAD | \
    239     HTTP_METHOD_OPTIONS | HTTP_METHOD_PATCH)
    240 
    241 #define HTTP_REQUEST_COMPLETE		0x0001
    242 #define HTTP_REQUEST_DELETE		0x0002
    243 #define HTTP_REQUEST_SLEEPING		0x0004
    244 #define HTTP_REQUEST_EXPECT_BODY	0x0020
    245 #define HTTP_REQUEST_RETAIN_EXTRA	0x0040
    246 #define HTTP_REQUEST_NO_CONTENT_LENGTH	0x0080
    247 #define HTTP_REQUEST_AUTHED		0x0100
    248 
    249 #define HTTP_VERSION_1_1		0x1000
    250 #define HTTP_VERSION_1_0		0x2000
    251 
    252 #define HTTP_VALIDATOR_IS_REQUEST	0x8000
    253 
    254 #define HTTP_BODY_DIGEST_LEN		32
    255 #define HTTP_BODY_DIGEST_STRLEN		((HTTP_BODY_DIGEST_LEN * 2) + 1)
    256 
    257 #define HTTP_CAPTURE_GROUPS		17
    258 
    259 struct reqcall;
    260 struct kore_task;
    261 struct http_client;
    262 
    263 struct http_redirect {
    264 	regex_t				rctx;
    265 	int				status;
    266 	char				*target;
    267 	TAILQ_ENTRY(http_redirect)	list;
    268 };
    269 
    270 struct http_request {
    271 	u_int8_t			method;
    272 	u_int8_t			fsm_state;
    273 	u_int16_t			flags;
    274 	u_int16_t			status;
    275 	u_int64_t			ms;
    276 	u_int64_t			start;
    277 	u_int64_t			end;
    278 	u_int64_t			total;
    279 	const char			*path;
    280 	const char			*host;
    281 	const char			*agent;
    282 	const char			*referer;
    283 	struct connection		*owner;
    284 	SHA2_CTX			hashctx;
    285 	u_int8_t			*headers;
    286 	struct kore_buf			*http_body;
    287 	int				http_body_fd;
    288 	char				*http_body_path;
    289 	u_int64_t			http_body_length;
    290 	u_int64_t			http_body_offset;
    291 	u_int64_t			content_length;
    292 	void				*hdlr_extra;
    293 	size_t				state_len;
    294 	char				*query_string;
    295 	struct kore_route		*rt;
    296 	struct http_runlock_queue	*runlock;
    297 	void				(*onfree)(struct http_request *);
    298 
    299 #if defined(KORE_USE_PYTHON)
    300 	void				*py_req;
    301 	void				*py_coro;
    302 	void				*py_validator;
    303 	struct reqcall			*py_rqnext;
    304 #endif
    305 
    306 	regmatch_t	cgroups[HTTP_CAPTURE_GROUPS];
    307 	u_int8_t	http_body_digest[HTTP_BODY_DIGEST_LEN];
    308 
    309 #if defined(KORE_USE_CURL)
    310 	LIST_HEAD(, kore_curl)		chandles;
    311 #endif
    312 
    313 #if defined(KORE_USE_TASKS)
    314 	LIST_HEAD(, kore_task)		tasks;
    315 #endif
    316 
    317 #if defined(KORE_USE_PGSQL)
    318 	LIST_HEAD(, kore_pgsql)		pgsqls;
    319 #endif
    320 
    321 	TAILQ_HEAD(, http_cookie)	req_cookies;
    322 	TAILQ_HEAD(, http_cookie)	resp_cookies;
    323 	TAILQ_HEAD(, http_header)	req_headers;
    324 	TAILQ_HEAD(, http_header)	resp_headers;
    325 	TAILQ_HEAD(, http_arg)		arguments;
    326 	TAILQ_HEAD(, http_file)		files;
    327 	TAILQ_ENTRY(http_request)	list;
    328 	TAILQ_ENTRY(http_request)	olist;
    329 };
    330 
    331 #define KORE_HTTP_STATE(f)		{ #f, f }
    332 
    333 struct http_state {
    334 	const char		*name;
    335 	int			(*cb)(struct http_request *);
    336 };
    337 
    338 struct http_media_type {
    339 	char				*ext;
    340 	char				*type;
    341 	LIST_ENTRY(http_media_type)	list;
    342 };
    343 
    344 extern size_t		http_body_max;
    345 extern u_int16_t	http_body_timeout;
    346 extern u_int16_t	http_header_max;
    347 extern u_int16_t	http_header_timeout;
    348 extern u_int32_t	http_request_ms;
    349 extern u_int64_t	http_hsts_enable;
    350 extern u_int16_t	http_keepalive_time;
    351 extern u_int32_t	http_request_limit;
    352 extern u_int32_t	http_request_count;
    353 extern u_int64_t	http_body_disk_offload;
    354 extern int		http_pretty_error;
    355 extern char		*http_body_disk_path;
    356 extern struct kore_pool	http_header_pool;
    357 
    358 void		kore_accesslog(struct http_request *);
    359 
    360 void		http_init(void);
    361 void		http_parent_init(void);
    362 void		http_cleanup(void);
    363 void 		http_server_version(const char *);
    364 void		http_process(void);
    365 const char	*http_status_text(int);
    366 const char	*http_method_text(int);
    367 time_t		http_date_to_time(char *);
    368 char		*http_validate_header(char *);
    369 int		http_method_value(const char *);
    370 void		http_start_recv(struct connection *);
    371 void		http_request_free(struct http_request *);
    372 void		http_request_sleep(struct http_request *);
    373 void		http_request_wakeup(struct http_request *);
    374 void		http_process_request(struct http_request *);
    375 int		http_body_rewind(struct http_request *);
    376 int		http_media_register(const char *, const char *);
    377 int		http_check_timeout(struct connection *, u_int64_t);
    378 ssize_t		http_body_read(struct http_request *, void *, size_t);
    379 int		http_body_digest(struct http_request *, char *, size_t);
    380 
    381 int		http_redirect_add(struct kore_domain *,
    382 		    const char *, int, const char *);
    383 void		http_response(struct http_request *, int, const void *, size_t);
    384 void		http_response_json(struct http_request *, int,
    385 		    struct kore_json_item *);
    386 void		http_response_close(struct http_request *, int,
    387 		    const void *, size_t);
    388 void		http_response_fileref(struct http_request *, int,
    389 		    struct kore_fileref *);
    390 void		http_serveable(struct http_request *, const void *,
    391 		    size_t, const char *, const char *);
    392 void		http_response_stream(struct http_request *, int, void *,
    393 		    size_t, int (*cb)(struct netbuf *), void *);
    394 int		http_request_header(struct http_request *,
    395 		    const char *, const char **);
    396 void		http_response_header(struct http_request *,
    397 		    const char *, const char *);
    398 int		http_state_run(struct http_state *, u_int8_t,
    399 		    struct http_request *);
    400 int	 	http_request_cookie(struct http_request *,
    401 		    const char *, char **);
    402 void		http_response_cookie(struct http_request *, const char *,
    403 		    const char *, const char *, time_t, u_int32_t,
    404 		    struct http_cookie **);
    405 
    406 void		http_runlock_init(struct http_runlock *);
    407 void		http_runlock_release(struct http_runlock *,
    408 		    struct http_request *);
    409 int		http_runlock_acquire(struct http_runlock *,
    410 		    struct http_request *);
    411 
    412 const char	*http_media_type(const char *);
    413 void		*http_state_get(struct http_request *);
    414 int		http_state_exists(struct http_request *);
    415 void		http_state_cleanup(struct http_request *);
    416 void		*http_state_create(struct http_request *, size_t);
    417 
    418 int		http_argument_urldecode(char *);
    419 int		http_header_recv(struct netbuf *);
    420 void		http_populate_qs(struct http_request *);
    421 void		http_populate_post(struct http_request *);
    422 void		http_populate_multipart_form(struct http_request *);
    423 void		http_populate_cookies(struct http_request *);
    424 int		http_argument_get(struct http_request *,
    425 		    const char *, void **, void *, int);
    426 int		http_request_header_get(struct http_request *,
    427 		    const char *, void **, void *, int);
    428 
    429 void			http_file_rewind(struct http_file *);
    430 ssize_t			http_file_read(struct http_file *, void *, size_t);
    431 struct http_file	*http_file_lookup(struct http_request *, const char *);
    432 
    433 enum http_status_code {
    434 	HTTP_STATUS_CONTINUE			= 100,
    435 	HTTP_STATUS_SWITCHING_PROTOCOLS		= 101,
    436 	HTTP_STATUS_OK				= 200,
    437 	HTTP_STATUS_CREATED			= 201,
    438 	HTTP_STATUS_ACCEPTED			= 202,
    439 	HTTP_STATUS_NON_AUTHORITATIVE		= 203,
    440 	HTTP_STATUS_NO_CONTENT			= 204,
    441 	HTTP_STATUS_RESET_CONTENT		= 205,
    442 	HTTP_STATUS_PARTIAL_CONTENT		= 206,
    443 	HTTP_STATUS_MULTIPLE_CHOICES		= 300,
    444 	HTTP_STATUS_MOVED_PERMANENTLY		= 301,
    445 	HTTP_STATUS_FOUND			= 302,
    446 	HTTP_STATUS_SEE_OTHER			= 303,
    447 	HTTP_STATUS_NOT_MODIFIED		= 304,
    448 	HTTP_STATUS_USE_PROXY			= 305,
    449 	HTTP_STATUS_TEMPORARY_REDIRECT		= 307,
    450 	HTTP_STATUS_BAD_REQUEST			= 400,
    451 	HTTP_STATUS_UNAUTHORIZED		= 401,
    452 	HTTP_STATUS_PAYMENT_REQUIRED		= 402,
    453 	HTTP_STATUS_FORBIDDEN			= 403,
    454 	HTTP_STATUS_NOT_FOUND			= 404,
    455 	HTTP_STATUS_METHOD_NOT_ALLOWED		= 405,
    456 	HTTP_STATUS_NOT_ACCEPTABLE		= 406,
    457 	HTTP_STATUS_PROXY_AUTH_REQUIRED		= 407,
    458 	HTTP_STATUS_REQUEST_TIMEOUT		= 408,
    459 	HTTP_STATUS_CONFLICT			= 409,
    460 	HTTP_STATUS_GONE			= 410,
    461 	HTTP_STATUS_LENGTH_REQUIRED		= 411,
    462 	HTTP_STATUS_PRECONDITION_FAILED		= 412,
    463 	HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE	= 413,
    464 	HTTP_STATUS_REQUEST_URI_TOO_LARGE	= 414,
    465 	HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE	= 415,
    466 	HTTP_STATUS_REQUEST_RANGE_INVALID	= 416,
    467 	HTTP_STATUS_EXPECTATION_FAILED		= 417,
    468 	HTTP_STATUS_MISDIRECTED_REQUEST		= 421,
    469 	HTTP_STATUS_INTERNAL_ERROR		= 500,
    470 	HTTP_STATUS_NOT_IMPLEMENTED		= 501,
    471 	HTTP_STATUS_BAD_GATEWAY			= 502,
    472 	HTTP_STATUS_SERVICE_UNAVAILABLE		= 503,
    473 	HTTP_STATUS_GATEWAY_TIMEOUT		= 504,
    474 	HTTP_STATUS_BAD_VERSION			= 505
    475 };
    476 #if defined(__cplusplus)
    477 }
    478 #endif
    479 #endif /* !__H_HTTP_H */
    480 
    481 #endif /* ! KORE_NO_HTTP */