From baa2c7a9f1209dae511562c29dfe12a96500f9d5 Mon Sep 17 00:00:00 2001 From: lzpong Date: Wed, 18 Jul 2018 19:42:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8B=E8=BD=BD=20?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main.c | 6 +++--- tinyweb.c | 44 +++++++++++++++++++++----------------------- tinyweb.h | 31 +++++++++++++++---------------- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/Main.c b/Main.c index 2a0f8b6..34c6770 100644 --- a/Main.c +++ b/Main.c @@ -120,19 +120,19 @@ char on_socket_data(void* data, uv_stream_t* client, tw_peerAddr* pa, membuf_t* char on_close(void* data, uv_stream_t* client, tw_peerAddr* pa) { - printf("closed: sk=%d [%s:%d] flag=%d\n", pa->sk, pa->ip, pa->port,pa->flag); + printf("closed: sk=%zd [%s:%d] flag=%d\n", pa->sk, pa->ip, pa->port,pa->flag); return 0; } char on_error(void* data, uv_stream_t* client, tw_peerAddr* pa, int errcode, char* errstr) { - printf("error: sk=%d [%s:%d] flag=%d %s\n", pa->sk, pa->ip, pa->port,pa->flag, errstr); + printf("error: sk=%zd [%s:%d] flag=%d %s\n", pa->sk, pa->ip, pa->port,pa->flag, errstr); return 0; } char on_connect(void* data, uv_stream_t* client, tw_peerAddr* pa) { - printf("connected: sk=%d [%s:%d]\n",pa->sk,pa->ip,pa->port); + printf("connected: sk=%zd [%s:%d]\n",pa->sk,pa->ip,pa->port); return 0; } diff --git a/tinyweb.c b/tinyweb.c index e889906..ca404f6 100644 --- a/tinyweb.c +++ b/tinyweb.c @@ -15,7 +15,8 @@ //TinyWeb 增加与完善功能,by lzpong 2016/11/24 -#define TW_SEND_SIZE 1024*8 +//值大,发送文件时磁盘和CPU性能更好,占用内存增加 +#define TW_SEND_SIZE 1024*1024*16 typedef struct tw_file_t { //uchar flag; //连接的标志 @@ -31,8 +32,6 @@ typedef struct tw_client { }tw_client; //================================================= -//发送文件到客户端 -static char tw_http_send_file(uv_stream_t* client, const char* content_type,const char* ext_heads, const char* file, tw_reqHeads* heads); //关闭客户端连接后,释放客户端连接的数据 static void after_uv_close_client(uv_handle_t* client) { @@ -40,7 +39,7 @@ static void after_uv_close_client(uv_handle_t* client) { //如果有发送文件 if (clidata->ft.fp) { fclose(clidata->ft.fp); - printf("send file close left:%lld\n", clidata->ft.lsize); + printf("send file close sk:%lld left:%lld\n",clidata->pa.sk, clidata->ft.lsize); } //如果是WebSocket if (clidata->pa.flag & 0x2) { //WebSocket @@ -65,14 +64,13 @@ void tw_close_client(uv_stream_t* client) { static void after_uv_write(uv_write_t* w, int status) { tw_client* clidata = (tw_client*)w->handle->data; if (w->data) - free(w->data); //copyed data + free(w->data); //sended data //长连接就不关闭了 if (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:: error: handle Has been closed\n"); - return; } else uv_close((uv_handle_t*)w->handle, after_uv_close_client); @@ -105,7 +103,7 @@ void tw_send_data(uv_stream_t* client, const void* data, size_t len, char need_c uv_write(w, client, &buf, 1, after_uv_write); //free w and w->data in after_uv_write() } -//获取头部 SetCookie 字段值 +//制造头部 SetCookie 字段和值 //setCookie: 缓存区(至少 110+strlen(domain)=strlen(path) ),外部传入 //ckLen: set_cookie的长度 //expires: 多少秒后过期 @@ -194,12 +192,13 @@ static void tw_404_not_found(uv_stream_t* client, const char* pathinfo, const ch 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响应 -// -static void tw_301_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads) { + +//发送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[10245]; 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" @@ -213,8 +212,9 @@ static void tw_301_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ex tw_send_data(client, buffer, -1, 1, 1); } -//发送文件到客户端 -static char tw_http_send_file(uv_stream_t* client, const char* content_type, const char* ext_heads, const char* file, tw_reqHeads* heads) { +//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; tw_config* tw_conf = (tw_config*)(client->loop->data); tw_client* clidata = (tw_client*)client->data; @@ -222,8 +222,8 @@ static char tw_http_send_file(uv_stream_t* client, const char* content_type, con char szDate[30]; //发送头部 - if (!filet->fp && file) { - filet->fp = fopen(file, "rb"); + if (!filet->fp && file_path) { + filet->fp = fopen(file_path, "rb"); if (filet->fp) { #ifdef _WIN64 _fseeki64(filet->fp, 0, SEEK_END); @@ -249,8 +249,9 @@ static char tw_http_send_file(uv_stream_t* client, const char* content_type, con } else { tw_404_not_found(client, heads->path, ext_heads); - return 0; + return; } + ext_heads == NULL ? ext_heads = "" : 0; getGmtTime(szDate,30,0); respone = (char*)malloc(300 + 1); int respone_size; @@ -261,7 +262,6 @@ static char tw_http_send_file(uv_stream_t* client, const char* content_type, con 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/%lld\r\nContent-Length:%lld%s\r\n\r\n" , szDate, content_type, tw_conf->charset, heads->Range_frm, heads->Range_to, filet->fsize, (heads->Range_to- heads->Range_frm),ext_heads); tw_send_data(client, respone, respone_size, 0, 1); - return 1; } else { //发送文件 size_t read_size;// read_bytes; @@ -285,9 +285,7 @@ static char tw_http_send_file(uv_stream_t* client, const char* content_type, con filet->fsize = 0; tw_send_data(client, respone, TW_SEND_SIZE, 0, 1); } - return 1; } - return 0; } } @@ -339,7 +337,7 @@ const char* tw_get_content_type(const char* fileExt) { else if (strcmpi(fileExt, "apk") == 0) return "application/vnd.android.package-archive"; else - return "application/octet-stream"; + return octet; } //处理客户端请求 @@ -348,7 +346,7 @@ const char* tw_get_content_type(const char* fileExt) { //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 "" -void tw_request(uv_stream_t* client, tw_reqHeads* heads) { +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)); @@ -377,7 +375,7 @@ void tw_request(uv_stream_t* client, tw_reqHeads* heads) { p--; } } - tw_http_send_file(client, postfix ? tw_get_content_type(postfix) : "application/octet-stream", NULL, fullpath, heads); + tw_http_send_file(client, heads, NULL, tw_get_content_type(postfix), fullpath); } break; case 2://存在:文件夹 @@ -396,7 +394,7 @@ void tw_request(uv_stream_t* client, tw_reqHeads* heads) { snprintf(tmp, 259, "%s/%s", fullpath, p); if (isFile(tmp)) { - tw_http_send_file(client, "text/html", NULL, tmp, heads); + tw_http_send_file(client, heads, NULL, "text/html", tmp); break; } tmp[0] = 0; @@ -685,7 +683,7 @@ static void on_uv_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf) free(p2); } else if (heads.method) { //HTTP - //所有请求全部回调,返回非0,则继续 + //所有请求全部回调,返回非0表示已处理 if (tw_conf->on_request == 0 || 0 == tw_conf->on_request(tw_conf->data, client, &clidata->pa, &heads)) { tw_request(client, &heads); } diff --git a/tinyweb.h b/tinyweb.h index b7c61d3..725244e 100644 --- a/tinyweb.h +++ b/tinyweb.h @@ -41,10 +41,10 @@ auth lzpong 2016/11/24 4.支持指定根目录(默认程序所在目录) 5.支持任意格式文件访问(带/不带扩展名, 文件下载) a.支持静态网页访问:html/htm - b.支持其他静态文件:js, css, png, jpeg/jpg, gif, ico, txt, xml, json, log, wam, wav, mp3, apk + b.支持其他静态文件:js, css, png, jpeg/jpg, gif, ico, txt, xml, json, log, wam, wav, mp3, mp4, apk 等 c.支持其他文件格式, 默认文件类型为:"application/octet-stream" d.支持不带扩展名文件访问 - e.支持 Range 请求参数下载大文件(Range: bytes=sizeFrom-[sizeTo],都可正可负) + e.支持 Range 请求参数下载大文件(Range: bytes=sizeFrom-[sizeTo],支持负反向计算) 6.支持默认index页面(index.html/index.htm),可以自定义设置 7.支持目录列表 8.不允许访问根目录上级文件或文件夹 @@ -68,7 +68,7 @@ typedef struct tw_peerAddr { uchar flag;//标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧) ushort port; ushort fport; - uint sk; + size_t sk; char ip[17]; char fip[17]; }tw_peerAddr; @@ -86,10 +86,10 @@ typedef struct tw_reqHeads { //服务配置 typedef struct tw_config { - //private data: +//private data: uv_tcp_t _server; - //public data: +//public data: uchar dirlist:1; //是否允许列出目录 char* doc_dir; //Web根目录,绝对路径,末尾带斜杠'\'(uninx为'/'); 默认程序文件所在目录 char* doc_index;//默认主页文件名,逗号分隔; 默认"index.html,index.htm" @@ -115,7 +115,7 @@ typedef struct tw_config { char (*on_data)(void* data, uv_stream_t* client, tw_peerAddr* pa, membuf_t* buf); //Socket 检测到错误(此时链接可能已经断开) - //错误消息格式:"%d:%s,%s,%s" + //错误消息格式:"%d:%s,%s" //pa->flag:标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧 char (*on_error)(void* data, uv_stream_t* client, tw_peerAddr* pa,int errcode, char* errstr); @@ -137,7 +137,7 @@ void tinyweb_stop(uv_loop_t* loop); //================================================= -//获取头部 SetCookie 字段值 +//制造头部 SetCookie 字段和值 //set_cookie: 缓存区(至少 110+strlen(domain)=strlen(path) ),外部传入 //ckLen: set_cookie的长度 //expires: 多少秒后过期 @@ -145,14 +145,6 @@ void tinyweb_stop(uv_loop_t* loop); //path: Path, 可以是 heads->path,外部传入 void tw_make_cookie(char* set_cookie, int ckLen, int expires, char* domain, char* path); -//处理客户端请求 -//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). -//path: "/" or "/book/view/1" -//query: the string after '?' in url, such as "id=0&value=123", maybe NULL or "" -void tw_request(uv_stream_t* client, tw_reqHeads* heads); - //返回格式华的HTTP响应内容 (需要free返回数据) //status:http状态,如:"200 OK" //ext_heads:额外的头部字符串,如:"head1: this-is-head1\r\nSetCookie: TINY_SSID=Tiny1531896250879; Expires=...\r\n" @@ -179,7 +171,14 @@ void tw_send_data(uv_stream_t* client, const void* data, size_t len, char need_c //u8data:utf-8编码的数据 //content_length:数据长度,为-1时自动计算(strlen) //respone_size:获取响应最终发送的数据长度,为0表示放不需要取此长度 -void tw_send_200_OK(uv_stream_t* client, const char* content_type, const char* ext_heads, const void* u8data, size_t content_length, size_t* respone_size); +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); + +//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); + +//发送301响应,路径重定位 +void tw_301_Moved(uv_stream_t* client, tw_reqHeads* heads, const char* ext_heads); //关闭客户端连接 void tw_close_client(uv_stream_t* client);