| /* |
| Copyright: Boaz segev, 2016-2017 |
| License: MIT |
| |
| Feel free to copy, use and enjoy according to the license provided. |
| */ |
| #ifndef H_HTTP_INTERNAL_H |
| #define H_HTTP_INTERNAL_H |
| |
| #include "http.h" |
| |
| #include "fiobj4sock.h" |
| |
| #include <arpa/inet.h> |
| #include <errno.h> |
| |
| /* ***************************************************************************** |
| Types |
| ***************************************************************************** */ |
| |
| typedef struct http_protocol_s http_protocol_s; |
| typedef struct http_vtable_s http_vtable_s; |
| |
| struct http_vtable_s { |
| /** Should send existing headers and data */ |
| int (*const http_send_body)(http_s *h, void *data, uintptr_t length); |
| /** Should send existing headers and file */ |
| int (*const http_sendfile)(http_s *h, int fd, uintptr_t length, |
| uintptr_t offset); |
| /** Should send existing headers and data and prepare for streaming */ |
| int (*const http_stream)(http_s *h, void *data, uintptr_t length); |
| /** Should send existing headers or complete streaming */ |
| void (*const http_finish)(http_s *h); |
| /** Push for data. */ |
| int (*const http_push_data)(http_s *h, void *data, uintptr_t length, |
| FIOBJ mime_type); |
| /** Push for files. */ |
| int (*const http_push_file)(http_s *h, FIOBJ filename, FIOBJ mime_type); |
| /** Defer request handling for later... careful (memory concern apply). */ |
| int (*const http_defer)(http_s *h, void (*task)(http_s *h), |
| void (*fallback)(http_s *h)); |
| /** Defer request handling for later... careful (memory concern apply). */ |
| int (*const http2websocket)(websocket_settings_s *arg); |
| }; |
| |
| struct http_protocol_s { |
| protocol_s protocol; |
| intptr_t uuid; |
| http_settings_s *settings; |
| http_vtable_s *vtable; |
| }; |
| |
| #define http2protocol(h) ((http_protocol_s *)h->private_data.owner) |
| |
| /* ***************************************************************************** |
| Constants that shouldn't be accessed by the users (`fiobj_dup` required). |
| ***************************************************************************** |
| */ |
| |
| extern FIOBJ HTTP_HEADER_ACCEPT_RANGES; |
| extern FIOBJ HTTP_HEADER_WS_SEC_KEY; |
| extern FIOBJ HTTP_HVALUE_BYTES; |
| extern FIOBJ HTTP_HVALUE_CLOSE; |
| extern FIOBJ HTTP_HVALUE_GZIP; |
| extern FIOBJ HTTP_HVALUE_KEEP_ALIVE; |
| extern FIOBJ HTTP_HVALUE_MAX_AGE; |
| extern FIOBJ HTTP_HVALUE_WEBSOCKET; |
| extern FIOBJ HTTP_HVALUE_WS_SEC_VERSION; |
| extern FIOBJ HTTP_HVALUE_WS_UPGRADE; |
| extern FIOBJ HTTP_HVALUE_WS_VERSION; |
| |
| /* ***************************************************************************** |
| HTTP request/response object management |
| ***************************************************************************** |
| */ |
| |
| static inline void http_s_init(http_s *h, http_protocol_s *owner) { |
| *h = (http_s){ |
| .private_data.owner = (protocol_s *)owner, |
| .private_data.request_id = 1, |
| .private_data.out_headers = fiobj_hash_new(), |
| .headers = fiobj_hash_new(), |
| .version = h->version, |
| .received_at = facil_last_tick(), |
| .status = 200, |
| .udata = owner->settings->udata, |
| }; |
| } |
| |
| static inline void http_s_cleanup(http_s *h) { |
| if (h->status && http2protocol(h) && http2protocol(h)->settings->log) |
| http_write_log(h); |
| fiobj_free(h->method); /* union for fiobj_free(r->status_str); */ |
| fiobj_free(h->private_data.out_headers); |
| fiobj_free(h->headers); |
| fiobj_free(h->version); |
| fiobj_free(h->query); |
| fiobj_free(h->path); |
| fiobj_free(h->cookies); |
| fiobj_free(h->body); |
| fiobj_free(h->params); |
| |
| *h = (http_s){.private_data.owner = h->private_data.owner}; |
| } |
| |
| /** Use this function to handle HTTP requests.*/ |
| void http_on_request_handler______internal(http_s *h, |
| http_settings_s *settings); |
| |
| int http_send_error2(size_t error, intptr_t uuid, http_settings_s *settings); |
| |
| /* ***************************************************************************** |
| Helpers |
| ***************************************************************************** */ |
| |
| #define HTTP_ASSERT(x, m) \ |
| if (!x) \ |
| perror("FATAL ERROR: (http)" m), exit(errno); |
| |
| /** sets an outgoing header only if it doesn't exist */ |
| static inline void set_header_if_missing(FIOBJ hash, FIOBJ name, FIOBJ value) { |
| FIOBJ old = fiobj_hash_replace(hash, name, value); |
| if (!old) |
| return; |
| fiobj_hash_replace(hash, name, old); |
| fiobj_free(value); |
| } |
| |
| /** sets an outgoing header, collecting duplicates in an Array (i.e. cookies) |
| */ |
| static inline void set_header_add(FIOBJ hash, FIOBJ name, FIOBJ value) { |
| FIOBJ old = fiobj_hash_replace(hash, name, value); |
| if (!old) |
| return; |
| if (!value) { |
| fiobj_free(old); |
| return; |
| } |
| if (old->type != FIOBJ_T_ARRAY) { |
| FIOBJ tmp = fiobj_ary_new(); |
| fiobj_ary_push(tmp, old); |
| old = tmp; |
| } |
| fiobj_ary_push(old, value); |
| fiobj_hash_replace(hash, name, old); |
| } |
| |
| #endif /* H_HTTP_INTERNAL_H */ |