diff --git a/patches/libwebsockets.patch b/patches/libwebsockets.patch new file mode 100644 index 0000000..3369046 --- /dev/null +++ b/patches/libwebsockets.patch @@ -0,0 +1,22 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 888f65e8..50198586 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -780,7 +780,7 @@ endif() + # top of the build tree rather than in hard-to-find leaf directories. + SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") + SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") +-SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") ++#SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") + + SET(LWS_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}") + +@@ -1853,7 +1853,7 @@ endif(LWS_WITH_LIBEV) + if (LWS_WITH_LIBUV) + if (NOT LIBUV_FOUND) + find_path(LIBUV_INCLUDE_DIRS NAMES uv.h) +- find_library(LIBUV_LIBRARIES NAMES uv) ++ find_library(LIBUV_LIBRARIES NAMES uv_a) + if(LIBUV_INCLUDE_DIRS AND LIBUV_LIBRARIES) + set(LIBUV_FOUND 1) + endif() diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..75b0fe6 --- /dev/null +++ b/src/main.c @@ -0,0 +1,188 @@ +/* + * lws-minimal-http-server-eventlib + * + * Written in 2010-2019 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates a minimal http[s] server that can work with any of the + * supported event loop backends, or the default poll() one. + * + * To keep it simple, it serves stuff from the subdirectory + * "./mount-origin" of the directory it was started in. + * You can change that by changing mount.origin below. + */ + +#include +#include +#include + +#define LWS_PLUGIN_STATIC +#include "./plugins/protocol_lws_mirror.c" +#include "./plugins/protocol_lws_status.c" +#include "./plugins/protocol_dumb_increment.c" +#include "./plugins/protocol_post_demo.c" + +static struct lws_context *context; + +static struct lws_protocols protocols[] = { + /* first protocol must always be HTTP handler */ + + { "http-only", lws_callback_http_dummy, 0, 0, }, + LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT, + LWS_PLUGIN_PROTOCOL_MIRROR, + LWS_PLUGIN_PROTOCOL_LWS_STATUS, + LWS_PLUGIN_PROTOCOL_POST_DEMO, + { NULL, NULL, 0, 0 } /* terminator */ +}; + +/* + * mount handlers for sections of the URL space + */ + +static const struct lws_http_mount mount_ziptest = { + NULL, /* linked-list pointer to next*/ + "/ziptest", /* mountpoint in URL namespace on this vhost */ + "candide.zip", /* handler */ + NULL, /* default filename if none given */ + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_FILE, /* origin points to a callback */ + 8, /* strlen("/ziptest"), ie length of the mountpoint */ + NULL, + + { NULL, NULL } // sentinel +}; + +static const struct lws_http_mount mount_post = { + (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ + "/formtest", /* mountpoint in URL namespace on this vhost */ + "protocol-post-demo", /* handler */ + NULL, /* default filename if none given */ + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + LWSMPRO_CALLBACK, /* origin points to a callback */ + 9, /* strlen("/formtest"), ie length of the mountpoint */ + NULL, + + { NULL, NULL } // sentinel +}; + + +static const struct lws_http_mount mount = { + /* .mount_next */ &mount_post, /* linked-list "next" */ + /* .mountpoint */ "/", /* mountpoint URL */ + /* .origin */ "./mount-origin", /* serve from dir */ + /* .def */ "test.html", /* default filename */ + /* .protocol */ NULL, + /* .cgienv */ NULL, + /* .extra_mimetypes */ NULL, + /* .interpret */ NULL, + /* .cgi_timeout */ 0, + /* .cache_max_age */ 0, + /* .auth_mask */ 0, + /* .cache_reusable */ 0, + /* .cache_revalidate */ 0, + /* .cache_intermediaries */ 0, + /* .origin_protocol */ LWSMPRO_FILE, /* files in a dir */ + /* .mountpoint_len */ 1, /* char count */ + /* .basic_auth_login_file */ NULL, +}; + +void signal_cb(void *handle, int signum) +{ + lwsl_err("%s: signal %d\n", __func__, signum); + + switch (signum) { + case SIGTERM: + case SIGINT: + break; + default: + + break; + } + lws_context_destroy(context); +} + +void sigint_handler(int sig) +{ + signal_cb(NULL, sig); +} + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + const char *p; + int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE + /* for LLL_ verbosity above NOTICE to be built into lws, + * lws must have been configured and built with + * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */ + /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */ + /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */ + /* | LLL_DEBUG */; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal http server eventlib | visit http://localhost:7681\n"); + lwsl_user(" [-s (ssl)] [--uv (libuv)] [--ev (libev)] [--event (libevent)]\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = 7681; + info.mounts = &mount; + info.error_document_404 = "/404.html"; + info.pcontext = &context; + info.protocols = protocols; + info.signal_cb = signal_cb; + info.options = + LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; + + if (lws_cmdline_option(argc, argv, "-s")) { + info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.ssl_cert_filepath = "localhost-100y.cert"; + info.ssl_private_key_filepath = "localhost-100y.key"; + } + + if (lws_cmdline_option(argc, argv, "--uv")) + info.options |= LWS_SERVER_OPTION_LIBUV; + else + if (lws_cmdline_option(argc, argv, "--event")) + info.options |= LWS_SERVER_OPTION_LIBEVENT; + else + if (lws_cmdline_option(argc, argv, "--ev")) + info.options |= LWS_SERVER_OPTION_LIBEV; + else + signal(SIGINT, sigint_handler); + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (!lws_service(context, 0)) + ; + + lwsl_info("calling external context destroy\n"); + lws_context_destroy(context); + + return 0; +} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 4291b1d..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * main.cpp - * - * Copyright (c) 2015-2019, NADAL Jean-Baptiste. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * @Author: NADAL Jean-Baptiste - * @Date: 08/11/2019 - * - */ - -// This is an independent project of an individual developer. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com - -/*-------------------------------- INCLUDES ---------------------------------*/ - -#include - -#include "server/domo-server.h" - -/*! ---------------------------------------------------------------------------- - * @fn main - * - * @brief Main function of domo-iot daemon. - */ -int main(int argc, char *argv[]) -{ - int the_return; - - DomoServer the_server; - - if (!the_server.setup()) - { - fprintf(stderr, "Failed to setup the daemon.\n"); - return -1; - } - - the_return = the_server.loop(); - - return the_return; -} diff --git a/src/tinyweb/tinyweb.c b/src/tinyweb/tinyweb.c deleted file mode 100644 index 7607246..0000000 --- a/src/tinyweb/tinyweb.c +++ /dev/null @@ -1,968 +0,0 @@ -#include "tinyweb.h" -#include "tools.h" - -#ifdef __GNUC__ -#include -#define _strncmpi strncasecmp -#define strcmpi strcasecmp -#endif // __GNUC__ - -#include -#include -#include -#include -#include - -// TinyWeb ajouté et amélioré les fonctions, par lzpong 2016/11/24 - -// Valeur élevée, meilleures performances du disque et du processeur lors de l'envoi de fichiers, utilisation accrue de la mémoire -#define TW_SEND_SIZE 1024*1024*16 - -typedef struct tw_file_t { - //uchar flag; //连接的标志 - FILE* fp; //文件指针 - uchar* buff;//文件发送缓存 - unsigned long long fsize;//文件大小 - unsigned long long lsize;//文件中要发送的块剩余大小 -}tw_file_t; - -typedef struct tw_client { - tw_peerAddr pa;//客户端连接的地址 - tw_file_t ft;//发往客户端的文件,断点续传记录 - WebSocketHandle hd; - tw_reqHeads heads;//Http 头部(如果是http) - membuf_t buf;//http post 分包接收的缓存 -}tw_client; -//================================================= - - -//关闭客户端连接后,释放客户端连接的数据 -static void after_uv_close_client(uv_handle_t* client) { - tw_config* tw_conf = (tw_config*)(client->loop->data); - tw_client* clidata = (tw_client*)client->data; - //如果有发送文件 - if (clidata->ft.fp) - fclose(clidata->ft.fp); - if (clidata->ft.buff) - free(clidata->ft.buff); - //如果是WebSocket - //if (clidata->pa.flag & 0x2) - membuf_uninit(&clidata->hd.buf); - //http post 分包接收的缓存 - membuf_uninit(&clidata->buf); - //关闭连接回调 - if (tw_conf->on_close) - tw_conf->on_close(tw_conf->data, client, &clidata->pa); - free(client->data); - free(client); -} - -//关闭客户端连接 -void tw_close_client(uv_stream_t* client) { - tw_client* clidata = (tw_client*)client->data; - uv_close((uv_handle_t*)client, after_uv_close_client); -} - -//发送数据后,free数据,关闭客户端连接 -static void after_uv_write(uv_write_t* w, int err) { - tw_client* clidata = (tw_client*)w->handle->data; - if (w->data) - free(w->data); //sended data need free - //长连接就不关闭了 - if (!err && clidata->ft.fp) - tw_http_send_file(w->handle, NULL, NULL, NULL, NULL); - else if (!(clidata->pa.flag & 0x1)){ - if (w->handle->flags & 0x01) - printf("after_uv_write sk:%zd error: handle Has been closed\n", clidata->pa.sk); - else - uv_close((uv_handle_t*)w->handle, after_uv_close_client); - } - free(w); -} - -//发送数据到客户端; 如果是短连接,则发送完后会关闭连接 -//data:待发送数据 -//len: 数据长度, -1 将自动计算数据长度 -//need_copy_data:是否需要复制数据 -//need_free_data:是否需要free数据, 如果need_copy_data非零则忽略此参数 -void tw_send_data(uv_stream_t* client, const void* data, size_t len, char need_copy_data, char need_free_data) { - uv_buf_t buf; - uv_write_t* w; - void* newdata = (void*)data; - - if (len == (size_t)-1) - len = strlen((char*)data); - - if (need_copy_data) { - newdata = malloc(len); - memcpy(newdata, data, len); - } - - buf = uv_buf_init((char*)newdata, len); - w = (uv_write_t*)malloc(sizeof(uv_write_t)); - w->data = (need_copy_data || need_free_data) ? newdata : NULL; - uv_write(w, client, &buf, 1, after_uv_write); //free w and w->data in after_uv_write() -} - -//制造头部 SetCookie 字段和值 -//cookie: 缓存区(至少 42+strlen(key)+strlen(val)+strlen(domain)+strlen(path) ) -//ckLen: cookie的长度 -//expires: 多少秒后过期 -//domain: Domain, 域名或IP地址,或NULL -//path: Path, 可以是 heads->path,或NULL -void tw_make_setcookie(char* set_cookie,int ckLen,const char* key,const char* val,int expires,char* domain,char* path) { - int rlen,len=0; - rlen=snprintf(set_cookie, ckLen, "Set-Cookie: %s=%s", key, val); - if (rlen > 0) len = rlen,rlen=0; - if (expires > 0) - rlen = snprintf(set_cookie + len, ckLen - len, "; Max-Age=%d", expires); - if (rlen > 0) len += rlen,rlen=0; - if (domain) - rlen = snprintf(set_cookie + len, ckLen - len, "; Domain=%s", domain); - if (rlen > 0) len += rlen, rlen = 0; - if (path) - rlen = snprintf(set_cookie + len, ckLen - len, "; Path=%s", path); - if (rlen > 0) len += rlen, rlen = 0; - set_cookie[len]='\r'; - set_cookie[len+1]='\n'; - set_cookie[len+2]=0; -} -//制造头部 delete cookie -void tw_make_delcookie(char* del_cookie, int ckLen, char* key) -{ - snprintf(del_cookie, ckLen, "Delete-Cookie: %s\r\n", key); -} - -//发送'200 OK' 响应; 不会释放(free)传入的数据(u8data) -//content_type:Content Type 文档类型 -//u8data:utf-8编码的数据 -//content_length:数据长度,为0或-1时自动计算(strlen)(c_str, end with NULL) -//respone_size:获取响应最终发送的数据长度,为0表示放不需要取此长度 -void tw_send_200_OK(uv_stream_t* client, const char* ext_heads, const char* content_type, const void* u8data, size_t content_length, size_t* respone_size) { - size_t repSize; - const char *type = strchr(content_type, '/'); - //有'.' 没有'/' 至少有两个'/' '/'是在开头 '/'是在末尾 - //都要重新取文件类型 - if (type) { - if (strchr(content_type, '.'))// 有'.' - type = tw_get_content_type(content_type); - else { - type = strchr(type + 1, '/'); - if (type)//至少有两个'/' - type = tw_get_content_type(content_type); - else { - type = strchr(content_type, '/'); - if (type == content_type || type == (content_type + strlen(content_type) - 1)) - type = tw_get_content_type(content_type); - else - type = content_type; - } - } - }//没有'/' - else - type = tw_get_content_type(content_type); - char *data = tw_format_http_respone(client, "200 OK", ext_heads, type, u8data, content_length, &repSize); - tw_send_data(client, data, repSize, 0, 1);//发送后free data - if (respone_size) - *respone_size = repSize; -} - -//返回格式华的HTTP响应内容(需要free返回数据) -//status: "200 OK" -//content_type: 文件类型,如:"text/html" ;可以调用tw_get_content_type()得到 -//content: any utf-8 data, need html-encode if content_type is "text/html" -//content_length: 0或-1自动计算 content 长度(c_str, end with NULL) -//respone_size: if not NULL,可以获取发送的数据长度 the size of respone will be writen to request -//returns malloc()ed c_str, need free() by caller -char* tw_format_http_respone(uv_stream_t* client, const char* status, const char* ext_heads, const char* content_type, const char* content, size_t content_length, size_t* respone_size) { - size_t totalsize, header_size; - char* respone; - char szDate[30]; - getGmtTime(szDate,30,0); - ext_heads == NULL ? ext_heads = "" : 0; - tw_config* tw_conf = (tw_config*)(client->loop->data); - if (content_length == 0 || content_length == (size_t)-1) - content_length = content ? strlen(content) : 0; - totalsize = strlen(status) + strlen(ext_heads) + strlen(content_type) + content_length + 158; - respone = (char*)malloc(totalsize + 1); - header_size = snprintf(respone, totalsize, "HTTP/1.1 %s\r\nDate: %s\r\nServer: TinyWeb\r\nConnection: close\r\nContent-Type:%s; charset=%s\r\nContent-Length:%zd\r\n%s\r\n" - , status, szDate, content_type, tw_conf->charset, content_length, ext_heads); - assert(header_size > 0); - if (content_length) - memcpy(respone + header_size, content, content_length+1); - - if (respone_size) - *respone_size = header_size + content_length; - return respone; -} - -//发送404响应 -static void tw_404_not_found(uv_stream_t* client, const char* pathinfo, const char* ext_heads) { - char* respone; - char buffer[128]; - snprintf(buffer, sizeof(buffer), "

404 Not Found

%s

