add and compile tinyweb
This commit is contained in:
@@ -17,7 +17,8 @@ file(
|
||||
server/domo-server.cpp
|
||||
broker/nats-broker.cpp
|
||||
web/web-server.cpp
|
||||
web/handler/exit-handler.cpp
|
||||
tinyweb/tinyweb.c
|
||||
tinyweb/tools.c
|
||||
)
|
||||
|
||||
add_executable (domo-iot ${source_files})
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "domo-server.h"
|
||||
|
||||
#define kDocumentRoot "."
|
||||
#define kPort "8081"
|
||||
#define kPort 8081
|
||||
|
||||
/*! ----------------------------------------------------------------------------
|
||||
* @fn DomoServer
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
|
||||
//TinyWeb 增加与完善功能,by lzpong 2016/11/24
|
||||
// TinyWeb ajouté et amélioré les fonctions, par lzpong 2016/11/24
|
||||
|
||||
//值大,发送文件时磁盘和CPU性能更好,占用内存增加
|
||||
// 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 {
|
||||
|
||||
@@ -32,34 +32,33 @@
|
||||
#if TinyWeb_Function_Description //TinyWeb功能说明
|
||||
|
||||
auth lzpong 2016/11/24
|
||||
功能基于 libuv 跨平台库
|
||||
|
||||
0.支持设置文档编码,默认 utf-8
|
||||
1.支持使用HTTP: GET/POST方式访问
|
||||
2.支持Socket, WebSocket 连接
|
||||
3.支持返回404错误页面
|
||||
4.支持指定根目录(默认程序所在目录)
|
||||
5.支持任意格式文件访问(带/不带扩展名, 文件下载)
|
||||
a.支持静态网页访问:html/htm
|
||||
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],支持负反向计算)
|
||||
6.支持默认index页面(index.html/index.htm),可以自定义设置
|
||||
7.支持目录列表
|
||||
8.不允许访问根目录上级文件或文件夹
|
||||
9.支持回调
|
||||
a.接收到HTTP请求后先回调(此功能便于程序返回自定义功能),回调失败或返回0时执行普通http响应
|
||||
b.WebSocket 数据回调
|
||||
c.socket 数据回调
|
||||
10.支持x64,支持超过2G大文件
|
||||
11.支持cookie/setcookie
|
||||
12.支持添加自定义头部信息
|
||||
13.支持POST较大的数据(支持分包发送的http Post内容)
|
||||
==============stable,future
|
||||
14.支持分包发送的http头部(http get)
|
||||
|
||||
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
|
||||
@@ -67,7 +66,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct tw_peerAddr {
|
||||
uchar flag;//标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧)
|
||||
uchar flag;//flag ([0 ~ 7]: [0] Reste connecté ou non [1] WebSocket [2] Cadre WebSocket ou
|
||||
ushort port;
|
||||
ushort fport;
|
||||
size_t sk;
|
||||
@@ -78,52 +77,53 @@ typedef struct tw_peerAddr {
|
||||
typedef struct tw_reqHeads {
|
||||
uchar method;//0:Socket 1:GET 2:POST
|
||||
char host[260]; //IP:port, domain
|
||||
char path[512]; //路径
|
||||
char query[1500];//参数
|
||||
char* data; //数据
|
||||
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; //接收的数据长度
|
||||
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; //是否允许列出目录
|
||||
char* doc_dir; //Web根目录,绝对路径,末尾带斜杠'\'(uninx为'/'); 默认程序文件所在目录
|
||||
char* doc_index;//默认主页文件名,逗号分隔; 默认"index.html,index.htm"
|
||||
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; //服务监听端口
|
||||
char* charset; //文档编码(默认utf-8)
|
||||
//数据
|
||||
void* data;//用户数据,如对象指针
|
||||
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);
|
||||
|
||||
//返回非0表示已经处理处理请求
|
||||
//返回0表示没有适合的处理请求,将自动查找文件/文件夹,若未找到则发送404响应
|
||||
//此功能便于程序返回自定义功能
|
||||
//heads成员不需要free
|
||||
//pa->flag:标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧
|
||||
// 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);
|
||||
|
||||
//Socket 或 WebSocket 数据, 可以通过buf->flag 或 pa->flag判断
|
||||
//buf成员不需要free
|
||||
//pa->flag:标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧
|
||||
// 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);
|
||||
|
||||
//Socket 检测到错误(此时链接可能已经断开)
|
||||
//错误消息格式:"%d:%s,%s"
|
||||
//pa->flag:标志字节 ([0~7]: [0]是否需要保持连接 [1]是否WebSocket [2]是否WebSocket文本帧
|
||||
|
||||
// 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);
|
||||
|
||||
//Socket 已关闭(此时链接已经断开)
|
||||
//flag:标志字节 ([0~7]: [0]是否需要保持连接<非长连接为http> [1]是否WebSocket
|
||||
// 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 <la connexion non longue est http> [1] s'il faut WebSocket
|
||||
char (*on_close)(void* data, uv_stream_t* client, tw_peerAddr* pa);
|
||||
} tw_config;
|
||||
|
||||
@@ -131,7 +131,7 @@ typedef struct tw_config {
|
||||
//start web server, start with the config
|
||||
//loop: if is NULL , it will be uv_default_loop()
|
||||
//conf: the server config
|
||||
//返回值不为0表示错误代码,用uv_err_name(n),和uv_strerror(n)查看原因字符串
|
||||
// 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
|
||||
@@ -140,55 +140,55 @@ void tinyweb_stop(uv_loop_t* loop);
|
||||
|
||||
//=================================================
|
||||
|
||||
//制造头部 SetCookie 字段和值
|
||||
//set_cookie: 缓存区(至少 42+strlen(domain)=strlen(path) )
|
||||
//ckLen: set_cookie的长度
|
||||
//expires: 多少秒后过期
|
||||
//domain: Domain, 域名或IP地址
|
||||
//path: Path, 可以是 heads->path
|
||||
// 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);
|
||||
|
||||
//制造头部 delete cookie
|
||||
// créer un cookie d'en-tête
|
||||
void tw_make_delcookie(char* del_cookie, int ckLen, char* key);
|
||||
|
||||
//返回格式华的HTTP响应内容 (需要free返回数据)
|
||||
//status:http状态,如:"200 OK"
|
||||
//ext_heads:额外的头部字符串,如:"head1: this-is-head1\r\nSetCookie: TINY_SSID=Tiny1531896250879; Expires=...\r\n"
|
||||
//content_type:文件类型,如:"text/html" ;可以调用tw_get_content_type()得到
|
||||
//content:使用utf-8编码格式的数据,特别是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
|
||||
// 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);
|
||||
|
||||
//根据扩展名返回文件类型 content_type
|
||||
//可以传入路径/文件名/扩展名
|
||||
// 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);
|
||||
|
||||
//发送数据到客户端; 如果是短连接,则发送完后会关闭连接
|
||||
//data:待发送数据
|
||||
//len: 数据长度, -1 将自动计算数据长度
|
||||
//need_copy_data:是否需要复制数据
|
||||
//need_free_data:是否需要free数据, 如果need_copy_data非零则忽略此参数
|
||||
// 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);
|
||||
|
||||
//发送'200 OK' 响应; 不会释放(free)传入的数据(u8data)
|
||||
//content_type:Content Type 文档类型
|
||||
//u8data:utf-8编码的数据
|
||||
//content_length:数据长度,为0或-1时自动计算(strlen)(c_str, end with NULL)
|
||||
//respone_size:获取响应最终发送的数据长度,为0表示放不需要取此长度
|
||||
// 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);
|
||||
|
||||
//http协议发送文件,异步
|
||||
//file_path: 文件路径
|
||||
// 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);
|
||||
|
||||
//发送301响应,路径永久重定位
|
||||
// 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);
|
||||
//发送302响应,路径临时重定位
|
||||
// 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
|
||||
|
||||
1715
src/tinyweb/tools.c
Normal file
1715
src/tinyweb/tools.c
Normal file
File diff suppressed because it is too large
Load Diff
263
src/tinyweb/tools.h
Normal file
263
src/tinyweb/tools.h
Normal file
@@ -0,0 +1,263 @@
|
||||
#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__
|
||||
@@ -28,20 +28,100 @@
|
||||
|
||||
/*------------------------------- INCLUDES ----------------------------------*/
|
||||
|
||||
#include "CivetServer.h"
|
||||
|
||||
#include "web/handler/exit-handler.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "web-server.h"
|
||||
|
||||
#define EXIT_URI "/exit"
|
||||
//404前回调(未找到页面/文件时回调,此功能便于程序返回自定义功能);返回0表示没有适合的处理请求,需要发送404错误
|
||||
char on_request(void* data, uv_stream_t* client, tw_peerAddr* pa, tw_reqHeads* heads)
|
||||
{
|
||||
// struct sockaddr_in serveraddr, peeraddr;
|
||||
// char serv_ip[17],peer_ip[17], tmp[1024];
|
||||
// int addrlen = sizeof(struct sockaddr);
|
||||
// int r;
|
||||
//
|
||||
// //获取clientAddr: http://www.codes51.com/article/detail_113112.html
|
||||
// //本地接入地址
|
||||
// r = uv_tcp_getsockname((uv_tcp_t*)client, (struct sockaddr*)&serveraddr, &addrlen);
|
||||
// //网络字节序转换成主机字符序
|
||||
// uv_ip4_name(&serveraddr, (char*)serv_ip, sizeof(serv_ip));
|
||||
// //客户端的地址
|
||||
// r = uv_tcp_getpeername((uv_tcp_t*)client, (struct sockaddr*)&peeraddr, &addrlen);
|
||||
// //网络字节序转换成主机字符序
|
||||
// uv_ip4_name(&peeraddr, (char*)peer_ip, sizeof(peer_ip));
|
||||
//
|
||||
// sprintf(tmp, "<h1>Page not found:</h1><url>%s<br>%s<br></url><br><br><br><i>server:%s:%d\t\tpeer:%s:%d</i>\n", heads->path, (heads->query?heads->query:""), serv_ip, ntohs(serveraddr.sin_port), peer_ip, ntohs(peeraddr.sin_port));
|
||||
//#ifdef _MSC_VER //Windows下需要转换编码
|
||||
// size_t ll = strlen(tmp);
|
||||
// char *ch = GB2U8(tmp, &ll);
|
||||
// tw_send_200_OK(client, "text/html", ch, -1, 0);
|
||||
// free(ch);
|
||||
//#else //linux 下,系统是和源代码文件编码都是是utf8的,就不需要转换
|
||||
// tw_send_200_OK(client, "text/html", tmp, -1, 0);
|
||||
//#endif // _MSC_VER
|
||||
//
|
||||
printf(" sk:%zd Request:\n",pa->sk);
|
||||
printf(" Query: %s\n",heads->query);
|
||||
printf(" Path: %s\n",heads->path);
|
||||
printf(" Host: %s\n",heads->host);
|
||||
printf(" Cookie: %s\n", heads->cookie);
|
||||
printf(" Range: %lld-%lld\n",heads->Range_frm,heads->Range_to);
|
||||
printf(" data(%zd): %s\n", heads->len,heads->data);
|
||||
if (!heads->cookie)
|
||||
{
|
||||
char ck[512];
|
||||
tw_make_setcookie(ck, 255,"TINYSSID","FDSAFdfafdsafds", 3600 * 8, NULL, heads->path);
|
||||
tw_make_setcookie(ck + strlen(ck),255,"TINYSSID2","faFDSAF45dsafds", 0, heads->host, NULL);
|
||||
sprintf(ck + strlen(ck), "WWW-Authenticate: Basic realm=\".\"\r\n");
|
||||
size_t len;
|
||||
char* rp = tw_format_http_respone(client, "401 Unauthorized", ck, "text/plan", "", -1, &len);
|
||||
tw_send_data(client, rp, len, 0, 1);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char on_socket_data(void* data, uv_stream_t* client, tw_peerAddr* pa, membuf_t* buf)
|
||||
{
|
||||
if (buf->size < 1)
|
||||
return 1;//防止发生数据为空
|
||||
if (pa->flag & 0x2) { //WebSocket
|
||||
printf((const char*)buf->data, buf->size < 256 ? buf->size : 256);
|
||||
printf("-------------------------------------------ws:%zd dlen=%zd\n%s\n-------------------------------------------\n",pa->sk, buf->size, buf->data);
|
||||
ulong len = buf->size;
|
||||
char* p = WebSocketMakeFrame(buf->data, &len, 1);//文本帧
|
||||
tw_send_data(client, p, len, 0, 1);
|
||||
} else { //Socket
|
||||
printf("-------------------------------------------sk:%zd dlen=%zd\n%s\n-------------------------------------------\n",pa->sk, buf->size, buf->data);
|
||||
tw_send_data(client, buf->data, buf->size, 1, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char on_close(void* data, uv_stream_t* client, tw_peerAddr* pa)
|
||||
{
|
||||
//printf("closed: sk=%zd [%s:%d] from:%s:%d cli:%d\n", pa->sk, pa->ip, pa->port, pa->fip, pa->fport, client->loop->active_tcp_streams);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char on_connect(void* data, uv_stream_t* client, tw_peerAddr* pa)
|
||||
{
|
||||
//printf("connected: sk=%zd [%s:%d] from:%s:%d cli:%d\n",pa->sk,pa->ip,pa->port,pa->fip,pa->fport, client->loop->active_tcp_streams);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char on_error(void* data, uv_stream_t* client, tw_peerAddr* pa, int errcode, char* errstr)
|
||||
{
|
||||
//printf("error: sk=%zd [%s:%d] from:%s:%d cli:%d %s\n", pa->sk, pa->ip, pa->port, pa->fip, pa->fport, client->loop->active_tcp_streams,errstr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! ----------------------------------------------------------------------------
|
||||
* @fn WebServer
|
||||
*
|
||||
* @brief Constructor of the Web Server Object.
|
||||
*/
|
||||
WebServer::WebServer(void) : m_server(NULL)
|
||||
WebServer::WebServer(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -53,7 +133,6 @@ WebServer::WebServer(void) : m_server(NULL)
|
||||
|
||||
WebServer::~WebServer(void)
|
||||
{
|
||||
delete m_server;
|
||||
}
|
||||
|
||||
/*! ----------------------------------------------------------------------------
|
||||
@@ -61,18 +140,22 @@ WebServer::~WebServer(void)
|
||||
*
|
||||
* @brief Setup the Web server
|
||||
*/
|
||||
int WebServer::setup(const char *a_document_root, const char *a_port, struct event_base *an_evt_loop)
|
||||
int WebServer::setup(char *a_document_root, int a_port, uv_loop_t *an_evt_loop)
|
||||
{
|
||||
std::vector<std::string> the_options;
|
||||
memset(&m_conf, 0, sizeof(m_conf));
|
||||
m_conf.dirlist = 1;//目录列表
|
||||
//conf.ip = NULL;// "127.0.0.1";
|
||||
m_conf.port = a_port;
|
||||
m_conf.doc_dir = a_document_root;
|
||||
m_conf.doc_index = NULL;// Default homepage
|
||||
//m_conf.doc_dir = NULL;// The directory where the default program files are located
|
||||
|
||||
the_options.push_back("document_root");
|
||||
the_options.push_back(a_document_root);
|
||||
the_options.push_back("listening_ports");
|
||||
the_options.push_back(a_port);
|
||||
|
||||
m_server = new CivetServer(the_options);
|
||||
|
||||
m_server->addHandler(EXIT_URI, new ExitHandler(an_evt_loop));
|
||||
m_conf.on_request = on_request;
|
||||
m_conf.on_data = on_socket_data;
|
||||
m_conf.on_close = on_close;
|
||||
m_conf.on_connect = on_connect;
|
||||
m_conf.on_error = on_error;
|
||||
|
||||
tinyweb_start(an_evt_loop, &m_conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,14 +27,11 @@
|
||||
#define _WEB_SERVER_H
|
||||
|
||||
/*------------------------------- INCLUDES ----------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include <uv.h>
|
||||
#include <tinyweb/tinyweb.h>
|
||||
|
||||
/*---------------------------------- Deps -----------------------------------*/
|
||||
|
||||
class CivetServer;
|
||||
struct event_base;
|
||||
|
||||
/*--------------------------------- CLASS ----------------------------------*/
|
||||
|
||||
class WebServer
|
||||
@@ -43,10 +40,10 @@ public:
|
||||
WebServer(void);
|
||||
~WebServer(void);
|
||||
|
||||
int setup(const char *a_document_root, const char *a_port, struct event_base *an_evt_loop);
|
||||
int setup(char *a_document_root, int a_port, uv_loop_t *an_evt_loop);
|
||||
|
||||
private:
|
||||
CivetServer *m_server;
|
||||
tw_config m_conf;
|
||||
};
|
||||
|
||||
#endif /* __WEB_SERVER_H */
|
||||
|
||||
Reference in New Issue
Block a user