/* * Copyright (c) 2016 Lammert Bies * Copyright (c) 2013-2016 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef LIBHTTP_HEADER_INCLUDED #define LIBHTTP_HEADER_INCLUDED #define LIBHTTP_VERSION "1.9" #ifndef UNUSED_PARAMETER #define UNUSED_PARAMETER(x) (void)(x) #endif /* UNUSED_PARAMETER */ #ifndef LIBHTTP_API #if defined(_WIN32) #if defined(LIBHTTP_DLL_EXPORTS) #define LIBHTTP_API __declspec(dllexport) #elif defined(LIBHTTP_DLL_IMPORTS) #define LIBHTTP_API __declspec(dllimport) #else #define LIBHTTP_API #endif #elif __GNUC__ >= 4 #define LIBHTTP_API __attribute__((visibility("default"))) #else #define LIBHTTP_API #endif #endif /* LIBHTTP_API */ #ifndef LIBHTTP_THREAD #if defined(_WIN32) #define LIBHTTP_THREAD unsigned __stdcall #define LIBHTTP_THREAD_TYPE unsigned #define LIBHTTP_THREAD_CALLING_CONV __stdcall #define LIBHTTP_THREAD_RETNULL 0 #else /* _WIN32 */ #define LIBHTTP_THREAD void * #define LIBHTTP_THREAD_TYPE void * #define LIBHTTP_THREAD_CALLING_CONV #define LIBHTTP_THREAD_RETNULL NULL #endif /* _WIN32 */ #endif /* LIBHTTP_THREAD */ #include #include #include #include #include #if defined(_WIN32) #include #include #endif /* _WIN32 */ /* * For our Posix emulation functions to open and close directories we need * to know the path length. If this length is not set yet, we set it here based * on an educated guess. */ #if !defined(PATH_MAX) #define PATH_MAX (MAX_PATH) #endif /* PATH_MAX */ #if !defined(PATH_MAX) #define PATH_MAX (4096) #endif /* PATH_MAX */ #if defined(_WIN32) /* * The OS does not support Posix calls, but we need some of them for the * library to function properly. We therefore define some items which makes * life easier in the multiple target world. */ #define SIGKILL (0) typedef HANDLE pthread_t; typedef HANDLE pthread_mutex_t; typedef DWORD pthread_key_t; typedef void pthread_condattr_t; typedef void pthread_mutexattr_t; typedef struct { CRITICAL_SECTION threadIdSec; struct httplib_workerTLS * waiting_thread; /* The chain of threads */ } pthread_cond_t; #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */ #else /* _WIN32 */ /* * For Posix compliant systems we need to read some include files where * definitions, structures and prototypes are present. */ #include #include #include #include #include #endif /* _WIN32 */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #if defined(_WIN32) /* * In Windows we emulate the Posix directory functions to make the OS dependent * code on the application side as small as possible. */ struct dirent { char d_name[PATH_MAX]; }; typedef struct DIR { HANDLE handle; WIN32_FIND_DATAW info; struct dirent result; } DIR; #endif /* _WIN32 */ #if defined(_WIN32) && !defined(POLLIN) /* * If we are on Windows without poll(), we emulate this Posix function. */ #ifndef HAVE_POLL struct pollfd { SOCKET fd; short events; short revents; }; #define POLLIN (0x0300) #endif /* HAVE_POLL */ #endif /* _WIN32 && ! POLLIN */ /* * Macros for enabling compiler-specific checks for printf-like arguments. */ #undef PRINTF_FORMAT_STRING #if defined(_MSC_VER) && _MSC_VER >= 1400 #include #if defined(_MSC_VER) && _MSC_VER > 1400 #define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s #else #define PRINTF_FORMAT_STRING(s) __format_string s #endif #else #define PRINTF_FORMAT_STRING(s) s #endif #ifdef __GNUC__ #define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y))) #else #define PRINTF_ARGS(x, y) #endif /************************************************************************************************/ /* */ /* enum lh_dbg_t; */ /* */ /* Error messages are generated depending on the debug level of a context. Different contexts */ /* can have different debug levels allowing an application to only generate debug messages of */ /* specific servers or client connections. */ enum lh_dbg_t { /* */ LH_DEBUG_NONE = 0x00, /* No error messages are generated at all */ LH_DEBUG_CRASH = 0x10, /* Messages for errors impacting multiple connections in a severe way are generated */ LH_DEBUG_ERROR = 0x20, /* Messages for errors impacting single connections in a severe way are generated (default) */ LH_DEBUG_WARNING = 0x30, /* Messages for errors impacting single connections in a minor way are generated */ LH_DEBUG_INFO = 0x40 /* All error, warning and informational messages are generated */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* Return values definition for the "field_found" callback in httplib_form_data_handler. */ enum { /* */ FORM_FIELD_STORAGE_SKIP = 0x00, /* Skip this field (neither get nor store it). Continue with the next field. */ FORM_FIELD_STORAGE_GET = 0x01, /* Get the field value. */ FORM_FIELD_STORAGE_STORE = 0x02, /* Store the field value into a file. */ FORM_FIELD_STORAGE_ABORT = 0x10 /* Stop parsing this request. Skip the remaining fields */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* Opcodes, from http://tools.ietf.org/html/rfc6455 */ enum { /* */ WEBSOCKET_OPCODE_CONTINUATION = 0x00, /* */ WEBSOCKET_OPCODE_TEXT = 0x01, /* */ WEBSOCKET_OPCODE_BINARY = 0x02, /* */ WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x08, /* */ WEBSOCKET_OPCODE_PING = 0x09, /* */ WEBSOCKET_OPCODE_PONG = 0x0A /* */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct lh_ctx_t; */ /* struct lh_con_t; */ /* struct lh_ip_t; */ /* */ /* Hidden structures used by the library to store context and connection information */ /* */ struct lh_ctx_t; /* Handle for an HTTP context */ struct lh_con_t; /* Handle for an individual connection */ struct lh_ip_t; /* Handle for an IPv4/IPv6 ip address */ /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct client_cert; */ /* */ /* Client certificate information (part of lh_rqi_t) */ struct client_cert { /* */ const char *subject; /* Subject of the certificate */ const char *issuer; /* Issuer of the certificate */ const char *serial; /* Serial number of the certificate */ const char *finger; /* Finger print of the certificate */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct lh_rqi_t; */ /* */ /* This structure contains information about the HTTP request. */ struct lh_rqi_t { /* */ const char * request_method; /* "GET", "POST", etc */ const char * request_uri; /* URL-decoded URI (absolute or relative, as in the request) */ const char * local_uri; /* URL-decoded URI (relative). Can be NULL if request_uri is not a resource at the server host */ const char * uri; /* Deprecated: use local_uri instead */ const char * http_version; /* E.g. "1.0", "1.1" */ const char * query_string; /* URL part after '?', not including '?', or NULL */ const char * remote_user; /* Authenticated user, or NULL if no auth used */ char remote_addr[48]; /* Client's IP address as a string. */ int64_t content_length; /* Length (in bytes) of the request body, can be -1 if no length was given. */ int remote_port; /* Client's port */ bool has_ssl; /* 1 if SSL-ed, 0 if not */ void * user_data; /* User data pointer passed to httplib_start() */ void * conn_data; /* Connection-specific user data */ int num_headers; /* Number of HTTP headers */ struct httplib_header { /* */ const char *name; /* HTTP header name */ const char *value; /* HTTP header value */ } http_headers[64]; /* Maximum 64 headers */ struct client_cert * client_cert; /* Client certificate information */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct lh_clb_t; */ /* */ /* This structure needs to be passed to httplib_start(), to let LibHTTP know which callbacks to */ /* invoke. For a detailed description, see */ /* https://github.com/lammertb/libhttp/blob/master/docs/UserManual.md */ struct lh_clb_t { /* */ int (*begin_request)( struct lh_ctx_t *ctx, struct lh_con_t *conn ); /* */ void (*end_request)( struct lh_ctx_t *ctx, const struct lh_con_t *conn, int reply_status_code ); /* */ int (*log_message)( struct lh_ctx_t *ctx, const struct lh_con_t *conn, const char *message ); /* */ int (*log_access)( struct lh_ctx_t *ctx, const struct lh_con_t *conn, const char *message ); /* */ int (*init_ssl)( struct lh_ctx_t *ctx, void *ssl_context, void *user_data ); /* */ void (*connection_close)( struct lh_ctx_t *ctx, const struct lh_con_t *conn ); /* */ const char * (*open_file)( struct lh_ctx_t *ctx, const struct lh_con_t *conn, const char *path, size_t *data_len ); /* */ void (*init_lua)( struct lh_ctx_t *ctx, const struct lh_con_t *conn, void *lua_context ); /* */ int (*http_error)( struct lh_ctx_t *ctx, struct lh_con_t *, int status ); /* */ void (*init_context)( struct lh_ctx_t *ctx ); /* */ void (*init_thread)( struct lh_ctx_t *ctx, int thread_type ); /* */ void (*exit_context)( struct lh_ctx_t *ctx ); /* */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct lh_opt_t; */ /* */ /* Option record passed in an array of option records when a context is created */ struct lh_opt_t { /* */ const char * name; /* name of the option used when creating a context */ const char * value; /* value of the option */ }; /* */ /************************************************************************************************/ /************************************************************************************************/ /* */ /* struct lh_slp_t */ /* */ /* Record of a port a server is listening on */ struct lh_slp_t { /* */ int protocol; /* The protocol supported by the port: 1 = IPv4, 2 = IPv6, 3 = both */ int port; /* The port number the server is listening on */ bool has_ssl; /* Does this port support https encryption: false = no, true = yes */ bool has_redirect; /* redirect all requests to a https connection false = no, true = yes */ }; /* */ /************************************************************************************************/ /* * This structure contains callback functions for handling form fields. * It is used as an argument to httplib_handle_form_request. */ struct httplib_form_data_handler { int (*field_found)( const char *key, const char *filename, char *path, size_t pathlen, void *user_data ); int (*field_get)( const char *key, const char *value, size_t valuelen, void *user_data ); int (*field_store)( const char *path, int64_t file_size, void *user_data ); void * user_data; }; typedef int (*httplib_request_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, void *cbdata ); typedef int (*httplib_authorization_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, void *cbdata ); typedef int (*httplib_websocket_connect_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, void *cbdata ); typedef void (*httplib_websocket_ready_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, void *cbdata ); typedef int (*httplib_websocket_data_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, int, char *buffer, size_t buflen, void *cbdata ); typedef void (*httplib_websocket_close_handler)( struct lh_ctx_t *ctx, struct lh_con_t *conn, void *cbdata ); typedef LIBHTTP_THREAD_TYPE (LIBHTTP_THREAD_CALLING_CONV *httplib_thread_func_t)(void *arg); struct httplib_client_options { const char *host; int port; const char *client_cert; const char *server_cert; /* TODO: add more data */ }; enum { TIMEOUT_INFINITE = -1 }; typedef void (*httplib_alloc_callback_func)( const char *file, unsigned line, const char *action, int64_t current_bytes, int64_t total_blocks, int64_t total_bytes ); #define httplib_calloc(a, b) XX_httplib_calloc_ex(a, b, __FILE__, __LINE__) #define httplib_free(a) XX_httplib_free_ex(a, __FILE__, __LINE__) #define httplib_malloc(a) XX_httplib_malloc_ex(a, __FILE__, __LINE__) #define httplib_realloc(a, b) XX_httplib_realloc_ex(a, b, __FILE__, __LINE__) LIBHTTP_API void * XX_httplib_calloc_ex( size_t count, size_t size, const char *file, unsigned line ); LIBHTTP_API void * XX_httplib_free_ex( void *memory, const char *file, unsigned line ); LIBHTTP_API void * XX_httplib_malloc_ex( size_t size, const char *file, unsigned line ); LIBHTTP_API void * XX_httplib_realloc_ex( void *memory, size_t newsize, const char *file, unsigned line ); LIBHTTP_API int httplib_atomic_dec( volatile int *addr ); LIBHTTP_API int httplib_atomic_inc( volatile int *addr ); LIBHTTP_API int httplib_base64_encode( const unsigned char *src, int src_len, char *dst, int dst_len ); LIBHTTP_API unsigned httplib_check_feature( unsigned feature ); LIBHTTP_API void httplib_close_connection( struct lh_ctx_t *ctx, struct lh_con_t *conn ); LIBHTTP_API int httplib_closedir( DIR *dir ); LIBHTTP_API struct lh_con_t * httplib_connect_client( struct lh_ctx_t *ctx, const char *host, int port, int use_ssl ); LIBHTTP_API struct lh_con_t * httplib_connect_client_secure( struct lh_ctx_t *ctx, const struct httplib_client_options *client_options ); LIBHTTP_API struct lh_con_t * httplib_connect_websocket_client( struct lh_ctx_t *ctx, const char *host, int port, int use_ssl, const char *path, const char *origin, httplib_websocket_data_handler data_func, httplib_websocket_close_handler close_func, void *user_data ); LIBHTTP_API struct lh_ctx_t * httplib_create_client_context( const struct lh_clb_t *callbacks, const struct lh_opt_t *options ); LIBHTTP_API void httplib_cry( enum lh_dbg_t debug_level, struct lh_ctx_t *ctx, const struct lh_con_t *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(4, 5); LIBHTTP_API void httplib_destroy_client_context( struct lh_ctx_t *ctx ); LIBHTTP_API struct lh_con_t * httplib_download( struct lh_ctx_t *ctx, const char *host, int port, int use_ssl, PRINTF_FORMAT_STRING(const char *request_fmt), ...) PRINTF_ARGS(5, 6); LIBHTTP_API char * httplib_error_string( int error_code, char *buf, size_t buf_len ); LIBHTTP_API const char * httplib_get_builtin_mime_type( const char *file_name ); LIBHTTP_API int httplib_get_cookie( const char *cookie, const char *var_name, char *buf, size_t buf_len ); LIBHTTP_API enum lh_dbg_t httplib_get_debug_level( struct lh_ctx_t *ctx ); LIBHTTP_API const char * httplib_get_header( const struct lh_con_t *conn, const char *name ); LIBHTTP_API const char * httplib_get_option( const struct lh_ctx_t *ctx, const char *name, char *buffer, size_t buflen ); LIBHTTP_API uint64_t httplib_get_random( void ); LIBHTTP_API const struct lh_rqi_t * httplib_get_request_info( const struct lh_con_t *conn ); LIBHTTP_API int httplib_get_response( const struct lh_ctx_t *ctx, struct lh_con_t *conn, int timeout ); LIBHTTP_API const char * httplib_get_response_code_text( struct lh_ctx_t *ctx, struct lh_con_t *conn, int response_code ); LIBHTTP_API int httplib_get_server_ports( const struct lh_ctx_t *ctx, int size, struct lh_slp_t *ports ); LIBHTTP_API void * httplib_get_user_connection_data( const struct lh_con_t *conn ); LIBHTTP_API void * httplib_get_user_data( const struct lh_ctx_t *ctx ); LIBHTTP_API int httplib_get_var( const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len ); LIBHTTP_API int httplib_get_var2( const char *data, size_t data_len, const char *var_name, char *dst, size_t dst_len, size_t occurrence ); LIBHTTP_API struct tm * httplib_gmtime_r( const time_t *clock, struct tm *result ); LIBHTTP_API int httplib_handle_form_request( struct lh_ctx_t *ctx, struct lh_con_t *conn, struct httplib_form_data_handler *fdh ); LIBHTTP_API int httplib_kill( pid_t pid, int sig_num ); LIBHTTP_API struct tm * httplib_localtime_r( const time_t *clock, struct tm *result ); LIBHTTP_API void httplib_lock_connection( struct lh_con_t *conn ); LIBHTTP_API void httplib_lock_context( struct lh_ctx_t *ctx ); LIBHTTP_API char * httplib_md5( char buf[33], ... ); LIBHTTP_API int httplib_mkdir( const char *path, int mode ); LIBHTTP_API int httplib_modify_passwords_file( const char *passwords_file_name, const char *domain, const char *user, const char *password ); LIBHTTP_API DIR * httplib_opendir( const char *name ); LIBHTTP_API int httplib_poll( struct pollfd *pfd, unsigned int nfds, int timeout ); LIBHTTP_API int httplib_printf( const struct lh_ctx_t *ctx, struct lh_con_t *conn, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4); LIBHTTP_API int httplib_pthread_cond_broadcast( pthread_cond_t *cv ); LIBHTTP_API int httplib_pthread_cond_destroy( pthread_cond_t *cv ); LIBHTTP_API int httplib_pthread_cond_init( pthread_cond_t *cv, const pthread_condattr_t *attr ); LIBHTTP_API int httplib_pthread_cond_signal( pthread_cond_t *cv ); LIBHTTP_API int httplib_pthread_cond_timedwait( pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec *abstime ); LIBHTTP_API int httplib_pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mutex ); LIBHTTP_API void * httplib_pthread_getspecific( pthread_key_t key ); LIBHTTP_API int httplib_pthread_join( pthread_t thread, void **value_ptr ); LIBHTTP_API int httplib_pthread_key_create( pthread_key_t *key, void (*destructor)(void *) ); LIBHTTP_API int httplib_pthread_key_delete( pthread_key_t key ); LIBHTTP_API int httplib_pthread_mutex_destroy( pthread_mutex_t *mutex ); LIBHTTP_API int httplib_pthread_mutex_init( pthread_mutex_t *mutex, const pthread_mutexattr_t *attr ); LIBHTTP_API int httplib_pthread_mutex_lock( pthread_mutex_t *mutex ); LIBHTTP_API int httplib_pthread_mutex_trylock( pthread_mutex_t *mutex ); LIBHTTP_API int httplib_pthread_mutex_unlock( pthread_mutex_t *mutex ); LIBHTTP_API pthread_t httplib_pthread_self( void ); LIBHTTP_API int httplib_pthread_setspecific( pthread_key_t key, void *value ); LIBHTTP_API int httplib_read( const struct lh_ctx_t *ctx, struct lh_con_t *conn, void *buf, size_t len ); LIBHTTP_API struct dirent * httplib_readdir( DIR *dir ); LIBHTTP_API int httplib_remove( const char *path ); LIBHTTP_API void httplib_send_file( struct lh_ctx_t *ctx, struct lh_con_t *conn, const char *path, const char *mime_type, const char *additional_headers ); LIBHTTP_API void httplib_set_alloc_callback_func( httplib_alloc_callback_func log_func ); LIBHTTP_API void httplib_set_auth_handler( struct lh_ctx_t *ctx, const char *uri, httplib_authorization_handler handler, void *cbdata ); LIBHTTP_API enum lh_dbg_t httplib_set_debug_level( struct lh_ctx_t *ctx, enum lh_dbg_t new_level ); LIBHTTP_API void httplib_set_request_handler( struct lh_ctx_t *ctx, const char *uri, httplib_request_handler handler, void *cbdata ); LIBHTTP_API void httplib_set_user_connection_data( struct lh_con_t *conn, void *data ); LIBHTTP_API void httplib_set_websocket_handler( struct lh_ctx_t *ctx, const char *uri, httplib_websocket_connect_handler connect_handler, httplib_websocket_ready_handler ready_handler, httplib_websocket_data_handler data_handler, httplib_websocket_close_handler close_handler, void *cbdata ); LIBHTTP_API struct lh_ctx_t * httplib_start( const struct lh_clb_t *callbacks, void *user_data, const struct lh_opt_t *options ); LIBHTTP_API int httplib_start_thread( httplib_thread_func_t func, void *param ); LIBHTTP_API void httplib_stop( struct lh_ctx_t *ctx ); LIBHTTP_API int64_t httplib_store_body( struct lh_ctx_t *ctx, struct lh_con_t *conn, const char *path ); LIBHTTP_API int httplib_strcasecmp( const char *s1, const char *s2 ); LIBHTTP_API const char * httplib_strcasestr( const char *big_str, const char *small_str ); LIBHTTP_API char * httplib_strdup( const char *str ); LIBHTTP_API void httplib_strlcpy( char *dst, const char *src, size_t len ); LIBHTTP_API int httplib_strncasecmp( const char *s1, const char *s2, size_t len ); LIBHTTP_API char * httplib_strndup( const char *str, size_t len ); LIBHTTP_API int httplib_system_exit( void ); LIBHTTP_API int httplib_system_init( void ); LIBHTTP_API void httplib_unlock_connection( struct lh_con_t *conn ); LIBHTTP_API void httplib_unlock_context( struct lh_ctx_t *ctx ); LIBHTTP_API int httplib_url_decode( const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded ); LIBHTTP_API int httplib_url_encode( const char *src, char *dst, size_t dst_len ); LIBHTTP_API const char * httplib_version( void ); LIBHTTP_API int httplib_websocket_client_write( struct lh_ctx_t *ctx, struct lh_con_t *conn, int opcode, const char *data, size_t data_len ); LIBHTTP_API int httplib_websocket_write( const struct lh_ctx_t *ctx, struct lh_con_t *conn, int opcode, const char *data, size_t data_len ); LIBHTTP_API int httplib_write( const struct lh_ctx_t *ctx, struct lh_con_t * conn, const void *buf, size_t len ); LIBHTTP_API char * lh_ipt_to_up( const struct lh_ip_t *in, char *buffwe, size_t buflen, bool compress, bool hybrid ); LIBHTTP_API char * lh_ipt_to_ip4( const struct lh_ip_t *in, char *buffer, size_t buflen, bool hybrid ); LIBHTTP_API char * lh_ipt_to_ip6( const struct lh_ip_t *in, char *buffer, size_t buflen, bool compress ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* LIBHTTP_HEADER_INCLUDED */