", pathinfo); - respone = tw_format_http_respone(client, "404 Not Found", ext_heads, "text/html", buffer, -1, NULL); - tw_send_data(client, respone, -1, 0, 1); -} - -//发送301响应,路径永久重定位 -void tw_301_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads) { - size_t len = 76 + strlen(heads->path); - char buffer[1245]; - char szDate[30]; - ext_heads == NULL ? ext_heads = "" : 0; - getGmtTime(szDate,30,0); - tw_config* tw_conf = (tw_config*)(client->loop->data); - snprintf(buffer, sizeof(buffer), "HTTP/1.1 301 Moved Permanently\r\nDate: %s\r\n" - "Server: TinyWeb\r\nLocation: http://%s%s%s%s\r\nConnection: close\r\n" - "Content-Type:text/html;charset=%s\r\nContent-Length:%zd\r\n%s\r\n" - "

Moved Permanently

The document has moved here.

" - , szDate - , heads->host, heads->path, (heads->query[0]?"?":""), (heads->query[0]?heads->query:"") - , tw_conf->charset, len, ext_heads - , heads->path, (heads->query[0]?"?":""), (heads->query[0]?heads->query:"")); - tw_send_data(client, buffer, -1, 1, 1); -} -//发送302响应,路径临时重定位 -void tw_302_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads) { - char buffer[1245]; - char szDate[30]; - ext_heads == NULL ? ext_heads = "" : 0; - getGmtTime(szDate,30,0); - tw_config* tw_conf = (tw_config*)(client->loop->data); - snprintf(buffer, sizeof(buffer), "HTTP/1.1 302 Moved Temporarily\r\nDate: %s\r\n" - "Server: TinyWeb\r\nLocation: http://%s%s%s%s\r\nConnection: close\r\n" - "Content-Type:text/html;charset=%s\r\nContent-Length:0\r\n%s\r\n" - , szDate - , heads->host, heads->path, (heads->query[0]?"?":""), (heads->query[0]?heads->query:"") - , tw_conf->charset, ext_heads); - tw_send_data(client, buffer, -1, 1, 1); -} - -//http协议发送文件,异步 -//file_path: 文件路径 -void tw_http_send_file(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads, const char* content_type, const char* file_path) { - char *respone; - char szDate[30]; - tw_config* tw_conf = (tw_config*)(client->loop->data); - tw_client* clidata = (tw_client*)client->data; - tw_file_t* filet = &clidata->ft; - - //发送头部 - if (!filet->fp && file_path) { - filet->fp = fopen(file_path, "rb"); - if (filet->fp) { -#ifdef _WIN64 - _fseeki64(filet->fp, 0, SEEK_END); - filet->fsize = _ftelli64(filet->fp); -#else - fseek(filet->fp, 0, SEEK_END); - filet->fsize = ftell(filet->fp); -#endif - if (heads->Range_frm < 0)//(负数:从文件末尾反过来的位置,即fileSize-sizeFrom) - heads->Range_frm = filet->fsize + heads->Range_frm; - if (heads->Range_to <= 0)//(负数:从文件末尾反过来的位置,即fileSize-sizeTo) - heads->Range_to = filet->fsize + heads->Range_to; - if (filet->fsize < (unsigned long long)heads->Range_frm)//开始位置大于文件 - heads->Range_frm = filet->fsize; - if (heads->Range_to < heads->Range_frm || (unsigned long long)heads->Range_to>filet->fsize)//Range_to 可能没有,或不正确,表示整个文件大小 - heads->Range_to = filet->fsize; - //要下载区段的size - filet->lsize = heads->Range_to - heads->Range_frm; -#ifdef _WIN64 - _fseeki64(filet->fp, heads->Range_frm, SEEK_SET); -#else - fseek(filet->fp, heads->Range_frm, SEEK_SET); -#endif - ext_heads == NULL ? ext_heads = "" : 0; - getGmtTime(szDate,30,0); - respone = (char*)malloc(300 + 1); - int respone_size; - if (heads->Range_frm == 0) //200 OK - respone_size = snprintf(respone, 300, "HTTP/1.1 200 OK\r\nDate: %s\r\nServer: TinyWeb\r\nConnection: close\r\nContent-Type:%s;charset=%s\r\nAccept-Range: bytes\r\nContent-Length:%llu\r\n%s\r\n" - , szDate, content_type, tw_conf->charset, filet->fsize,ext_heads); - else //206 Partial Content - respone_size = snprintf(respone, 300, "HTTP/1.1 206 Partial Content\r\nDate: %s\r\nServer: TinyWeb\r\nConnection: close\r\nContent-Type:%s;charset=%s\r\nAccept-Range: bytes\r\nContent-Range: %lld-%lld/%llu\r\nContent-Length:%llu\r\n%s\r\n" - , szDate, content_type, tw_conf->charset, heads->Range_frm, heads->Range_to, filet->fsize, filet->lsize,ext_heads); - tw_send_data(client, respone, respone_size, 0, 1); - } - else - tw_404_not_found(client, heads->path, ext_heads); - } - else { //发送文件 - size_t read_size=0;// read_bytes; - if (filet->fp) { - if (filet->lsize > 0) { - if(!filet->buff) - filet->buff = (char*)malloc(TW_SEND_SIZE + 1); - //fread 返回实际读取的单元个数。如果小于count,则可能文件结束或读取出错; - //可以用ferror()检测是否读取出错,用feof()函数检测是否到达文件结尾。如果size或count为0,则返回0。 - if(filet->lsize>TW_SEND_SIZE) - read_size = fread(filet->buff, sizeof(char), TW_SEND_SIZE, filet->fp); - else - read_size = fread(filet->buff, sizeof(char), filet->lsize, filet->fp); - filet->lsize -= read_size; - tw_send_data(client, filet->buff, read_size, 0, 0); - } - else - { - fclose(filet->fp); - filet->fp = 0; - filet->fsize = 0; - } - } - } -} - -//根据扩展名(不区分大小写),返回文件类型 content_type -const char* tw_get_content_type(const char* fileExt) { - const static char* octet = "application/octet-stream"; - if (fileExt) - { - //不管什么路径名或者文件名, 只要最后面有点(.),就认为是有扩展名的 - const char *p = strrchr(fileExt, '.'); - if (p) { // /aaa.txt - fileExt = p + 1; - } - } - else //否则没有扩展名 - return octet; - if (strcmpi(fileExt, "htm") == 0 || strcmpi(fileExt, "html") == 0) - return "text/html"; - else if (strcmpi(fileExt, "js") == 0) - return "application/javascript"; - else if (strcmpi(fileExt, "css") == 0) - return "text/css"; - else if (strcmpi(fileExt, "json") == 0) - return "application/json"; - else if (strcmpi(fileExt, "log") == 0 || strcmpi(fileExt, "txt") == 0 || strcmpi(fileExt, "ini") == 0 - || strcmpi(fileExt, "config") == 0 || strcmpi(fileExt, "conf") == 0 || strcmpi(fileExt, "cfg") == 0 - || strcmpi(fileExt, "sh") == 0 || strcmpi(fileExt, "bat") == 0) - return "text/plain"; - else if (strcmpi(fileExt, "jpg") == 0 || strcmpi(fileExt, "jpeg") == 0) - return "image/jpeg"; - else if (strcmpi(fileExt, "png") == 0) - return "image/png"; - else if (strcmpi(fileExt, "gif") == 0) - return "image/gif"; - else if (strcmpi(fileExt, "ico") == 0) - return "image/x-icon"; - else if (strcmpi(fileExt, "xml") == 0) - return "application/xml"; - else if (strcmpi(fileExt, "xhtml") == 0) - return "application/xhtml+xml"; - else if (strcmpi(fileExt, "swf") == 0) - return "application/x-shockwave-flash"; - else if (strcmpi(fileExt, "svg") == 0) - return "image/svg-xml"; - else if (strcmpi(fileExt, "wav") == 0) - return "audio/wav"; - else if (strcmpi(fileExt, "mid") == 0 || strcmpi(fileExt, "midi") == 0) - return "audio/midi"; - else if (strcmpi(fileExt, "wma") == 0) - return "audio/x-ms-wma"; - else if (strcmpi(fileExt, "mp3") == 0) - return "audio/mp3"; - else if (strcmpi(fileExt, "3gp") == 0) - return "video/3gpp"; - else if (strcmpi(fileExt, "avi") == 0) - return "video/x-msvideo"; - else if (strcmpi(fileExt, "mkv") == 0) - return "video/x-matroska"; - else if (strcmpi(fileExt, "mp4") == 0) - return "video/mp4"; - else if (strcmpi(fileExt, "rmvb") == 0) - return "video/vnd.rn-realvideo"; - else if (strcmpi(fileExt, "flv") == 0) - return "flv-application/octet-stream";// "video/x-flv"; - else if (strcmpi(fileExt, "apk") == 0) - return "application/vnd.android.package-archive"; - else - return octet; -} - -//处理客户端请求 -//invoked by tinyweb when GET request comes in -//please invoke write_uv_data() once and only once on every request, to send respone to client and close the connection. -//if not handle this request (by invoking write_uv_data()), you can close connection using tw_close_client(client). -//pathinfo: "/" or "/book/view/1" -//query_stirng: the string after '?' in url, such as "id=0&value=123", maybe NULL or "" -static void tw_request(uv_stream_t* client, tw_reqHeads* heads) { - tw_config* tw_conf = (tw_config*)(client->loop->data); - char fullpath[260];//绝对路径(末尾不带斜杠) - snprintf(fullpath, 259, "%s/%s\0", tw_conf->doc_dir, (heads->path[0] == '/' ? heads->path + 1 : heads->path)); - //去掉末尾的斜杠 - char *p = &fullpath[strlen(fullpath) - 1]; - while (*p == '/' || *p == '\\') - *p = 0, p--; - - char file_dir = isExist(fullpath); - //判断 文件或文件夹,或不存在 - switch (file_dir) - { - case 1://存在:文件 - { - char* postfix = strrchr(heads->path, '.');//从后面开始找文件扩展名 - if (postfix) - { - postfix++; - p = postfix + strlen(postfix) - 1; - while (*p == '/' || *p == '\\') - *p = 0, p--; - } - tw_http_send_file(client, heads, NULL, tw_get_content_type(postfix), fullpath); - } - break; - case 2://存在:文件夹 - { - if (heads->path[strlen(heads->path)-1] != '/') //文件夹要检测末尾'/' - { - int len = strlen(heads->path); - if (len >= sizeof(heads->path)-1) - len=sizeof(heads->path)-2; - heads->path[len] = '/'; - heads->path[len+1] = 0; - tw_301_Moved(client, heads, NULL); - break; - } - char tmp[260]; tmp[0] = 0; - char *s = strdup(tw_conf->doc_index); - p = strtok(s, ";"); - //是否有默认主页 - while (p) - { - snprintf(tmp, 259, "%s/%s", fullpath, p); - if (isFile(tmp)) { - tw_http_send_file(client, heads, NULL, "text/html", tmp); - break; - } - tmp[0] = 0; - p = strtok(NULL, ";"); - } - free(s); - //没用默认主页 - if (!tmp[0]) - { - char* p2=NULL; - uint len; - membuf_t buf; - membuf_init(&buf, 1024 * 2); - char *body = "Welcome to TinyWeb.
Directory access forbidden."; - if (tw_conf->dirlist) { - membuf_append(&buf, "Index of ");//+path -#ifdef _MSC_VER - if (strnicmp(tw_conf->charset, "utf",3) == 0) {//utf-8 - len = strlen(heads->path); - p2 = GB2U8(heads->path, &len); - membuf_append(&buf, p2); - } else -#endif // _MSC_VER - membuf_append(&buf, heads->path); - membuf_append_format(&buf, "\r\n", tw_conf->charset); - membuf_append(&buf, "

Index of ");//+path - if (p2) { - membuf_append(&buf, p2); - free(p2); - } else { - membuf_append(&buf, heads->path); - } - membuf_append(&buf, "

\r\n" - "\r\n" - "" - "\r\n" - "" - "" - "
@NameSizeLast modified


" - "
TinyWeb Server
" - "\r\n"); - } - else - membuf_append_data(&buf, body, strlen(body)); - char *respone = tw_format_http_respone(client, "200 OK", NULL, "text/html", (char*)buf.data, buf.size, NULL); - tw_send_data(client, respone, -1, 0, 1); - membuf_uninit(&buf); - } - } - break; - default://不存在 - tw_404_not_found(client, heads->path, NULL); - break; - } -} - -//获取http头信息,返回指向 Sec-WebSocket-Key 的指针 -static char* tw_get_http_heads(const uv_buf_t* buf, int len, tw_reqHeads* heads) { - char *key=NULL, *start, *head, *p; - char delims[] = "\r\n"; - char* data = strstr(buf->base, "\r\n\r\n"); - if (data) { - *data = 0; - heads->data = data += 4; - heads->len = len - (data-buf->base); - //是http get/post协议 - if (buf->base[0] == 'G' && buf->base[1] == 'E' && buf->base[2] == 'T' && buf->base[3] == ' ') { - heads->method = 1;//GET - } - else if (buf->base[0] == 'P' && buf->base[1] == 'O' && buf->base[2] == 'S' && buf->base[3] == 'T' && buf->base[4] == ' ') { - heads->method = 2;//POST - } - //是http get/post协议 - if (heads->method) - { - char *path = "", *query = ""; - head = strtok(buf->base, delims); - //search path - path = strchr(head + 3, ' ') + 1; - while (isspace(*path)) path++; - start = strchr(path, ' '); - if (start) *start = 0; - //url含有转义编码字符 - if (strstr(path, "%") != 0) - { - url_decode(heads->path); -#ifdef _MSC_VER //Windows下需要转换编码,因为windows系统的编码是GB2312 - size_t len = strlen(path); - char *gb = U82GB(path, &(unsigned int)len); - strncpy(path, gb, len); - path[len] = 0; - free(gb); - //linux 下,系统和源代码文件编码都是是utf8的,就不需要转换 -#endif // _MSC_VER - } - //query param - p = strchr(path, '?'); - if (p) { - query = p + 1; - *p = 0; - } - //确保开头为'/' - if (*path != '/') { - path--; - *path = '/'; - *(path - 1) = 0; - } - //确保结尾不是"/.." - p = strrchr(path, '.'); - if (p && *(p + 1) == 0 && *(p - 1) == '.' && *(p - 2) == '/') { - *(p + 1) = '/'; - *(p + 2) = 0; - } - ////------------尽可能的合并 "../" "/./" - if (strstr(path, "./") != 0) - { - //去掉"/./" - while ((p = strstr(path, "/./"))) - memmove(p, p + 2, strlen(p + 2) + 1); - //尽可能的合并"../" - while ((p = strstr(path, "/.."))) {//存在 .. - if ((p - path) <= 1) { - if ((start = strchr(path + 2, '/'))) - path = start; - else - *p = 0; - continue; - } - *(p - 1) = 0; - start = strrchr(path, '/'); - if (start == NULL) - start = path; - key = strchr(p + 2, '/'); - if (key) - p = key; - else - break; - memmove(start, p, strlen(p) + 1); - } - } - snprintf(heads->path,512, "%s", path); - snprintf(heads->query,1500, "%s", query); - - key = NULL; - //从第二行开始循环处理 头部 - head = strtok(NULL, delims); - while (head) - { - //是否有 Sec-WebSocket-Key - //http upgrade to WebSocket - if (start = strstr(head, "Sec-WebSocket-Key: ")) - { - key = start + 19; - } - //search host - else if (start = strstr(head, "Host: ")) - { - snprintf(heads->host,260,"%s", start + 6); - } - //Range: bytes=sizeFrom-[sizeTo] (sizeTo 可能没有,或不正确,表示整个文件大小) - // (sizeFrom 为负数,表示从文件末尾反过来的位置,即fileSize-sizeFrom) - //Range: bytes=sizeFrom-[sizeTo],sizeFrom-[sizeTo][,sizeFrom-[sizeTo]] 这种多段不支持,只支持一段 - else if (start = strstr(head, "Range: ")) - { - start += 7; - start = strstr(start, "bytes="); - if (start) - start += 6; - p= strstr(start + 1, "-");//防止 sizeFrom 为负数 - heads->Range_to = 0; - if (p)//可能有 sizeTo - { - heads->Range_frm = strtoll(start, &p, 10); - p++;//跳过 '-' - if(*p) - heads->Range_to = strtoll(p, NULL, 10); - } - else //没有 sizeTo - heads->Range_frm = strtol(start, NULL, 10); - } - //Content-Length: 3543 - else if (start = strstr(head, "Content-Length: ")) - { - heads->contentLen = atoi(start + 16); - } - //Cookie: xxxxx - else if (start = strstr(head, "Cookie: ")) - { - snprintf(heads->cookie,260,"%s", start + 8); - } - //下一行 头部 - head = strtok(NULL, delims); - } - if (heads->contentLen < 1) - heads->data = NULL,heads->len=0; - } - } - return key; -} - -//on_read_WebSocket -static void on_read_websocket(uv_stream_t* client, char* data, size_t Len) { - tw_config* tw_conf = (tw_config*)(client->loop->data); - tw_client* clidata = (tw_client*)client->data; - WebSocketHandle* hd = &clidata->hd; - if (NULL == hd->buf.data) - membuf_init(&hd->buf, 128); - - WebSocketGetData(hd, data, Len); - clidata->pa.flag = bitRemove(clidata->pa.flag, 0x4); - - if (hd->isEof) - { - switch (hd->type) { - case 0: //0x0表示附加数据帧 - break; - case 1: //0x1表示文本数据帧 - clidata->pa.flag |= 0x4; - case 2: //0x2表示二进制数据帧 - //接收数据回调 - if (tw_conf->on_data) - tw_conf->on_data(tw_conf->data, client, &clidata->pa, &hd->buf); - break; - case 3: case 4: case 5: case 6: case 7: //0x3 - 7暂时无定义,为以后的非控制帧保留 - //membuf_uninit(hd->buf); - //memset(hd, 0, sizeof(WebSocketHandle)); - break; - case 8: //0x8表示连接关闭 - *(data + 1) = 0;//无数据 - tw_send_data(client, data, 2, 1, 0); - if (hd->buf.size > 2) { //错误信息 - if (tw_conf->on_error) { - char errstr[60] = { 0 }; - snprintf(errstr, 59, "-0:wserr,%s", hd->buf.data + 2); - //出错信息回调 - tw_conf->on_error(tw_conf->data, client, &clidata->pa, 0, errstr); - } - else - fprintf(stderr, "-0:wserr,%s\n", hd->buf.data + 2); - } - break; - case 9: //0x9表示ping - case 10://0xA表示pong - default://0xB - F暂时无定义,为以后的控制帧保留 - *data += 1;//发送pong - *(data + 1) = 0;//无数据 - tw_send_data(client, data, 2, 1, 0); - //memset(hd, 0, sizeof(WebSocketHandle)); - break; - } - //释放 membuf , 收到消息时再分配 - clidata->hd.dfExt = clidata->hd.isEof = clidata->hd.type = 0; - membuf_uninit(&hd->buf); - } -} - -//(循环)读取客户端发送的数据,接收客户的数据 -static void on_uv_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) { - tw_config* tw_conf = (tw_config*)(client->loop->data); - tw_client* clidata = (tw_client*)client->data; - membuf_t mbuf; - if (nread > 0) { - assert(clidata); - //WebSocket - if (clidata->pa.flag & 0x2) //WebSocket - on_read_websocket(client, buf->base, nread); - //long-link - else if (clidata->pa.flag & 0x1) { //SOCKET //long-link - //接收数据回调 - if (tw_conf->on_data) { - mbuf.data = buf->base; - mbuf.size = nread; - mbuf.buffer_size = buf->len; - tw_conf->on_data(tw_conf->data, client, &clidata->pa, &mbuf); - } - } - //http post继续接收 未收完的数据 - else if (clidata->heads.method==2) { - if (nread) { - membuf_append_data(&clidata->buf, buf->base, nread); - clidata->heads.len += nread; - } - if (clidata->heads.len >= clidata->heads.contentLen) { - //所有请求全部回调,返回非0表示已处理 - clidata->heads.data = clidata->buf.data; - if (tw_conf->on_request == 0 || 0 == tw_conf->on_request(tw_conf->data, client, &clidata->pa, &clidata->heads)) - tw_request(client, &clidata->heads); - } - } - //未知 - else { //http 或 未知 - char* p, *p2; - //tw_reqHeads heads; - //memset(&heads, 0, sizeof(tw_reqHeads)); - p = tw_get_http_heads(buf,nread, &clidata->heads);//get Sec-WebSocket-Key ? - if (p) { //WebSocket 握手 - clidata->pa.flag |= 3;//long-link & WebSocket - p2 = WebSocketHandShak(p); - tw_send_data(client, p2, -1, 1, 0); - free(p2); - } - else if (clidata->heads.method) { //HTTP - if (!clidata->heads.path && clidata->heads.path[0] != '/'){//路径没有 '/' 开头 - tw_301_Moved(client, &clidata->heads, NULL); - } - else {//http post 数据 - if (clidata->heads.len >= clidata->heads.contentLen) { - //所有请求全部回调,返回非0表示已处理 - if (tw_conf->on_request == 0 || 0 == tw_conf->on_request(tw_conf->data, client, &clidata->pa, &clidata->heads)) - tw_request(client, &clidata->heads); - } - else {//跟随头部的 post 数据未发送完 - membuf_init(&clidata->buf, 128); - if (clidata->heads.len) - membuf_append_data(&clidata->buf, clidata->heads.data, clidata->heads.len); - } - } - } - else { //SOCKET - clidata->pa.flag |= 1;//long-link - //接收数据回调 - if (tw_conf->on_data) { - mbuf.data = buf->base; - mbuf.size = nread; - mbuf.buffer_size = buf->len; - tw_conf->on_data(tw_conf->data, client, &clidata->pa, &mbuf); - } - } - } - } - else if (nread <= 0) {//在任何情况下出错, read 回调函数 nread 参数都<0,如:出错原因可能是 EOF(遇到文件尾) - if (nread != UV_EOF) { - if (tw_conf->on_error) { - char errstr[60] = { 0 }; - snprintf(errstr, 59, "%d:%s,%s", (int)nread, uv_err_name((int)nread), uv_strerror((int)nread)); - //出错信息回调 - tw_conf->on_error(tw_conf->data, client, &clidata->pa, nread, errstr); - } - else - fprintf(stderr, "%d:%s,%s\n", (int)nread, uv_err_name((int)nread), uv_strerror((int)nread)); - } - //关闭连接. 读取长度为0,或是错误值,都应该关闭连接 - tw_close_client(client); - } - //每次使用完要释放 - if (buf->base) - free(buf->base); -} - -//为每次读取数据分配内存缓存 -static void on_uv_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { - buf->base = (char*)calloc(1, suggested_size); - buf->len = suggested_size; -} - -//获取客户端的 socket,ip,port -static char tw_getPeerAddr(uv_stream_t* client, tw_peerAddr* pa) -{ - struct sockaddr_in peeraddr[2], hostaddr[2]; //Windows 下不声明成数组(且数组长度大于1),getpeername会失败(errno=10014) - int addrlen = sizeof(peeraddr); - //memset(pa, 0, sizeof(PeerAddr)); - //客户端的地址 - if (client->type == UV_TCP) { -#ifdef WIN32 - pa->sk = ((uv_tcp_t*)client)->socket; -#else - addrlen /= 2; -#if defined(__APPLE__) - if (client->select) - pa->sk = client->select; - else -#endif - pa->sk = client->io_watcher.fd; -#endif - int er = uv_tcp_getpeername((uv_tcp_t*)client, (struct sockaddr*)peeraddr, &addrlen); - if (er < 0) - memset(peeraddr, 0, addrlen); - er = uv_tcp_getsockname((uv_tcp_t*)client, (struct sockaddr*)hostaddr, &addrlen); - if (er < 0) - memset(hostaddr, 0, addrlen); - } - else if (client->type == UV_UDP) { -#ifdef WIN32 - pa->sk = ((uv_udp_t*)client)->socket; -#else - pa->sk = client->io_watcher.fd; -#endif - int er = uv_udp_getsockname((uv_udp_t*)client, (struct sockaddr*)peeraddr, &addrlen); - if (er < 0) - memset(peeraddr, 0, addrlen); - er = uv_udp_getsockname((uv_udp_t*)client, (struct sockaddr*)hostaddr, &addrlen); - if (er < 0) - memset(hostaddr, 0, addrlen); - } - else - return 1; - //网络字节序转换成主机字符序 - uv_ip4_name(peeraddr, pa->ip, sizeof(pa->ip)); - pa->port = ntohs(peeraddr[0].sin_port); - uv_ip4_name(hostaddr, pa->fip, sizeof(pa->ip)); - pa->fport = ntohs(hostaddr[0].sin_port); - - return 0; -} - -//客户端接入 -static void tw_on_connection(uv_stream_t* server, int status) { - //assert(server == (uv_stream_t*)&_server); - tw_client* cli; - if (status == 0) { - //建立客户端信息,在关闭连接时释放 see after_uv_close_client - uv_tcp_t* client = (uv_tcp_t*)calloc(1, sizeof(uv_tcp_t)); - //创建客户端的数据缓存块,在关闭连接时释放 see after_uv_close_client - cli = client->data = calloc(1, sizeof(tw_client)); - uv_tcp_init(server->loop, client);//将客户端放入loop - //接受客户,保存客户端信息 - uv_accept(server, (uv_stream_t*)client); - client->close_cb = after_uv_close_client; - //取客户端 socket,ip,port; - tw_getPeerAddr((uv_stream_t*)client, &cli->pa); - //开始读取客户端数据 - uv_read_start((uv_stream_t*)client, on_uv_alloc, on_uv_read); - //客户端接入回调 - tw_config* tw_conf = (tw_config*)(server->loop->data); - if (tw_conf->on_connect) - tw_conf->on_connect(tw_conf->data, (uv_stream_t*)client, &cli->pa); - } -} - -//================================================================================================== - -//TinyWeb 线程开始运行 -static void tw_run(uv_loop_t* loop) { - tw_config* tw_conf = (tw_config*)loop->data; - printf("TinyWeb v1.2.2 is started, listening on %s:%d\n", tw_conf->ip, tw_conf->port); - uv_run(loop, UV_RUN_DEFAULT); - uv_stop(loop); - if (!uv_loop_close(loop) && loop != uv_default_loop()) { - uv_loop_delete(loop); - } - printf("TinyWeb v1.2.2 is stopped, listening on %s:%d\n", tw_conf->ip, tw_conf->port); - free(tw_conf->doc_dir); - free(tw_conf->doc_index); - free(tw_conf->charset); - free(tw_conf); -} - -//start web server, start with the config -//loop: if is NULL , it will be uv_default_loop() -//conf: the server config -int tinyweb_start(uv_loop_t* loop, tw_config* conf) { - int ret; - assert(conf != NULL); - if (conf->ip == NULL || (conf->ip != NULL && conf->ip[0] == '*')) - conf->ip = "0.0.0.0"; - struct sockaddr_in addr; - uv_ip4_addr(conf->ip, conf->port, &addr); - - tw_config* tw_conf = calloc(1, sizeof(tw_config)); - memcpy(tw_conf, conf, sizeof(tw_config)); - - //设置主目录(末尾不带斜杠) - if (conf->doc_dir) - tw_conf->doc_dir = strdup(conf->doc_dir); - else - tw_conf->doc_dir = strdup("./"); - - printf("WebRoot port:%d Dir:%s\n",tw_conf->port, tw_conf->doc_dir); - //设置默认主页(分号间隔) - if (conf->doc_index && strcmpi(conf->doc_index, "") != 0) - tw_conf->doc_index = strdup(conf->doc_index); - else - tw_conf->doc_index = strdup("index.htm;index.html"); - //设置more编码 - if (conf->charset) - tw_conf->charset = strdup(conf->charset); - else - tw_conf->charset = strdup("utf-8"); - if (loop == NULL) - loop = uv_default_loop(); - ret = uv_tcp_init(loop, &tw_conf->_server); - if (ret < 0) - return ret; - ret = uv_tcp_bind(&tw_conf->_server, (const struct sockaddr*) &addr, 0); - if (ret < 0) - return ret; - ret = uv_listen((uv_stream_t*)&tw_conf->_server, 8, tw_on_connection); - if (ret < 0) - return ret; - loop->data = tw_conf; - //开始线程 - uv_thread_t hare_id; - uv_thread_create(&hare_id, (uv_thread_cb)tw_run, loop); - return 0; -} - -static void on_close_cb(uv_handle_t* handle) { -} - -//stop TinyWeb -//当执行uv_stop之后,uv_run并不能马上退出,而是要等待其内部循环的下一个iteration到来时才会退出; -//如果提前free掉loop就会导致loop失效。当然也可以sleep几十毫秒然后再close,但这么搞不太雅观。 -//uv_stop以后不能马上执行uv_loop_close() -//貌似关闭及释放loop等资源不是很完善的样子 -void tinyweb_stop(uv_loop_t* loop) -{ - if (loop == NULL) - loop = uv_default_loop(); - uv_stop(loop); - if (loop->data) - uv_close((uv_handle_t*)&((tw_config*)loop->data)->_server, on_close_cb); - uv_loop_close(loop); -} - diff --git a/src/tinyweb/tinyweb.h b/src/tinyweb/tinyweb.h deleted file mode 100644 index e62689d..0000000 --- a/src/tinyweb/tinyweb.h +++ /dev/null @@ -1,197 +0,0 @@ -#pragma once -#ifndef __TINYWEB_H__ -#define __TINYWEB_H__ - -#ifdef _MSC_VER -//去掉 warning C4996: '***': The POSIX name for this item is deprecated.Instead, use the ISO C++ conformant name... -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE -#endif -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#pragma comment(lib, "libuv.lib") -#pragma comment(lib, "ws2_32.lib") -#pragma comment(lib, "IPHLPAPI.lib") -#pragma comment(lib, "Psapi.lib") -#pragma comment(lib, "Userenv.lib") -# if defined(WIN32) && !defined(snprintf) -# define snprintf _snprintf -# endif - -#else //__GNUGC__ - -#include - -#endif - -#include "tools.h" - -#if TinyWeb_Function_Description //TinyWeb功能说明 - -auth lzpong 2016/11/24 - -Fonctionnalités basées sur la bibliothèque multiplateforme libuv - -0. Encodage de document de réglage d assistance, utf-8 par défaut -1.Support via HTTP: GET / POST -2.Support Socket, connexion WebSocket -3. Assistance renvoyant une page d erreur 404 -4. Assistance pour spécifier le répertoire racine (le répertoire dans lequel se trouve le programme par défaut) -5.Accès aux fichiers au format arbitraire (avec / sans extension, téléchargement de fichier) -Soutenir l accès statique aux pages Web: html / htm -Soutenir d autres fichiers statiques: js, css, png, jpeg / jpg, gif, ico, txt, xml, json, journal, wam, wav, mp3, mp4, apk, etc. -c. Prend en charge d’autres formats de fichier, le type de fichier par défaut est: "application / octet-stream" -d. Accès aux fichiers de support sans extension -Paramètres de demande de prise en charge de plage pour télécharger des fichiers volumineux (plage: octets = tailleFrom- [tailleVers], prise en charge du calcul inverse négatif) -6. Soutenez la page d’index par défaut (index.html / index.htm), vous pouvez personnaliser les paramètres. -7. Liste de répertoires d assistance -8. Ne pas autoriser l accès aux fichiers ou dossiers racine -9. Rappel d assistance -Rappel après réception de la demande HTTP (cette fonction facilite le retour du programme à la fonction personnalisée), et la réponse http ordinaire est exécutée lorsque le rappel échoue ou renvoie 0 -b. rappel de données WebSocket -Rappel de données c.socket -10.Support x64, supporte plus de 2G gros fichiers -11.Support cookie / setcookie -12. Prise en charge de l ajout d'informations d'en-tête personnalisées -13.Support POST données plus volumineuses (soutien post-contenu http envoyé par sous-traitance) -=============== stable, futur -14. en-tête http de soutien (http get) -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct tw_peerAddr { - uchar flag;//flag ([0 ~ 7]: [0] Reste connecté ou non [1] WebSocket [2] Cadre WebSocket ou - ushort port; - ushort fport; - size_t sk; - char ip[17]; - char fip[17]; -}tw_peerAddr; - -typedef struct tw_reqHeads { - uchar method;//0:Socket 1:GET 2:POST - char host[260]; //IP:port, domain - char path[512]; //Chemin - char query[1500];//Paramètre - char* data; //Les données - char cookie[260];//cookie - size_t contentLen;//Content Lenth - size_t len; //Longueur des données reçues - long long Range_frm, Range_to; -}tw_reqHeads; - -// Configuration du service -typedef struct tw_config { -//private data: - uv_tcp_t _server; - -//public data: - uchar dirlist:1; // Autoriser ou non la liste des répertoires - char* doc_dir; // Répertoire racine Web, chemin absolu, avec la barre oblique '\' à la fin (uninx est '/'); répertoire dans lequel se trouve le fichier de programme par défaut - char* doc_index;// Nom du fichier de page d'accueil par défaut, séparé par des virgules; par défaut "index.html, index.htm" - char* ip; //服务的IP地址 is only ipV4, can be NULL or "" or "*", which means "0.0.0.0" - ushort port; // L'adresse IP du service est uniquement ipV4, peut être NULL ou "" ou "*", ce qui signifie "0.0.0.0" - char* charset; // Encodage de document (utf-8 par défaut) - // Les données - void* data;// Données utilisateur, telles que les pointeurs d'objet - - // Accès client - char (*on_connect)(void* data, uv_stream_t* client, tw_peerAddr* pa); - - // Retour non nul signifie que la demande de traitement a été traitée. - // Return 0 signifie qu'il n'y a pas de demande de traitement appropriée, il trouvera automatiquement le fichier / dossier, s'il n'est pas trouvé, envoie une réponse 404 - // Cette fonction est pratique pour que le programme revienne à la fonction personnalisée. - // les membres chefs n'ont pas besoin d'être libres - // pa-> flag: octet de drapeau ([0 ~ 7]: [0] Rester connecté ou non [1] WebSocket [2] Si cadre de texte WebSocket - char (*on_request)(void* data, uv_stream_t* client, tw_peerAddr* pa, tw_reqHeads* heads); - - // Les données de socket ou WebSocket peuvent être jugées par buf-> flag ou pa-> flag - // les membres de buf n'ont pas besoin d'être libres - // pa-> flag: octet de drapeau ([0 ~ 7]: [0] Rester connecté ou non [1] WebSocket [2] Si cadre de texte WebSocket - char (*on_data)(void* data, uv_stream_t* client, tw_peerAddr* pa, membuf_t* buf); - - - // Le socket a détecté une erreur (le lien peut être cassé à ce moment) - // Format du message d'erreur: "% d:% s,% s" - // pa-> flag: octet de drapeau ([0 ~ 7]: [0] Rester connecté ou non [1] WebSocket [2] Si cadre de texte WebSocket - char (*on_error)(void* data, uv_stream_t* client, tw_peerAddr* pa,int errcode, char* errstr); - - // Le socket est fermé (le lien a été déconnecté pour le moment) - // indicateur: octet d'indicateur ([0 ~ 7]: [0] s'il faut conserver la connexion [1] s'il faut WebSocket - char (*on_close)(void* data, uv_stream_t* client, tw_peerAddr* pa); -} tw_config; - - -//start web server, start with the config -//loop: if is NULL , it will be uv_default_loop() -//conf: the server config -// Si la valeur renvoyée n'est pas 0, cela indique le code d'erreur. Utilisez uv_err_name (n) et uv_strerror (n) pour afficher la chaîne de motif. -int tinyweb_start(uv_loop_t* loop, tw_config* conf); - -//stop TinyWeb -//loop: if is NULL , it will be &uv_default_loop() -void tinyweb_stop(uv_loop_t* loop); - -//================================================= - -// Crée les champs et les valeurs de l'en-tête SetCookie -// set_cookie: zone de cache (au moins 42 + strlen (domaine) = strlen (chemin)) -// ckLen: longueur de set_cookie -// expire: combien de secondes vont expirer -// domaine: domaine, nom de domaine ou adresse IP -// chemin: chemin, peut être heads-> chemin -void tw_make_setcookie(char* set_cookie, int ckLen, const char* key, const char* val, int expires, char* domain, char* path); - -// créer un cookie d'en-tête -void tw_make_delcookie(char* del_cookie, int ckLen, char* key); - -// Renvoie le format du contenu de la réponse HTTP (nécessite des données de retour gratuites) -// status: statut http, tel que: "200 OK" -// ext_heads: chaînes d'en-tête supplémentaires, telles que: "head1: this-is-head1 \ r \ nSetCookie: TINY_SSID = Tiny1531896250879; Expires = ... \ r \ n" -// contenu_type: type de fichier, tel que: "text / html"; vous pouvez l'obtenir en appelant tw_get_content_type () -// contenu: utiliser les données de format de codage UTF-8, en particulier la réponse du type de fichier html -// longueur_contenu: 0 ou -1 calcule automatiquement la longueur du contenu (c_str, se termine par NULL) -// respone_size: si non NULL, vous pouvez obtenir la longueur des données envoyées, la taille de respone sera écrite pour demander -// retourne malloc () ed c_str, need free () par appelant -char* tw_format_http_respone(uv_stream_t* client, const char* status, const char* ext_heads, const char* content_type, const char* content, size_t content_length, size_t* respone_size); - -// Retourne le type de fichier content_type en fonction de l'extension -// Vous pouvez passer le chemin / nom du fichier / extension -const char* tw_get_content_type(const char* fileExt); - -// Envoie des données au client, s'il s'agit d'une connexion courte, la connexion sera fermée après l'envoi -// data: données à envoyer -// len: longueur des données, -1 calculera automatiquement la longueur des données -// need_copy_data: s'il faut copier des données -// need_free_data: si des données libres sont nécessaires, si need_copy_data est différent de zéro, ce paramètre est ignoré -void tw_send_data(uv_stream_t* client, const void* data, size_t len, char need_copy_data, char need_free_data); - -// Envoie une réponse '200 OK', les données entrantes (u8data) ne seront pas libérées -// contenu_type: type de document Type de contenu -// u8data: données codées UTF-8 -// longueur_contenu: longueur des données, calculée automatiquement lorsque la valeur est 0 ou -1 (strlen) (c_str, se termine par NULL) -// respone_size: Récupère la longueur des données envoyées par la réponse. Une valeur de 0 signifie que vous n'avez pas besoin de prendre cette longueur -void tw_send_200_OK(uv_stream_t* client, const char* ext_heads, const char* content_type, const void* u8data, size_t content_length, size_t* respone_size); - -// fichier d'envoi de protocole http, asynchrone -// chemin_fichier: chemin du fichier -void tw_http_send_file(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads, const char* content_type, const char* file_path); - -// Envoie une réponse 301, le chemin est déplacé de façon permanente -void tw_301_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads); -// Envoyer une réponse 302, le chemin est temporairement déplacé -void tw_302_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads); - -// ferme la connexion du client -void tw_close_client(uv_stream_t* client); - -#ifdef __cplusplus -} // extern "C" -#endif -#endif //__TINYWEB_H__ \ No newline at end of file diff --git a/src/tinyweb/tools.c b/src/tinyweb/tools.c deleted file mode 100644 index 453f31b..0000000 --- a/src/tinyweb/tools.c +++ /dev/null @@ -1,1715 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tools.h" - -#include - -#include -#include -#include -#include -#include -#include - -//-----------------------------------------------------------------------------------membuf c-str win/linux -#pragma region membuf c - str - -#include - -// ----------------------------------------------------------------------------------- - -//初始化 -void membuf_init(membuf_t *buf, size_t initial_buffer_size) -{ - memset(buf, 0, sizeof(membuf_t)); - buf->data = initial_buffer_size > 0 ? (uchar *)calloc(1, initial_buffer_size) : NULL; - //memset(buf->data, 0, initial_buffer_size); - buf->buffer_size = initial_buffer_size; -} - -// ----------------------------------------------------------------------------------- - -//释放buffer -void membuf_uninit(membuf_t *buf) -{ - if (buf->data) - free(buf->data); - memset(buf, 0, sizeof(membuf_t)); -} - -// ----------------------------------------------------------------------------------- - -//清除数据(数据覆盖为NULL),并缩小buffer大小 -void membuf_clear(membuf_t *buf, size_t maxSize) -{ - if (buf->data && buf->size) - { - if (maxSize > 1 && buf->buffer_size > maxSize) - { - uchar *p = (uchar *)realloc(buf->data, maxSize); - //防止realloc分配失败,或返回的地址一样 - assert(p); - if (p != buf->data) - buf->data = p; - buf->size = 0; - buf->buffer_size = maxSize; - } - else - { - buf->size = 0; - } - memset(buf->data, 0, buf->buffer_size); - } -} - -// ----------------------------------------------------------------------------------- - -////扩展buffer大小 -void membuf_reserve(membuf_t *buf, size_t extra_size) -{ - if (extra_size > buf->buffer_size - buf->size) - { - //calculate new buffer size - size_t new_buffer_size = buf->buffer_size == 0 ? extra_size : buf->buffer_size << 1; - size_t new_data_size = buf->size + extra_size; - while (new_buffer_size < new_data_size) - new_buffer_size <<= 1; - - // malloc/realloc new buffer - uchar *p = (uchar *)realloc(buf->data, new_buffer_size); // realloc new buffer - //防止realloc分配失败,或返回的地址一样 - assert(p); - if (p != buf->data) - buf->data = p; - memset((buf->data + buf->size), 0, new_buffer_size - buf->size); - buf->buffer_size = new_buffer_size; - } -} - -// ----------------------------------------------------------------------------------- - -//截断(释放)多余的内存 或者增加内存,至 size+4 的大小; 后面4字节填充0 -void membuf_trunc(membuf_t *buf) -{ - if (buf->buffer_size > (buf->size + 4) || buf->buffer_size < (buf->size + 4)) - { - uchar *p = (uchar *)realloc(buf->data, buf->size + 4); // realloc new buffer - //防止realloc分配失败,或返回的地址一样 - assert(p); - if (p && p != buf->data) - buf->data = p; - memset((buf->data + buf->size), 0, 4); - buf->buffer_size = buf->size + 4; - } -} - -// ----------------------------------------------------------------------------------- - -//添加C-style字符串 -size_t membuf_append(membuf_t *buf, const char *str) -{ - if (str == NULL) - return 0; - size_t size = strlen(str); - membuf_reserve(buf, size); - memmove((buf->data + buf->size), str, size); - buf->size += size; - return size; -} - -// ----------------------------------------------------------------------------------- - -//添加数据 -size_t membuf_append_data(membuf_t *buf, const void *data, size_t size) -{ - assert(data && size > 0); - membuf_reserve(buf, size); - memmove((buf->data + buf->size), data, size); - buf->size += size; - return size; -} - -// ----------------------------------------------------------------------------------- - -//按格式添加数据 -size_t membuf_append_format(membuf_t *buf, const char *fmt, ...) -{ - assert(fmt); - va_list ap, ap2; - va_start(ap, fmt); - size_t size = vsnprintf(0, 0, fmt, ap) + 1; - va_end(ap); - membuf_reserve(buf, size); - va_start(ap2, fmt); - vsnprintf((char *)(buf->data + buf->size), size, fmt, ap2); - va_end(ap2); - buf->size += --size; - return size; -} - -// ----------------------------------------------------------------------------------- - -//插入数据:offset位置,data数据,size数据大小 -void membuf_insert(membuf_t *buf, size_t offset, void *data, size_t size) -{ - assert(offset < buf->size); - membuf_reserve(buf, size); - memcpy((buf->data + offset + size), buf->data + offset, buf->size - offset); - memcpy((buf->data + offset), data, size); - buf->size += size; -} - -// ----------------------------------------------------------------------------------- - -//从末尾移动数据(不会填充为NULL,仅更改size) -void membuf_move(membuf_t *buf, size_t offset, size_t size) -{ - assert(offset < buf->size); - if (offset + size >= buf->size) - { - buf->size = offset; - } - else - { - //memmove() 用来复制内存内容(可以处理重叠的内存块):void * memmove(void *dest, const void *src, size_t num); - memmove((buf->data + offset), buf->data + offset + size, buf->size - offset - size); - buf->size -= size; - } - if (buf->buffer_size >= buf->size) - buf->data[buf->size] = 0; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------文件/文件夹检测 win/linux -#pragma region 文件 / 文件夹检测 - -// ----------------------------------------------------------------------------------- - -//获取工作目录路径,不带'/' -char *getWorkPath() -{ - static char CurPath[260] = {0}; - getcwd(CurPath, 259); - return CurPath; -} - -// ----------------------------------------------------------------------------------- - -//建立目录,递归建立 -int makeDir(const char *path, int mod) -{ - char pth[513]; - strncpy(pth, path, 512); - char *p = strrchr(pth, '\\'); - if (!p) - p = (char *)strrchr(pth, '/'); - if (p) - { - if (strlen(p) == 1) - *p = 0; - p = strrchr(pth, '\\'); - if (!p) - p = (char *)strrchr(pth, '/'); - if (p) - { - *p = 0; - if (!isExist(pth)) - makeDir(pth, mod); - } - } - return mkdir(path, mod); -} - -// ----------------------------------------------------------------------------------- - -//获取程序文件所在路径,不带'/' -char *getProcPath() -{ - static char CurPath[260] = {0}; - int cnt = readlink("/proc/self/exe", CurPath, 259); - if (cnt > 0 || cnt < 260) - { - //获取程序路径,即去掉程序名,包括去掉最后的'/' - int i; - for (i = cnt - 1; i > 0 && CurPath[i] != '/'; --i) - { - CurPath[i] = 0; - } - if (i > 2 && CurPath[i] == '/') - CurPath[i] = 0; - } - return CurPath; -} - -// ----------------------------------------------------------------------------------- - -//路径是否存在(0:不存在 1:存在:文件 2:存在:文件夹) -char isExist(const char *path) -{ - if (path && access(path, F_OK) == 0) - { - struct stat info; - stat(path, &info); - if (S_ISDIR(info.st_mode) || S_ISLNK(info.st_mode)) //dir or link - return 2; - return 1; - } - return 0; -} - -// ----------------------------------------------------------------------------------- - -//是否目录(1:是目录 0;非目录/不存在) -char isDir(const char *path) -{ - struct stat info; - if (path && !stat(path, &info)) // && opendir(path)!=NULL) - { - if (S_ISDIR(info.st_mode) || S_ISLNK(info.st_mode)) //dir or link - return 1; - } - return 0; -} - -// ----------------------------------------------------------------------------------- - -//是否文件(1:是文件 0:非文件/不存在) -char isFile(const char *path) -{ - if (path) - { - struct stat info; - stat(path, &info); - if (S_ISREG(info.st_mode)) //普通文件 - return 1; - } - return 0; -} - -// ----------------------------------------------------------------------------------- - -// Return list directory Json string, need free the return -char *listDir(const char *fullpath, const char *reqPath) -{ - int fnum = 0; - char tmp[1024]; - struct tm *mtime; - DIR *dp; - struct dirent *fileInfo; - struct stat statbuf; - membuf_t buf; - membuf_init(&buf, 2048); - membuf_append_format(&buf, "{\"path\":\"%s\",\"files\":[\r\n\0\0", reqPath); - - //文件(size>-1) 或 目录(size=-1) [name:"file1.txt",mtime:"2016-11-28 16:25:46",size:123],\r\n - if ((dp = opendir(fullpath)) != NULL) - { - while ((fileInfo = readdir(dp)) != NULL) - { - snprintf(tmp, 1023, "%s/%s\0\0", fullpath, fileInfo->d_name); - stat(tmp, &statbuf); //stat函数需要传入绝对路径或相对(工作目录的)路径 - mtime = localtime(&statbuf.st_mtime); - if (S_ISDIR(statbuf.st_mode)) - { - if (strncmp(fileInfo->d_name, ".", 1) == 0) - continue; - membuf_append_format(&buf, "{\"name\":\"%s/\",\"mtime\":\"%d-%02d-%02d %02d:%02d:%02d\",\"size\":\"-\",\"type\":\"D\"},\n", fileInfo->d_name, (1900 + mtime->tm_year), (1 + mtime->tm_mon), mtime->tm_mday, mtime->tm_hour, mtime->tm_min, mtime->tm_sec); - } - else - { - fnum++; - membuf_append_format(&buf, "{\"name\":\"%s\",\"mtime\":\"%d-%02d-%02d %02d:%02d:%02d\",\"size\":%ld,\"type\":\"F\"},\n", fileInfo->d_name, (1900 + mtime->tm_year), (1 + mtime->tm_mon), mtime->tm_mday, mtime->tm_hour, mtime->tm_min, mtime->tm_sec, statbuf.st_size); - } - } - closedir(dp); - } - //membuf_remove(&buf, buf.size - 1, 1); - buf.data[--buf.size] = 0; - buf.data[--buf.size] = 0; - membuf_append_format(&buf, "],total:%d}", fnum); - membuf_trunc(&buf); - return (char *)buf.data; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------编码转换 win/linux -#pragma region 编码转换 - -/***************************************************************************** -* 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码. -* -* 参数: -* unic 字符的Unicode编码值 -* pOutput 指向输出的用于存储UTF8编码值的缓冲区的指针 -* outsize pOutput缓冲的大小 -* -* 返回值: -* 返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 . -* -* 注意: -* 1. UTF8没有字节序问题, 但是Unicode有字节序要求; -* 字节序分为大端(Big Endian)和小端(Little Endian)两种; -* 在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位) -* 2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小! -****************************************************************************/ -int enc_unicode_to_utf8_one(size_t unic, uchar *pOutput, int outSize) -{ - assert(pOutput != NULL); - assert(outSize >= 6); - - if (unic <= 0x0000007F) - { - // U-00000000 - U-0000007F: 0xxxxxxx - *pOutput = (unic & 0x7F); - return 1; - } - else if (unic >= 0x00000080 && unic <= 0x000007FF) - { - // * U-00000080 - U-000007FF: 110xxxxx 10xxxxxx - *pOutput = ((unic >> 6) & 0x1F) | 0xC0; - *(pOutput + 1) = (unic & 0x3F) | 0x80; - return 2; - } - else if (unic >= 0x00000800 && unic <= 0x0000FFFF) - { - // U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx - *pOutput = ((unic >> 12) & 0x0F) | 0xE0; - *(pOutput + 1) = ((unic >> 6) & 0x3F) | 0x80; - *(pOutput + 2) = (unic & 0x3F) | 0x80; - return 3; - } - else if (unic >= 0x00010000 && unic <= 0x001FFFFF) - { - // U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - *pOutput = ((unic >> 18) & 0x07) | 0xF0; - *(pOutput + 1) = ((unic >> 12) & 0x3F) | 0x80; - *(pOutput + 2) = ((unic >> 6) & 0x3F) | 0x80; - *(pOutput + 3) = (unic & 0x3F) | 0x80; - return 4; - } - else if (unic >= 0x00200000 && unic <= 0x03FFFFFF) - { - // U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - *pOutput = ((unic >> 24) & 0x03) | 0xF8; - *(pOutput + 1) = ((unic >> 18) & 0x3F) | 0x80; - *(pOutput + 2) = ((unic >> 12) & 0x3F) | 0x80; - *(pOutput + 3) = ((unic >> 6) & 0x3F) | 0x80; - *(pOutput + 4) = (unic & 0x3F) | 0x80; - return 5; - } - else if (unic >= 0x04000000 && unic <= 0x7FFFFFFF) - { - // U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - *pOutput = ((unic >> 30) & 0x01) | 0xFC; - *(pOutput + 1) = ((unic >> 24) & 0x3F) | 0x80; - *(pOutput + 2) = ((unic >> 18) & 0x3F) | 0x80; - *(pOutput + 3) = ((unic >> 12) & 0x3F) | 0x80; - *(pOutput + 4) = ((unic >> 6) & 0x3F) | 0x80; - *(pOutput + 5) = (unic & 0x3F) | 0x80; - return 6; - } - return 0; -} - -// ----------------------------------------------------------------------------------- - -int enc_get_utf8_size(const unsigned char pInput) -{ - unsigned char c = pInput; - // 0xxxxxxx 返回0 0x0 - // 10xxxxxx 不存在 0x80 - // 110xxxxx 返回2 0xC0 - // 1110xxxx 返回3 0xE0 - // 11110xxx 返回4 0xF0 - // 111110xx 返回5 0xF8 - // 1111110x 返回6 0xFC - if (c < 0x80) - return 1; - if (c >= 0x80 && c < 0xC0) - return -1; - if (c >= 0xC0 && c < 0xE0) - return 2; - if (c >= 0xE0 && c < 0xF0) - return 3; - if (c >= 0xF0 && c < 0xF8) - return 4; - if (c >= 0xF8 && c < 0xFC) - return 5; - if (c >= 0xFC) - return 6; - return 1; -} -/***************************************************************************** -* 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码. -* -* 参数: -* pInput 指向输入缓冲区, 以UTF-8编码 -* Unic 指向输出缓冲区, 其保存的数据即是Unicode编码值, -* 类型为ulong . -* -* 返回值: -* 成功则返回该字符的Unicode编码所占用的字节数; 失败则返回0. -* -* 注意: -* 1. UTF8没有字节序问题, 但是Unicode有字节序要求; -* 字节序分为大端(Big Endian)和小端(Little Endian)两种; -* 在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位) -****************************************************************************/ -int enc_utf8_to_unicode_one(const uchar *pInput, uchar *Unic) -{ - assert(pInput != NULL && Unic != NULL); - - // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ... - char b1, b2, b3, b4, b5, b6; - - *Unic = 0x0; // 把 *Unic 初始化为全零 - int utfbytes = enc_get_utf8_size(*pInput); - uchar *pOutput = (uchar *)Unic; - - switch (utfbytes) - { - case 1: //1字节 - *pOutput = *pInput; - break; - case 2: //2字节 - b1 = *pInput; - b2 = *(pInput + 1); - if ((b2 & 0xC0) != 0x80) - return 0; - *pOutput = (b1 << 6) + (b2 & 0x3F); - *(pOutput + 1) = (b1 >> 2) & 0x07; - break; - case 3: - b1 = *pInput; - b2 = *(pInput + 1); - b3 = *(pInput + 2); - if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)) - return 0; - *pOutput = (b2 << 6) + (b3 & 0x3F); - *(pOutput + 1) = (b1 << 4) + ((b2 >> 2) & 0x0F); - break; - case 4: - b1 = *pInput; - b2 = *(pInput + 1); - b3 = *(pInput + 2); - b4 = *(pInput + 3); - if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) || ((b4 & 0xC0) != 0x80)) - return 0; - *pOutput = (b3 << 6) + (b4 & 0x3F); - *(pOutput + 1) = (b2 << 4) + ((b3 >> 2) & 0x0F); - *(pOutput + 2) = ((b1 << 2) & 0x1C) + ((b2 >> 4) & 0x03); - break; - case 5: - b1 = *pInput; - b2 = *(pInput + 1); - b3 = *(pInput + 2); - b4 = *(pInput + 3); - b5 = *(pInput + 4); - if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80)) - return 0; - *pOutput = (b4 << 6) + (b5 & 0x3F); - *(pOutput + 1) = (b3 << 4) + ((b4 >> 2) & 0x0F); - *(pOutput + 2) = (b2 << 2) + ((b3 >> 4) & 0x03); - *(pOutput + 3) = (b1 << 6); - break; - case 6: - b1 = *pInput; - b2 = *(pInput + 1); - b3 = *(pInput + 2); - b4 = *(pInput + 3); - b5 = *(pInput + 4); - b6 = *(pInput + 5); - if (((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80) || ((b6 & 0xC0) != 0x80)) - return 0; - *pOutput = (b5 << 6) + (b6 & 0x3F); - *(pOutput + 1) = (b5 << 4) + ((b6 >> 2) & 0x0F); - *(pOutput + 2) = (b3 << 2) + ((b4 >> 4) & 0x03); - *(pOutput + 3) = ((b1 << 6) & 0x40) + (b2 & 0x3F); - break; - default: - utfbytes = 0; - break; - } - return utfbytes; -} - -// ----------------------------------------------------------------------------------- - -char *enc_u2u8(char *data, uint *len) -{ - size_t t, i; - membuf_t buf; - membuf_init(&buf, 128); - (*len)--; - for (i = 0; i <= *len;) - { - if (buf.buffer_size - buf.size < 7) - membuf_reserve(&buf, 7); - t = enc_unicode_to_utf8_one(*(uint *)(data + i), (buf.data + buf.size), 7); - if (t == 0) - break; - buf.size += t; - } - membuf_trunc(&buf); - *len = buf.size; - return (char *)buf.data; -} - -// ----------------------------------------------------------------------------------- - -char *enc_u82u(char *data, uint *len) -{ - size_t t, i; - membuf_t buf; - membuf_init(&buf, 128); - for (i = 0; i < *len;) - { - if (buf.buffer_size - buf.size < 4) - membuf_reserve(&buf, 4); - t = enc_utf8_to_unicode_one((uchar *)(data + i), (uchar *)(buf.data + buf.size)); - if (t == 0) - break; - buf.size += 2; - i += t; - } - membuf_trunc(&buf); - *len = buf.size; - return (char *)buf.data; -} - -// ----------------------------------------------------------------------------------- - -//代码转换:从一种编码转为另一种编码 -size_t code_convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen, char *outbuf, uint *outlen) -{ - iconv_t cd; - size_t rc = 0, len = *outlen; - char **pin = &inbuf; - char **pout = &outbuf; - - cd = iconv_open(to_charset, from_charset); - if (cd == 0) - return -1; - memset(outbuf, 0, len); - if (iconv(cd, pin, (size_t *)&inlen, pout, (size_t *)&len) == -1) - rc = -1; - iconv_close(cd); - *outlen -= len; //返回已用长度 - return rc; -} - -// ----------------------------------------------------------------------------------- - -//GB2312 to unicode(need free) 返回字串长度为:实际长度+1, 末尾\0站一字节(需要释放) -char *GB2U(char *pszGbs, uint *aLen) -{ - size_t len = *aLen * 4; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("gb2312", "unicode", pszGbs, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -// ----------------------------------------------------------------------------------- - -//unicode to utf8(need free) 返回字串长度为:实际长度+1, 末尾\0站一字节(需要释放) -char *U2U8(char *wszUnicode, uint *aLen) -{ - size_t len = *aLen; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("unicode", "utf-8", wszUnicode, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -// ----------------------------------------------------------------------------------- - -//utf8 to unicode(need free) 返回字串长度为:实际长度+1, 末尾\0站一字节(需要释放) -char *U82U(char *szU8, uint *aLen) -{ - size_t len = *aLen * 2; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("utf-8", "unicode", szU8, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -// ----------------------------------------------------------------------------------- - -//unicode to GB2312(need free) 返回字串(需要释放)长度为:实际长度+1, 末尾\0站一字节 -char *U2GB(char *wszUnicode, uint *aLen) -{ - size_t len = *aLen; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("unicode", "gb2312", wszUnicode, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -// ----------------------------------------------------------------------------------- - -//GB2312 to utf8(need free) 返回字串(需要释放)长度为:实际长度+1, 末尾\0站一字节 -char *GB2U8(char *pszGbs, uint *aLen) -{ - size_t len = *aLen * 3; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("gb2312", "utf-8", pszGbs, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -// ----------------------------------------------------------------------------------- - -//utf8 to GB2312(need free) 返回字串(需要释放)长度为:实际长度+1, 末尾\0站一字节 -char *U82GB(char *szU8, uint *aLen) -{ - size_t len = *aLen; - char *outbuf = (char *)malloc(len + 1); - outbuf[0] = 0; - size_t rc = code_convert("utf-8", "gb2312", szU8, *aLen, outbuf, &len); - if (rc < 0) - *aLen = rc; - else - *aLen = len + 1; - return outbuf; -} - -/*************************************************************************** -* 函数名称: UTF8ToUCS2 -* 功能描述: 转换UTF8格式到UCS2格式(UCS2是双字节编码,Unicode是其中一种) -* 日 期: 2008-05-22 13:36:56 -* 作 者: lianxiuzhu -* 参数说明: binUTF8 - UTF8字节流数组 -* uCount - UTF8字节流数组中的字节数 -* binUCS2 - UCS2字节流数组 -* 返 回 值: 转换到UCS2字节流数组中的U16单元个数 -***************************************************************************/ -size_t UTF8ToUCS2(const uchar *binUTF8, size_t uCount, ushort *binUCS2) -{ - size_t uLength = 0; - uchar *szTemp = (uchar *)binUTF8; - while ((uint)(szTemp - binUTF8) < uCount) - { - if (*szTemp <= 0x7F) //0xxxxxxx - { - binUCS2[uLength] = binUCS2[uLength] | (ushort)(*szTemp & 0x7F); - szTemp = szTemp + 1; - } - else if (*szTemp <= 0xDF) //110xxxxx 10xxxxxx - { - binUCS2[uLength] = binUCS2[uLength] | (ushort)(*(szTemp + 1) & 0x3F); - binUCS2[uLength] = binUCS2[uLength] | ((ushort)(*(szTemp)&0x1F) << 6); - szTemp = szTemp + 2; - } - else if (*szTemp <= 0xEF) //1110xxxx 10xxxxxx 10xxxxxx - { - binUCS2[uLength] = binUCS2[uLength] | (ushort)(*(szTemp + 2) & 0x3F); - binUCS2[uLength] = binUCS2[uLength] | ((ushort)(*(szTemp + 1) & 0x3F) << 6); - binUCS2[uLength] = binUCS2[uLength] | ((ushort)(*(szTemp)&0x0F) << 12); - szTemp = szTemp + 3; - } - else - { - return 0; - } - - uLength++; - } - return uLength; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------url编码解码 win/linux -#pragma region url编码解码 - -// ----------------------------------------------------------------------------------- - -//url编码 (len为buf的长度) -char *url_encode(const char *url, uint *len) -{ - if (!url) - return NULL; - membuf_t buf; - const char *p; - const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}"; - const char hex[] = "0123456789ABCDEF"; - char enc[3] = {'%', 0, 0}; - len--; - membuf_init(&buf, strlen(url) + 1); - for (p = url; *p; p++) - { - if ((p - url) > *len) - break; - if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) - { - enc[1] = hex[*p >> 4]; - enc[2] = hex[*p & 0x0f]; - membuf_append_data(&buf, enc, 3); - } - else - { - membuf_append_data(&buf, p, 1); - } - } - membuf_trunc(&buf); - *len = buf.size; - return (char *)buf.data; -} - -// ----------------------------------------------------------------------------------- - -//url解码 -char *url_decode(char *url) -{ - char *o, *s; - uint tmp; - - for (o = s = url; *s; s++, o++) - { - if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) - { - *o = (char)tmp; - s += 2; - } - else - { - *o = *s; - } - } - *o = '\0'; - return url; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------Base64编码解码 win/linux -#pragma region Base64编码解码 - -char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -char base64_end = '='; - -// ----------------------------------------------------------------------------------- - -inline char is_base64(uchar c) -{ - return (isalnum(c) || (c == '+') || (c == '/')); -} - -// ----------------------------------------------------------------------------------- - -//Base64编码,需要释放返回值(need free return) -char *base64_Encode(const uchar *bytes_to_encode, uint in_len) -{ - membuf_t ret; - int i = 0, j = 0; - uchar char_array_3[3]; - uchar char_array_4[4]; - - membuf_init(&ret, in_len * 3); //初始化缓存字节数为 长度的3被 - - while (in_len--) - { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) - { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (i = 0; (i < 4); i++) - membuf_append_data(&ret, &base64_table[char_array_4[i]], 1); - i = 0; - } - } - - if (i) - { - for (j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - membuf_append_data(&ret, &base64_table[char_array_4[j]], 1); - - while ((i++ < 3)) - membuf_append_data(&ret, &base64_end, 1); - } - return (char *)ret.data; -} - -// ----------------------------------------------------------------------------------- - -//Base64解码,需要释放返回值(need free return) -char *base64_Decode(const char *encoded_string) -{ - size_t in_len = strlen(encoded_string); - int i = 0; - int j = 0; - size_t in_ = 0; - uchar char_array_4[4], char_array_3[3]; - membuf_t ret; - membuf_init(&ret, strlen(encoded_string) / 3 + 1); - - while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) - { - char_array_4[i++] = encoded_string[in_]; - in_++; - if (i == 4) - { - for (i = 0; i < 4; i++) - //char_array_4[i] = strstr(base64_table,(char*)&char_array_4[i])[0]; - char_array_4[i] = strchr(base64_table, char_array_4[i]) - base64_table; - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - membuf_append_data(&ret, &char_array_3[i], 1); - i = 0; - } - } - - if (i) - { - for (j = i; j < 4; j++) - char_array_4[j] = 0; - - for (j = 0; j < 4; j++) - //char_array_4[j] = strstr(base64_table, (char*)&char_array_4[j])[0]; - char_array_4[j] = strchr(base64_table, char_array_4[j]) - base64_table; - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) - membuf_append_data(&ret, &char_array_3[j], 1); - } - return (char *)ret.data; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------Hash1加密 win/linux -#pragma region Hash1加密 - -/**************** -* Rotate a 32 bit integer by n bytes -****************/ -#if defined(__GNUC__) && defined(__i386__) -static inline u32 rol(u32 x, int n) -{ - __asm__("roll %%cl,%0" - : "=r"(x) - : "0"(x), "c"(n)); - return x; -} -#else -#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -#endif - -// ----------------------------------------------------------------------------------- - -void hash1_Reset(SHA1_CONTEXT *hd) -{ - hd->bFinal = 0; - hd->h0 = 0x67452301; - hd->h1 = 0xefcdab89; - hd->h2 = 0x98badcfe; - hd->h3 = 0x10325476; - hd->h4 = 0xc3d2e1f0; - hd->nblocks = 0; - hd->count = 0; - memset(hd->buf, 0, 64); -} - -/* -* Transform the message X which consists of 16 32-bit-words -*/ -static void hash1_transform(SHA1_CONTEXT *hd, uchar *data) -{ - uint a, b, c, d, e, tm; - uint x[16]; - - /* get values from the chaining vars */ - a = hd->h0; - b = hd->h1; - c = hd->h2; - d = hd->h3; - e = hd->h4; - -#ifdef BIG_ENDIAN_HOST - memcpy(x, data, 64); -#else - { - int i; - uchar *p2; - for (i = 0, p2 = (uchar *)x; i < 16; i++, p2 += 4) - { - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; - } - } -#endif - -#define K1 0x5A827999L -#define K2 0x6ED9EBA1L -#define K3 0x8F1BBCDCL -#define K4 0xCA62C1D6L -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) (x ^ y ^ z) -#define F3(x, y, z) ((x & y) | (z & (x | y))) -#define F4(x, y, z) (x ^ y ^ z) - -#define M(i) (tm = x[i & 0x0f] ^ x[(i - 14) & 0x0f] ^ x[(i - 8) & 0x0f] ^ x[(i - 3) & 0x0f], (x[i & 0x0f] = rol(tm, 1))) - -#define R(a, b, c, d, e, f, k, m) \ - do \ - { \ - e += rol(a, 5) + f(b, c, d) + k + m; \ - b = rol(b, 30); \ - } while (0) - - R(a, b, c, d, e, F1, K1, x[0]); - R(e, a, b, c, d, F1, K1, x[1]); - R(d, e, a, b, c, F1, K1, x[2]); - R(c, d, e, a, b, F1, K1, x[3]); - R(b, c, d, e, a, F1, K1, x[4]); - R(a, b, c, d, e, F1, K1, x[5]); - R(e, a, b, c, d, F1, K1, x[6]); - R(d, e, a, b, c, F1, K1, x[7]); - R(c, d, e, a, b, F1, K1, x[8]); - R(b, c, d, e, a, F1, K1, x[9]); - R(a, b, c, d, e, F1, K1, x[10]); - R(e, a, b, c, d, F1, K1, x[11]); - R(d, e, a, b, c, F1, K1, x[12]); - R(c, d, e, a, b, F1, K1, x[13]); - R(b, c, d, e, a, F1, K1, x[14]); - R(a, b, c, d, e, F1, K1, x[15]); - R(e, a, b, c, d, F1, K1, M(16)); - R(d, e, a, b, c, F1, K1, M(17)); - R(c, d, e, a, b, F1, K1, M(18)); - R(b, c, d, e, a, F1, K1, M(19)); - R(a, b, c, d, e, F2, K2, M(20)); - R(e, a, b, c, d, F2, K2, M(21)); - R(d, e, a, b, c, F2, K2, M(22)); - R(c, d, e, a, b, F2, K2, M(23)); - R(b, c, d, e, a, F2, K2, M(24)); - R(a, b, c, d, e, F2, K2, M(25)); - R(e, a, b, c, d, F2, K2, M(26)); - R(d, e, a, b, c, F2, K2, M(27)); - R(c, d, e, a, b, F2, K2, M(28)); - R(b, c, d, e, a, F2, K2, M(29)); - R(a, b, c, d, e, F2, K2, M(30)); - R(e, a, b, c, d, F2, K2, M(31)); - R(d, e, a, b, c, F2, K2, M(32)); - R(c, d, e, a, b, F2, K2, M(33)); - R(b, c, d, e, a, F2, K2, M(34)); - R(a, b, c, d, e, F2, K2, M(35)); - R(e, a, b, c, d, F2, K2, M(36)); - R(d, e, a, b, c, F2, K2, M(37)); - R(c, d, e, a, b, F2, K2, M(38)); - R(b, c, d, e, a, F2, K2, M(39)); - R(a, b, c, d, e, F3, K3, M(40)); - R(e, a, b, c, d, F3, K3, M(41)); - R(d, e, a, b, c, F3, K3, M(42)); - R(c, d, e, a, b, F3, K3, M(43)); - R(b, c, d, e, a, F3, K3, M(44)); - R(a, b, c, d, e, F3, K3, M(45)); - R(e, a, b, c, d, F3, K3, M(46)); - R(d, e, a, b, c, F3, K3, M(47)); - R(c, d, e, a, b, F3, K3, M(48)); - R(b, c, d, e, a, F3, K3, M(49)); - R(a, b, c, d, e, F3, K3, M(50)); - R(e, a, b, c, d, F3, K3, M(51)); - R(d, e, a, b, c, F3, K3, M(52)); - R(c, d, e, a, b, F3, K3, M(53)); - R(b, c, d, e, a, F3, K3, M(54)); - R(a, b, c, d, e, F3, K3, M(55)); - R(e, a, b, c, d, F3, K3, M(56)); - R(d, e, a, b, c, F3, K3, M(57)); - R(c, d, e, a, b, F3, K3, M(58)); - R(b, c, d, e, a, F3, K3, M(59)); - R(a, b, c, d, e, F4, K4, M(60)); - R(e, a, b, c, d, F4, K4, M(61)); - R(d, e, a, b, c, F4, K4, M(62)); - R(c, d, e, a, b, F4, K4, M(63)); - R(b, c, d, e, a, F4, K4, M(64)); - R(a, b, c, d, e, F4, K4, M(65)); - R(e, a, b, c, d, F4, K4, M(66)); - R(d, e, a, b, c, F4, K4, M(67)); - R(c, d, e, a, b, F4, K4, M(68)); - R(b, c, d, e, a, F4, K4, M(69)); - R(a, b, c, d, e, F4, K4, M(70)); - R(e, a, b, c, d, F4, K4, M(71)); - R(d, e, a, b, c, F4, K4, M(72)); - R(c, d, e, a, b, F4, K4, M(73)); - R(b, c, d, e, a, F4, K4, M(74)); - R(a, b, c, d, e, F4, K4, M(75)); - R(e, a, b, c, d, F4, K4, M(76)); - R(d, e, a, b, c, F4, K4, M(77)); - R(c, d, e, a, b, F4, K4, M(78)); - R(b, c, d, e, a, F4, K4, M(79)); - - /* Update chaining vars */ - hd->h0 += a; - hd->h1 += b; - hd->h2 += c; - hd->h3 += d; - hd->h4 += e; -} - -// ----------------------------------------------------------------------------------- - -// Update the message digest with the contents of INBUF with length INLEN. -void hash1_Write(SHA1_CONTEXT *hd, uchar *inbuf, size_t inlen) -{ - if (hd->bFinal) - hash1_Reset(hd); - if (hd->count == 64) - { /* flush the buffer */ - hash1_transform(hd, hd->buf); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) - { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - hash1_Write(hd, NULL, 0); - if (!inlen) - return; - } - - while (inlen >= 64) - { - hash1_transform(hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; -} - - -// ----------------------------------------------------------------------------------- - -/* The routine final terminates the computation and returns the digest. -* The handle is prepared for a new cycle, but adding bytes to the -* handle will the destroy the returned buffer. -* Returns: 20 bytes representing the digest. -*/ -void hash1_Final(SHA1_CONTEXT *hd) -{ - uint t, msb, lsb; - uchar *p; - - hash1_Write(hd, NULL, 0); /* flush */ - ; - - t = hd->nblocks; - /* multiply by 64 to make a byte count */ - lsb = t << 6; - msb = t >> 26; - /* add the count */ - t = lsb; - if ((lsb += hd->count) < t) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 29; - - if (hd->count < 56) - { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 56) - hd->buf[hd->count++] = 0; /* pad */ - } - else - { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 64) - hd->buf[hd->count++] = 0; - hash1_Write(hd, NULL, 0); /* flush */ - ; - memset(hd->buf, 0, 56); /* fill next block with zeroes */ - } - /* append the 64 bit count */ - hd->buf[56] = msb >> 24; - hd->buf[57] = msb >> 16; - hd->buf[58] = msb >> 8; - hd->buf[59] = msb; - hd->buf[60] = lsb >> 24; - hd->buf[61] = lsb >> 16; - hd->buf[62] = lsb >> 8; - hd->buf[63] = lsb; - hash1_transform(hd, hd->buf); - - p = hd->buf; -#ifdef BIG_ENDIAN_HOST -#define X(a) \ - do \ - { \ - *(u32 *)p = hd->h##a; \ - p += 4; \ - } while (0) -#else /* little endian */ -#define X(a) \ - do \ - { \ - *p++ = hd->h##a >> 24; \ - *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; \ - *p++ = hd->h##a; \ - } while (0) -#endif - X(0); - X(1); - X(2); - X(3); - X(4); -#undef X - //Hash1 operation finally - hd->bFinal = 1; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------WebSocket win/linux -#pragma region WebSocket Tool - - -// ----------------------------------------------------------------------------------- - -//WebSocket握手Key计算 -char *WebSocketHandShak(const char *key) -{ - char akey[137] = {0}; - char acc[165] = {0}, *p; - int len; - SHA1_CONTEXT hd; - // - //char* p=strstr(header, "Sec-WebSocket-Key:");//不需要查找 Upgrade:为 "websocket" - //if (p) - //{ - //p += 19; - //char* p2=strst(p, "\r\n"); - strncpy(akey, key, 99); - strncpy(akey + strlen(key), "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36); - - hash1_Reset(&hd); - hash1_Write(&hd, (uchar *)akey, strlen(akey)); - hash1_Final(&hd); - p = base64_Encode(hd.buf, 20); - len = snprintf(acc, 164, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n", p); - free(p); - - p = (char *)malloc(len + 1); - memcpy(p, acc, len); - p[len] = 0; - return p; - //} - //else - // return NULL; -} - -// ----------------------------------------------------------------------------------- - -inline void WebSocketDoMask(char *data, ulong len, char *mask) -{ - ulong i = 0; - for (i = 0; i < len; i++) - data[i] = data[i] ^ mask[i % 4]; -} - -// ----------------------------------------------------------------------------------- - -//从帧中取得实际数据 -ulong WebSocketGetData(WebSocketHandle *handle, char *data, ulong len) -{ - if (!handle || !data) - return 0; - handle->isEof = (char)(data[0] >> 7); //是否结束 - handle->dfExt = (data[0] & 0x70); //扩展码 - handle->type = data[0] & 0xF; //OPCode - char hasMask = (char)(data[1] >> 7); - char Mask[4]; - membuf_t *buf = &handle->buf; - //Payload长度是ExtensionData长度与ApplicationData长度之和。 - //ExtensionData长度可能是0,这种情况下,Payload长度即是ApplicationData长度(默认ExtensionData长度是0) - ulong tLen; //本次真实数据长度 - ulong Len = data[1] & 0x7f; //Payload长度 - //当前帧,第一截数据 - if (Len < 126) //如果其值在0-125,则是payload的真实长度(ApplicationData长度,ExtensionData长度为0) - { - if (hasMask) - { - if ((len - 6) > 0) //防止结尾帧数据不够长度的错误 - { - memcpy(Mask, &data[2], 4); - tLen = len - 6; - Len = (Len > 0 && Len > tLen) ? tLen : Len; - membuf_append_data(buf, &data[6], Len); - WebSocketDoMask((char *)(buf->data + buf->size - Len), Len, Mask); - } - } - else //没用掩码 - if ((len - 2) > 0) - { - tLen = len - 2; - Len = (Len > 0 && Len > tLen) ? tLen : Len; - membuf_append_data(buf, &data[2], Len); - } - } - else if (Len == 126) //如果值是126,则后面2个字节形成的16位无符号整型数(ushort)的值是payload的真实长度,掩码就紧更着后面 - { - Len = data[2] * 0x100UL + (uchar)data[3]; //逐字节转换 - if (hasMask) - { - if ((len - 8) > 0) - { - memcpy(Mask, &data[4], 4); //防止结尾帧数据不够长度的错误 - tLen = len - 8; - Len = (Len > 0 && Len > tLen) ? tLen : Len; - membuf_append_data(buf, &data[8], Len); - WebSocketDoMask((char *)(buf->data + buf->size - Len), Len, Mask); - } - } - else //没用掩码 - if ((len - 4) > 0) - { - tLen = len - 4; - Len = Len > tLen ? tLen : Len; - membuf_append_data(buf, &data[4], tLen); - } - } - else if (Len == 127) //如果值是127,则后面8个字节形成的64位无符号整型数(uint64)的值是payload的真实长度,掩码就紧更着后面 - { - //Len = data[2] * 0x100000000000000ULL + data[3] * 0x1000000000000ULL + data[4] * 0x10000000000ULL + data[5] * 0x100000000ULL - // +data[6]*0x1000000ULL+data[7]*0x10000ULL+data[8]*0x100ULL+data[9]*0x1ULL;//逐字节转换 - Len = data[6] * 0x1000000ULL + data[7] * 0x10000ULL + data[8] * 0x100ULL + (uchar)data[9]; //逐字节转换为ulong - if (hasMask) - { - if ((len - 14) > 0) //防止结尾帧数据不够长度的错误 - { - memcpy(Mask, &data[10], 4); - tLen = len - 14; - Len = Len > tLen ? tLen : Len; - membuf_append_data(buf, &data[14], Len); - WebSocketDoMask((char *)(buf->data + buf->size - Len), Len, Mask); - } - } - else //没用掩码 - if ((len - 10) > 0) - { - tLen = len - 10; - Len = Len > tLen ? tLen : Len; - membuf_append_data(buf, &data[10], Len); - } - } - return Len; -} - -// ----------------------------------------------------------------------------------- - -//转换为一个WebSocket帧,无mask (need free return) -char *WebSocketMakeFrame(uchar *data, ulong *dlen, uchar op) -{ - if (data == NULL) - return NULL; - membuf_t buf; - membuf_init(&buf, 129); - //第一byte,10000000, fin = 1, rsv1 rsv2 rsv3均为0, opcode = 0x01,即数据为文本帧 - buf.data[0] = 0x80 + op; //0x81 最后一个包 |(无扩展协议)| 控制码(0x1表示文本帧) - if (*dlen > 0) - { //要有数据 - if (*dlen <= 125) - { - //数据长度 - buf.data[1] = (uchar)*dlen; - buf.size = 2; - } - else if (*dlen <= 65535) - { - buf.data[1] = 0x7E; - //数据长度 - buf.data[2] = (*dlen >> 8) & 255; - buf.data[3] = (*dlen) & 255; - buf.size = 4; - } - else - { - buf.data[1] = 0x7F; - //数据长度,前4字节留空,保存32位数据大小 - //buf.data[2] = (*dlen >> 56) & 255; - //buf.data[3] = (*dlen >> 48) & 255; - //buf.data[4] = (*dlen >> 40) & 255; - //buf.data[5] = (*dlen >> 32) & 255; - buf.data[6] = (*dlen >> 24) & 255; - buf.data[7] = (*dlen >> 16) & 255; - buf.data[8] = (*dlen >> 8) & 255; - buf.data[9] = (*dlen) & 255; - buf.size = 10; - } - } - membuf_append_data(&buf, data, *dlen); - *dlen = buf.size; - membuf_trunc(&buf); - return (char *)buf.data; -} - -#pragma endregion - -//-----------------------------------------------------------------------------------工具/杂项 win/linux -#pragma region 工具 / 杂项 - -// ----------------------------------------------------------------------------------- - -inline int day_of_year(int y, int m, int d) -{ - int k, leap, s; - int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - leap = (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0); - s = d; - for (k = 1; k < m; k++) - { - s += days[k]; - } - if (leap == 1 && m > 2) - s += 1; - return s; -} - -// ----------------------------------------------------------------------------------- - -//获取格林制(GMT)时间: "Wed, 18 Jul 2018 06:02:42 GMT" -//szDate: 存放GMT时间的缓存区(至少 char[30]),外部传入 -//szLen: szDate的长度大小 -//addSecond: 当前时间加上多少秒 -char *getGmtTime(char *szDate, int szLen, int addSecond) -{ - time_t rawTime; - struct tm *timeInfo; - time(&rawTime); - rawTime += addSecond; - timeInfo = gmtime(&rawTime); - strftime(szDate, szLen, "%a, %d %b %Y %H:%M:%S GMT", timeInfo); - return szDate; -} - -// ----------------------------------------------------------------------------------- - -//字符串转换成时间戳(秒),字符串格式为:"2016-08-03 06:56:36" -llong str2stmp(const char *strTime) -{ - if (strTime != NULL) - { - struct tm sTime; - memset(&sTime, 0, sizeof(struct tm)); - sTime.tm_isdst = -1; // daylight savings time flag -#ifdef __GNUC__ - if (strchr(strTime, '-')) - { - if (strlen(strTime) > 10) - strptime(strTime, "%Y-%m-%d %H:%M:%S", &sTime); - else - strptime(strTime, "%Y-%m-%d", &sTime); - } - else - { - if (strlen(strTime) > 10) - strptime(strTime, "%Y/%m/%d %H:%M:%S", &sTime); - else - strptime(strTime, "%Y/%m/%d", &sTime); - } -#else - if (strlen(strTime) > 10) - { - if (strchr(strTime, '-')) - sscanf(strTime, "%d-%d-%d %d:%d:%d", &sTime.tm_year, &sTime.tm_mon, &sTime.tm_mday, &sTime.tm_hour, &sTime.tm_min, &sTime.tm_sec); - else - sscanf(strTime, "%d/%d/%d %d:%d:%d", &sTime.tm_year, &sTime.tm_mon, &sTime.tm_mday, &sTime.tm_hour, &sTime.tm_min, &sTime.tm_sec); - } - else - { - if (strchr(strTime, '-')) - sscanf(strTime, "%d-%d-%d", &sTime.tm_year, &sTime.tm_mon, &sTime.tm_mday); - else - sscanf(strTime, "%d/%d/%d", &sTime.tm_year, &sTime.tm_mon, &sTime.tm_mday); - } - sTime.tm_year -= 1900; - sTime.tm_mon -= 1; - if (sTime.tm_year > 1100) //windows 下不能超过 3000-12-31, 千年虫 - sTime.tm_year = 1100; -#endif - return mktime(&sTime); - } - else - { - return time(0); - } -} - -// ----------------------------------------------------------------------------------- - -//时间戳(秒)转换成字符串,字符串格式为:"2016-08-03 06:56:36" -char *stmp2str(llong t, char *str, int strlen) -{ - if (t < 1000000) - t = time(0); - struct tm *sTime = localtime((time_t *)&t); - if (sTime) - strftime(str, strlen, "%Y-%m-%d %H:%M:%S", sTime); - return str; -} - - -// ----------------------------------------------------------------------------------- - -//从头比较字符串,返回相同的长度,不区分大小写 -size_t strinstr(const char *s1, const char *s2) -{ - const char *cur = s1; - while (s1 && *s1 > 0 && s2 && *s2 > 0) - { - if (*s1 == *s2 || (isalpha(*s1) && isalpha(*s2) && abs(*s1 - *s2) == 32)) - s1++, s2++; - else - break; - } - return s1 - cur; -} - -// ----------------------------------------------------------------------------------- - -//int32 转二进制字符串 -char *u2b(uint n) -{ - static char b[33] = {0}; - b[31] = '0'; - int i = 31; - uint p = 1; - for (; i >= 0; i--, p <<= 1) - { - b[i] = (n & p) ? '1' : '0'; - } - return b; -} - -// ----------------------------------------------------------------------------------- - -//int64 转二进制字符串 -char *u2b64(ullong n) -{ - static char b[65] = {0}; - b[63] = '0'; - int i = 63; - ullong p = 1; - for (; i >= 0; i--, p <<= 1) - { - b[i] = (n & p) ? '1' : '0'; - } - return b; -} - -// ----------------------------------------------------------------------------------- - -//获取当前时间信息 -tm_u GetLocaTime() -{ - struct timeval tv; //timespec - struct tm *p; - tm_u tmu; - - gettimeofday(&tv, NULL); - p = localtime(&tv.tv_sec); - - tmu.tm_sec = p->tm_sec; - tmu.tm_min = p->tm_min; - tmu.tm_hour = p->tm_hour; - tmu.tm_mday = p->tm_mday; - tmu.tm_mon = p->tm_mon + 1; - tmu.tm_year = p->tm_year + 1900; - tmu.tm_wday = p->tm_wday; - tmu.tm_yday = p->tm_yday; - tmu.tm_isdst = p->tm_isdst; - tmu.tm_vsec = tv.tv_sec; - tmu.tm_usec = tv.tv_usec; - return tmu; -} - -// ----------------------------------------------------------------------------------- - -//获取当天已逝去的秒数 -size_t GetDaySecond() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec % 86400); -} - -// ----------------------------------------------------------------------------------- - -static char CurIPv4[17] = {0}; -static char CurIPv6[50] = {0}; -static char CurMac[25] = {0}; - -#include -#include -#include -#include - -// ----------------------------------------------------------------------------------- - -//#include -//获取 IP,MAC 参见 http://www.cnblogs.com/lzpong/p/6956439.html -//获取 MAC 地址 -static char *getMac(char *mac, char *dv) -{ - struct ifreq ifreq; - int sock; - if (!mac || !dv) - return mac; - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - perror("socket "); - return mac; - } - strcpy(ifreq.ifr_name, dv); - if (ioctl(sock, SIOCGIFHWADDR, &ifreq) < 0) - { - perror("ioctl "); - return mac; - } - sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", //以太网MAC地址的长度是48位 - (unsigned char)ifreq.ifr_hwaddr.sa_data[0], - (unsigned char)ifreq.ifr_hwaddr.sa_data[1], - (unsigned char)ifreq.ifr_hwaddr.sa_data[2], - (unsigned char)ifreq.ifr_hwaddr.sa_data[3], - (unsigned char)ifreq.ifr_hwaddr.sa_data[4], - (unsigned char)ifreq.ifr_hwaddr.sa_data[5]); - return mac; -} - -// ----------------------------------------------------------------------------------- - -//获取IP地址 -static int GetIP_v4_and_v6_linux(int family) -{ - struct ifaddrs *ifaplist = NULL, *ifap = NULL; - void *tmpAddrPtr = NULL; - - getifaddrs(&ifaplist); - ifap = ifaplist; - while (ifap != NULL) - { - if (ifap->ifa_addr->sa_family == family) - { //AF_INET check it is IP4 - // is a valid IP4 Address - tmpAddrPtr = &((struct sockaddr_in *)ifap->ifa_addr)->sin_addr; - inet_ntop(AF_INET, tmpAddrPtr, CurIPv4, INET_ADDRSTRLEN); - if (strcmp(CurIPv4, "127.0.0.1") != 0) - { - getMac(CurMac, ifap->ifa_name); - break; - } - } - else if (ifap->ifa_addr->sa_family == family) - { //AF_INET6 check it is IP6 - // is a valid IP6 Address - tmpAddrPtr = &((struct sockaddr_in *)ifap->ifa_addr)->sin_addr; - inet_ntop(AF_INET6, tmpAddrPtr, CurIPv6, INET6_ADDRSTRLEN); - if (strcmp(CurIPv6, "::") != 0 && strcmp(CurIPv6, "::1") != 0) - { - getMac(CurMac, ifap->ifa_name); - break; - } - } - ifap = ifap->ifa_next; - } - if (ifaplist) - { - freeifaddrs(ifaplist); - ifaplist = NULL; - } - return -1; -} - -// ----------------------------------------------------------------------------------- - -//获取网卡地址 -const char *GetMacAddr() -{ - if (CurMac[0] < 1) - GetIP_v4_and_v6_linux(AF_INET); - return CurMac; -} - -// ----------------------------------------------------------------------------------- - -//获取IPv4地址 (第一个IPv4) -const char *GetIPv4() -{ - if (CurIPv4[0] < 1) - GetIP_v4_and_v6_linux(AF_INET); - return CurIPv4; -} - -// ----------------------------------------------------------------------------------- - -//获取IPv6地址 (第一个IPv6) -const char *GetIPv6() -{ - if (CurIPv6[0] < 1) - GetIP_v4_and_v6_linux(AF_INET6); - return CurIPv6; -} - -#pragma endregion diff --git a/src/tinyweb/tools.h b/src/tinyweb/tools.h deleted file mode 100644 index 9619542..0000000 --- a/src/tinyweb/tools.h +++ /dev/null @@ -1,263 +0,0 @@ -#pragma once -#ifndef __TOOLS_H__ -#define __TOOLS_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; -typedef long long llong; -typedef unsigned long long ullong; - -#define bitAdd(a, b) ((a) | (b)) -#define bitHas(a, b) ((a) & (b)) -#define bitRemove(a, b) ((a) & ~(b)) -#define Min(a, b) (((a) > (b)) ? (b) : (a)) -#define Max(a, b) (((a) > (b)) ? (a) : (b)) - -//-----------------------------------------------------------------------------------membuf c-str win/unix - -typedef struct membuf_t -{ - uchar *data; - size_t size; - size_t buffer_size; -} membuf_t; - -// ----------------------------------------------------------------------------------- - -void membuf_init(membuf_t *buf, size_t initial_buffer_size); -void membuf_uninit(membuf_t *buf); -size_t membuf_append(membuf_t *buf, const char *str); -size_t membuf_append_data(membuf_t *buf, const void *data, size_t size); -size_t membuf_append_format(membuf_t *buf, const char *fmt, ...); -void membuf_insert(membuf_t *buf, size_t offset, void *data, size_t size); -void membuf_move(membuf_t *buf, size_t offset, size_t size); -void membuf_clear(membuf_t *buf, size_t maxSize); -void membuf_reserve(membuf_t *buf, size_t extra_size); -void membuf_trunc(membuf_t *buf); - -#define _INLINE static inline - -//-----------------------------------------------------------------------------------membuf c-str win/unix - -_INLINE size_t membuf_append_byte(membuf_t *buf, uchar b) -{ - return membuf_append_data(buf, &b, sizeof(b)); -} - -_INLINE size_t membuf_append_int(membuf_t *buf, int i) -{ - return membuf_append_data(buf, &i, sizeof(i)); -} - -_INLINE size_t membuf_append_uint(membuf_t *buf, uint ui) -{ - return membuf_append_data(buf, &ui, sizeof(ui)); -} - -_INLINE size_t membuf_append_long(membuf_t *buf, long i) -{ - return membuf_append_data(buf, &i, sizeof(i)); -} - -_INLINE size_t membuf_append_ulong(membuf_t *buf, ulong ui) -{ - return membuf_append_data(buf, &ui, sizeof(ui)); -} - -_INLINE size_t membuf_append_short(membuf_t *buf, short s) -{ - return membuf_append_data(buf, &s, sizeof(s)); -} - -_INLINE size_t membuf_append_ushort(membuf_t *buf, ushort us) -{ - return membuf_append_data(buf, &us, sizeof(us)); -} - -_INLINE size_t membuf_append_float(membuf_t *buf, float f) -{ - return membuf_append_data(buf, &f, sizeof(f)); -} - -_INLINE size_t membuf_append_double(membuf_t *buf, double d) -{ - return membuf_append_data(buf, &d, sizeof(d)); -} - -_INLINE size_t membuf_append_ptr(membuf_t *buf, void *ptr) -{ - return membuf_append_data(buf, &ptr, sizeof(ptr)); -} - -//-----------------------------------------------------------------------------------File / folder detection win/unix - -//获取工作目录路径,不带'/' -char *getWorkPath(); - -//获取程序文件所在路径,不带'/' -char *getProcPath(); - -//建立目录,递归建立 (mod: linux系统需要,权限模式,, windows系统不需要) -int makeDir(const char *path, int mod); -//路径是否存在(0:不存在 1:存在:文件 2:存在:文件夹) -char isExist(const char *path); -//是否文件(1:是文件 0:非文件/不存在) -char isFile(const char *path); -//是否目录(1:是目录 0;非目录/不存在) -char isDir(const char *path); - -//返回列表目录Json字符串,need free the return -//{"path":"/","files":[{"name":"file.txt","mtime":"2014-04-18 23:24:05","size":463,"type":"F"}]} -char *listDir(const char *fullpath, const char *reqPath); - -//----------------------------------------------------------------------------------- Transcoding win/unix - -//GB2312 to unicode(need free return) 返回字串(需要释放)长度为:实际长度+2,返回长度小于0为:失败, 末尾\0\0占一字节 -char *GB2U(char *pszGbs, uint *aLen); -//unicode to utf8(need free return) 返回字串(需要释放)长度为:实际长度+1,返回长度小于0为:失败, 末尾\0占一字节 -char *U2U8(char *wszUnicode, uint *aLen); -//utf8 to unicode(need free return) 返回字串(需要释放)长度为:实际长度+2,返回长度小于0为:失败, 末尾\0\0占一字节 -char *U82U(char *szU8, uint *aaLen); -//unicode to GB2312(need free return) 返回字串(需要释放)长度为:实际长度+1,返回长度小于0为:失败, 末尾\0占一字节 -char *U2GB(char *wszUnicode, uint *aLen); - -//GB2312 to utf8(need free return) 返回字串(需要释放)长度为:实际长度+1,返回长度小于0为:失败, 末尾\0占一字节 -char *GB2U8(char *pszGbs, uint *aLen); -//utf8 to GB2312(need free return) 返回字串(需要释放)长度为:实际长度+1,返回长度小于0为:失败, 末尾\0占一字节 -char *U82GB(char *szU8, uint *aLen); - -char *enc_u82u(char *data, uint *len); -char *enc_u2u8(char *data, uint *len); - -//-----------------------------------------------------------------------------------Base64 encode decode win/unix - -//Base64编码,需要释放返回值(need free return) -char *base64_Encode(const uchar *bytes_to_encode, uint in_len); -//Base64解码,需要释放返回值(need free return) -char *base64_Decode(const char *encoded_string); - -//-----------------------------------------------------------------------------------SHA1计算摘要 win/unix - -typedef struct SHA1_CONTEXT -{ - char bFinal : 1; //是否计算完成 - uint h0, h1, h2, h3, h4; - uint nblocks; - uint count; - uchar buf[64]; //返回SHA1结果不是字符串,是定长的20字节数据,中间可能有'\0',,要作为字符输出:printf("%02X ", sh.buf[i]); -} SHA1_CONTEXT; - -//初始化/重置结构体 -void hash1_Reset(SHA1_CONTEXT *hd); - -//使用长度为 inlen 的 inbuf 内容更新消息摘要。 -void hash1_Write(SHA1_CONTEXT *hd, uchar *inbuf, size_t inlen); - -/*结束计算并返回摘要。 - *句柄准备用于新的循环,但是向句柄添加字节将破坏返回的缓冲区。 - *返回:表示摘要的20个字节。 - */ -void hash1_Final(SHA1_CONTEXT *hd); - -//-----------------------------------------------------------------------------------url encode decode win/unix - -//url编码 (len为url的长度) -char *url_encode(const char *url, uint *len); -//url解码 -char *url_decode(char *url); - -//-----------------------------------------------------------------------------------WebSocket win/unix - -//WebSocket以文本传输的时候,都为UTF - 8编码,是WebSocket协议允许的唯一编码 -//服务端收数据用 -typedef struct WebSocketHandle -{ - membuf_t buf; //原始帧数据 - //data[0] - uchar isEof : 1; //是否是结束帧 data[0]>>7 - uchar dfExt : 3; //是否有扩展定义 (data[0]>>4) & 0x7 - /*控制码/帧类型 type 的定义data[0] & 0xF - 0x0表示附加数据帧 - 0x1表示文本数据帧 - 0x2表示二进制数据帧 - 0x3-7暂时无定义,为以后的非控制帧保留 - 0x8表示连接关闭 - 0x9表示ping - 0xA表示pong - 0xB-F暂时无定义,为以后的控制帧保留 */ - uchar type : 4; -} WebSocketHandle; - -//传入http头,返回WebSocket握手Key,非http升级ws则返回NULL -//需要释放返回值(need free return) -char *WebSocketHandShak(const char *key); - -//从帧中取得实际数据 (帧不应超过32位大小) -ulong WebSocketGetData(WebSocketHandle *handle, char *data, ulong len); - -//转换为一个WebSocket帧,无mask (need free return) -//op:控制码/帧类型 0x0表示附加数据帧 0x1表示文本数据帧 ... -char *WebSocketMakeFrame(uchar *data, ulong *len, uchar op); - -//-----------------------------------------------------------------------------------工具函数/杂项 win/unix - -//获取IPv4地址 (第一个IPv4) -const char *GetIPv4(); -//获取IPv6地址 (第一个IPv6) -const char *GetIPv6(); -//获取网卡地址 -const char *GetMacAddr(); - -typedef struct tm_u -{ - int tm_sec; /*秒 seconds after the minute - [0,59] */ - int tm_min; /*分 minutes after the hour - [0,59] */ - int tm_hour; /*时 hours since midnight - [0,23] */ - int tm_mday; /*天 day of the month - [1,31] */ - int tm_mon; /*月 months since January - [1,12] */ - int tm_year; /*年 years since 1900 */ - int tm_wday; /*星期 days since Sunday - [0,6 0:周日] */ - int tm_yday; /*年中的天数 days since January 1 - [0,365] */ - int tm_isdst; /*夏令时标志 daylight savings time flag */ - llong tm_vsec; /*时间戳 seconds from 1900/1/1 0:0:0 */ - int tm_usec; /*微妙 microseconds */ -} tm_u; - -//获取当前时间信息 -tm_u GetLocaTime(); - -//获取当天已逝去的秒数 -size_t GetDaySecond(); - -//获取格林制(GMT)时间: "Wed, 18 Jul 2018 06:02:42 GMT" -//szDate: 存放GMT时间的缓存区(至少 char[30]),外部传入 -//szLen: szDate的长度大小 -//addSecond: 当前时间加上多少秒 -char *getGmtTime(char *szDate, int szLen, int addSecond); - -//字符串转换成时间戳(秒),字符串格式为:"2016-08-03 06:56:36" -llong str2stmp(const char *strTime); - -//时间戳(秒)转换成字符串,字符串格式为:"2016-08-03 06:56:36" -char *stmp2str(llong t, char *str, int strlen); - -//从头比较字符串,返回相同的长度,不区分大小写 -size_t strinstr(const char *s1, const char *s2); - -//int32 转二进制字符串 -char *u2b(uint n); -//int64 转二进制字符串 -char *u2b64(ullong n); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif //__TOOLS_H__ diff --git a/src/web/handler/exit-handler.cpp b/src/web/handler/exit-handler.cpp deleted file mode 100644 index 9d25bf2..0000000 --- a/src/web/handler/exit-handler.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/*! - * web-server.cpp - * - * Copyright (c) 2015-2019, NADAL Jean-Baptiste. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * @Author: NADAL Jean-Baptiste - * @Date: 14/11/2019 - * - */ - -// This is an independent project of an individual developer. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com - -/*------------------------------- INCLUDES ----------------------------------*/ - -#include - -#include "exit-handler.h" - -/*! ---------------------------------------------------------------------------- - * @fn ExitHandler - * - * @brief Constructor of the Exit Handler - */ -ExitHandler::ExitHandler(struct event_base *an_evt_loop) : m_evt_loop(an_evt_loop) -{ -} - -/*! ---------------------------------------------------------------------------- - * @fn handleGet - * - * @brief Exit Handler HandleGet method - */ -bool ExitHandler::handleGet(CivetServer *a_server, struct mg_connection *a_conn) -{ - mg_printf(a_conn, - "HTTP/1.1 200 OK\r\nContent-Type: " - "text/plain\r\nConnection: close\r\n\r\n"); - mg_printf(a_conn, "Bye!\n"); - event_base_loopbreak(m_evt_loop); - return true; -} diff --git a/src/web/handler/exit-handler.h b/src/web/handler/exit-handler.h deleted file mode 100644 index 3efbc1f..0000000 --- a/src/web/handler/exit-handler.h +++ /dev/null @@ -1,47 +0,0 @@ -/*! - * web-server.h - * - * Copyright (c) 2015-2019, NADAL Jean-Baptiste. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * @Author: NADAL Jean-Baptiste - * @Date: 14/11/2019 - * - */ - -#ifndef _EXIT_HANDLER_H -#define _EXIT_HANDLER_H - -/*------------------------------- INCLUDES ----------------------------------*/ - -#include "CivetServer.h" - -/*---------------------------------- Deps -----------------------------------*/ - -/*--------------------------------- CLASS ----------------------------------*/ - -class ExitHandler : public CivetHandler -{ -public: - ExitHandler(struct event_base *an_evt_loop); - bool handleGet(CivetServer *a_server, struct mg_connection *a_conn); - -private: - struct event_base *m_evt_loop; -}; - -#endif /* _EXIT_HANDLER_H */