添加了bltJsonDecode,bltJsonEncode,bltMd5,bltStr,bltCount,bltUnset等模块函数,此外,根据访问的文件名后缀设置响应头中的Content-Type,例如:.html设置为text/html,.css设置为text/css等,对于静态文件,会在响应头中输出Last-Modified,当客户端的请求头中包含了If-Modified-Since字段时,会将该字段的时间值,与所访问的静态文件的修改时间进行比较,如果两个时间相同,则返回304状态码...
/** * bltJsonDecode模块函数,将字符串进行json解码 * 例如: * json = '{"hello": "world!!", "name": "zengl", "val": "programmer", "arr":[1,2,3]}'; * json = bltJsonDecode(json); * for(i=0; bltIterArray(json,&i,&k,&v); ) * if(k == 'arr') * print 'arr:<br/>'; * for(j=0; bltIterArray(v,&j,&inner_k,&inner_v); ) * print ' -- ' + inner_k +": " + inner_v + '<br/>'; * endfor * else * print k +": " + v + '<br/>'; * endif * endfor * 执行结果如下: * hello: world!! * name: zengl * val: programmer * arr: * -- 0: 1 * -- 1: 2 * -- 2: 3 * 上面将json字符串解码为了zengl数组 * 第二个参数max_depth用于设置json最多解析的对象或数组的层次 * 例如,将上面代码json = bltJsonDecode(json);修改为json = bltJsonDecode(json,1);后,执行时就会报500错误 * 并在日志中输出 user defined error: json depth 2 is big than 1 的错误信息,也就是只能解析一层json对象或数组 * 第三个参数max_memory用于设置json解析最多可以使用的内存,例如: * 将代码修改为:json = bltJsonDecode(json,2,400);表示最多解析两层json对象或数组,同时,最多只能分配400字节的内存, * 如果json解析时,使用的内存超过400字节时,就会报500错误,同时日志中输出 * user defined error: bltJsonDecode error: Unable to parse data, json error: Memory allocation failure 的错误信息 * 表示内存分配失败,这里是由于内存超出允许使用的最大值而引起的 */ ZL_EXP_VOID module_builtin_json_decode(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: bltJsonDecode(str[, max_depth[, max_memory]])"); zenglApi_GetFunArg(VM_ARG,1,&arg); //得到第一个参数 if(arg.type != ZL_EXP_FAT_STR) zenglApi_Exit(VM_ARG,"first argument str of bltJsonDecode must be string"); json_char * json = (json_char *)arg.val.str; json_settings settings = { 0 }; settings.mem_alloc = my_json_mem_alloc; settings.mem_free = my_json_mem_free; settings.user_data = VM_ARG; settings.settings = json_enable_comments; unsigned int max_depth = 1000; if(argcount >= 2) { zenglApi_GetFunArg(VM_ARG,2,&arg); //得到第二个参数 if(arg.type != ZL_EXP_FAT_INT) zenglApi_Exit(VM_ARG,"the second argument max_depth of bltJsonDecode must be integer"); max_depth = (unsigned int)arg.val.integer; if(argcount >= 3) { zenglApi_GetFunArg(VM_ARG,3,&arg); //得到第三个参数 if(arg.type != ZL_EXP_FAT_INT) zenglApi_Exit(VM_ARG,"the third argument max_memory of bltJsonDecode must be integer"); settings.max_memory = (unsigned long)arg.val.integer; } } json_char json_error_str[json_error_max]; json_value * value; size_t json_length = strlen(json); // 通过json-parser第三方解析程式来解析会话文件中的json数据,解析的结果是一个json_value结构 value = json_parse_ex (&settings, json, json_length, json_error_str); if (value == NULL) { zenglApi_Exit(VM_ARG,"bltJsonDecode error: Unable to parse data, json error: %s", json_error_str); } ZENGL_EXPORT_MEMBLOCK memblock; switch (value->type) { case json_none: // 将json中的null转为整数0 zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0); break; case json_object: case json_array: // 如果是json对象或json数组,则创建一个memblock内存块 if(zenglApi_CreateMemBlock(VM_ARG,&memblock,0) == -1) { zenglApi_Exit(VM_ARG,zenglApi_GetErrorString(VM_ARG)); } // 通过process_json_object_array函数,循环将value中的json成员填充到memblock中 process_json_object_array(VM_ARG, &memblock, value, 1, max_depth); zenglApi_SetRetValAsMemBlock(VM_ARG,&memblock); break; case json_integer: zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, (ZL_EXP_LONG)value->u.integer, 0); break; case json_double: zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_FLOAT, ZL_EXP_NULL, 0, value->u.dbl); break; case json_string: zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, value->u.string.ptr, 0, 0); break; case json_boolean: // 将json中的bool类型转为整数,例如:true转为1,false转为0 zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, (ZL_EXP_LONG)value->u.boolean, 0); break; default: zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0); break; } json_value_free_ex (&settings, value); } /** * bltJsonEncode模块函数,将data参数进行json编码,返回json格式的字符串 * 例如: * array['username'] = 'zenglong'; * array['password'] = '123456'; * tmp = bltArray(100,200,300,400,500,600); * array['tmp'] = tmp; * json = bltJsonEncode(array); * print 'array转json字符串:<br/>'; * print json + '<br/><br/>'; * 执行结果如下: * array转json字符串: * {"username":"zenglong","password":"123456","tmp":[100,200,300,400,500,600]} * 上面是数组转json的例子,对于整数,浮点数,直接返回整数和浮点数的字符串形式 * 对于字符串类型的参数,直接将字符串的原值返回 * 其他类型的参数都返回null字符串 */ ZL_EXP_VOID module_builtin_json_encode(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: bltJsonEncode(data)"); zenglApi_GetFunArg(VM_ARG,1,&arg); BUILTIN_INFO_STRING infoString = { 0 }; switch(arg.type) { case ZL_EXP_FAT_MEMBLOCK: // 通过builtin_write_array_to_string函数将zengl数组转为json格式的字符串 builtin_write_array_to_string(VM_ARG, &infoString, arg.val.memblock); break; case ZL_EXP_FAT_INT: builtin_make_info_string(VM_ARG, &infoString, "%ld",arg.val.integer); break; case ZL_EXP_FAT_FLOAT: builtin_make_info_string(VM_ARG, &infoString, "%.16g",arg.val.floatnum); break; case ZL_EXP_FAT_STR: builtin_make_info_string(VM_ARG, &infoString, "%s",arg.val.str); break; default: zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, "null", 0, 0); return; } if(infoString.str != NULL) { zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, infoString.str, 0, 0); zenglApi_FreeMem(VM_ARG, infoString.str); } else zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, "null", 0, 0); } /** * bltMd5模块函数,获取字符串的md5值,第一个参数str是要转成md5的字符串 * 第二个参数isLowerCase表示是否生成小写的md5值(默认值是1,也就是小写,将该参数设置为0,可以生成大写的md5值) * 第三个参数is32表示是否生成32位的md5值(默认值是1,也就是32位,将该参数设置为0,可以生成16位的md5值) * 例如: * def MD5_LOWER_CASE 1; * def MD5_UPPER_CASE 0; * def MD5_32BIT 1; * def MD5_16BIT 0; * print '"admin@123456"的md5值:<br/>'; * print bltMd5('admin@123456') + ' [32位小写]<br/>'; * print bltMd5('admin@123456', MD5_UPPER_CASE) + ' [32位大写]<br/>'; * print bltMd5('admin@123456', MD5_LOWER_CASE, MD5_16BIT) + ' [16位小写]<br/>'; * print bltMd5('admin@123456', MD5_UPPER_CASE, MD5_16BIT) + ' [16位大写]<br/><br/>'; * 执行结果如下: * "admin@123456"的md5值: * f19b8dc2029cf707939e886e4b164681 [32位小写] * F19B8DC2029CF707939E886E4B164681 [32位大写] * 029cf707939e886e [16位小写] * 029CF707939E886E [16位大写] */ ZL_EXP_VOID module_builtin_md5(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: bltMd5(str[, isLowerCase[, is32]])"); zenglApi_GetFunArg(VM_ARG,1,&arg); if(arg.type != ZL_EXP_FAT_STR) zenglApi_Exit(VM_ARG,"first argument str of bltMd5 must be string"); MD5_CTX md5; MD5Init(&md5); unsigned char * encrypt = (unsigned char *)arg.val.str; unsigned char decrypt[16]; MD5Update(&md5,encrypt,strlen((char *)encrypt)); MD5Final(&md5,decrypt); int isLowerCase = ZL_EXP_TRUE; int is32 = ZL_EXP_TRUE; if(argcount >= 2) { zenglApi_GetFunArg(VM_ARG,2,&arg); if(arg.type != ZL_EXP_FAT_INT) zenglApi_Exit(VM_ARG,"the second argument isLowerCase of bltMd5 must be integer"); isLowerCase = arg.val.integer; if(argcount >= 3) { zenglApi_GetFunArg(VM_ARG,3,&arg); if(arg.type != ZL_EXP_FAT_INT) zenglApi_Exit(VM_ARG,"the third argument is32 of bltMd5 must be integer"); is32 = arg.val.integer; } } char buf[33]; char * p = buf; int start_idx = is32 ? 0 : 4; int end_idx = is32 ? 16 : 12; const char * format = isLowerCase ? "%02x" : "%02X"; for(int i = start_idx; i < end_idx; i++) { sprintf(p, format, decrypt[i]); p += 2; } (*p) = '\0'; zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, buf, 0, 0); } /** * bltStr模块函数,返回第一个参数的字符串形式 * 如果第一个参数的值为NONE类型,要获取他对应的字符串形式即空字符串,需要将第一个参数的引用传递过来 * 例如: * print 'bltStr(test): "' + bltStr(test) + '"<br/>'; * print 'bltStr(&test): "' + bltStr(&test) + '"<br/>'; * 执行的结果如下: * bltStr(test): "0" * bltStr(&test): "" * 上面test在没有被赋值的情况下,是NONE类型,NONE类型变量在参与运算或者以参数形式传递给函数时,是以整数0的形式进行运算和传递的 * 因此,要将NONE转为空字符串返回,需要将test的引用传递进去 * 如果将第二个参数设置为非0值,bltStr会同时将转化的结果赋值给第一个参数(需要将第一个参数的引用传递进来) * 例如: * def TRUE 1; * def FALSE 0; * print 'test: "' + test + '"<br/>'; * bltStr(&test, TRUE); * print 'test: "' + test + '"<br/><br/>'; * 执行结果如下: * test: "0" * test: "" * 在经过bltStr(&test, TRUE);转化后,test就被赋值为了空字符串 */ ZL_EXP_VOID module_builtin_str(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: bltStr(data|&data[, isSetData=0])"); zenglApi_GetFunArg(VM_ARG,1,&arg); int isSetData = ZL_EXP_FALSE; if(argcount >= 2) { ZENGL_EXPORT_MOD_FUN_ARG arg2 = {ZL_EXP_FAT_NONE,{0}}; zenglApi_GetFunArg(VM_ARG,2,&arg2); if(arg2.type != ZL_EXP_FAT_INT) zenglApi_Exit(VM_ARG,"the second argument isSetData of bltStr must be integer"); isSetData = arg2.val.integer; } char * retstr; char tmpstr[40]; switch(arg.type) { case ZL_EXP_FAT_STR: retstr = arg.val.str; break; case ZL_EXP_FAT_INT: snprintf(tmpstr, 40, "%ld", arg.val.integer); retstr = tmpstr; break; case ZL_EXP_FAT_FLOAT: snprintf(tmpstr, 40, "%.16g", arg.val.floatnum); retstr = tmpstr; break; case ZL_EXP_FAT_MEMBLOCK: retstr = "[array or class obj type]"; break; default: retstr = ""; break; } if(isSetData) { if(arg.type != ZL_EXP_FAT_STR) { arg.type = ZL_EXP_FAT_STR; arg.val.str = retstr; zenglApi_SetFunArg(VM_ARG,1,&arg); } } zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_STR, retstr, 0, 0); } /** * bltCount模块函数,获取数组的有效成员数,或者获取字符串的有效长度 */ ZL_EXP_VOID module_builtin_count(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount < 1) zenglApi_Exit(VM_ARG,"usage: bltCount(data)"); zenglApi_GetFunArg(VM_ARG,1,&arg); int retcount; switch(arg.type) { case ZL_EXP_FAT_STR: retcount = strlen(arg.val.str); break; case ZL_EXP_FAT_MEMBLOCK: retcount = zenglApi_GetMemBlockNNCount(VM_ARG, &arg.val.memblock); break; default: retcount = 0; break; } zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, retcount, 0); } /** * bltGetZenglServerVersion模块函数,获取zenglServer的版本号 */ ZL_EXP_VOID module_builtin_get_zengl_server_version(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; ZENGL_EXPORT_MEMBLOCK memblock; if(zenglApi_CreateMemBlock(VM_ARG,&memblock,0) == -1) { zenglApi_Exit(VM_ARG,zenglApi_GetErrorString(VM_ARG)); } arg.type = ZL_EXP_FAT_INT; arg.val.integer = ZLSERVER_MAJOR_VERSION; zenglApi_SetMemBlock(VM_ARG,&memblock,1,&arg); arg.val.integer = ZLSERVER_MINOR_VERSION; zenglApi_SetMemBlock(VM_ARG,&memblock,2,&arg); arg.val.integer = ZLSERVER_REVISION; zenglApi_SetMemBlock(VM_ARG,&memblock,3,&arg); zenglApi_SetRetValAsMemBlock(VM_ARG,&memblock); } /** * bltGetZenglVersion模块函数,获取zengl语言的版本号 */ ZL_EXP_VOID module_builtin_get_zengl_version(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; ZENGL_EXPORT_MEMBLOCK memblock; if(zenglApi_CreateMemBlock(VM_ARG,&memblock,0) == -1) { zenglApi_Exit(VM_ARG,zenglApi_GetErrorString(VM_ARG)); } arg.type = ZL_EXP_FAT_INT; arg.val.integer = ZL_EXP_MAJOR_VERSION; zenglApi_SetMemBlock(VM_ARG,&memblock,1,&arg); arg.val.integer = ZL_EXP_MINOR_VERSION; zenglApi_SetMemBlock(VM_ARG,&memblock,2,&arg); arg.val.integer = ZL_EXP_REVISION; zenglApi_SetMemBlock(VM_ARG,&memblock,3,&arg); zenglApi_SetRetValAsMemBlock(VM_ARG,&memblock); } /** * builtin模块的初始化函数,里面设置了与该模块相关的各个模块函数及其相关的处理句柄 */ ZL_EXP_VOID module_builtin_init(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT moduleID) { ..................................... zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltUnset",zenglApiBMF_unset); ..................................... zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltJsonDecode",module_builtin_json_decode); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltJsonEncode",module_builtin_json_encode); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltMd5",module_builtin_md5); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltStr",module_builtin_str); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltCount",module_builtin_count); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltGetZenglServerVersion",module_builtin_get_zengl_server_version); zenglApi_SetModFunHandle(VM_ARG,moduleID,"bltGetZenglVersion",module_builtin_get_zengl_version); } |
use builtin; def TRUE 1; def FALSE 0; def MD5_LOWER_CASE 1; def MD5_UPPER_CASE 0; def MD5_32BIT 1; def MD5_16BIT 0; print '<!Doctype html> <html> <head><meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>json编解码测试</title> </head> <body>'; json = '{"hello": "world!!", "name": "zengl", "val": "programmer", "arr":[1,2,3]}'; json = bltJsonDecode(json); //json = bltJsonDecode(json,1); //json = bltJsonDecode(json,2,400); for(i=0; bltIterArray(json,&i,&k,&v); ) if(k == 'arr') print 'arr:<br/>'; for(j=0; bltIterArray(v,&j,&inner_k,&inner_v); ) print ' -- ' + inner_k +": " + inner_v + '<br/>'; endfor else print k +": " + v + '<br/>'; endif endfor array['username'] = 'zenglong'; array['password'] = '123456'; tmp = bltArray(100,200,300,400,500,600); array['tmp'] = tmp; json = bltJsonEncode(array); print '<br/>'; print 'array转json字符串:<br/>'; print json + '<br/><br/>'; print '"admin@123456"的md5值:<br/>'; print bltMd5('admin@123456') + ' [32位小写]<br/>'; print bltMd5('admin@123456', MD5_UPPER_CASE) + ' [32位大写]<br/>'; print bltMd5('admin@123456', MD5_LOWER_CASE, MD5_16BIT) + ' [16位小写]<br/>'; print bltMd5('admin@123456', MD5_UPPER_CASE, MD5_16BIT) + ' [16位大写]<br/><br/>'; print 'bltStr(test): "' + bltStr(test) + '"<br/>'; print 'bltStr(&test): "' + bltStr(&test) + '"<br/>'; print 'test: "' + test + '"<br/>'; bltStr(&test, TRUE); print 'test: "' + test + '"<br/><br/>'; print 'bltCount(array): ' + bltCount(array) + '<br/>'; print 'bltCount("hello world"): ' + bltCount("hello world") + '<br/><br/>'; bltUnset(&array['tmp']); print 'array after unset:<br/>'; print bltJsonEncode(array) + '<br/>'; print 'bltCount(array): ' + bltCount(array) + '<br/><br/>'; zls_version = bltGetZenglServerVersion(); print 'zenglServer版本号:' + zls_version[0] + '.' + zls_version[1] + '.' + zls_version[2] + '<br/>'; zl_version = bltGetZenglVersion(); print 'zengl语言版本号:' + zl_version[0] + '.' + zl_version[1] + '.' + zl_version[2]; print '</body></html>'; |
use builtin, request; rqtSetResponseHeader("HTTP/1.1 302 Moved Temporarily"); rqtSetResponseHeader("Location: test.zl"); bltExit(); |
/** * sessDelete模块函数,根据sess_file_name会话文件名删除会话文件 */ ZL_EXP_VOID module_session_delete(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ZENGL_EXPORT_MOD_FUN_ARG arg = {ZL_EXP_FAT_NONE,{0}}; if(argcount != 1) zenglApi_Exit(VM_ARG,"usage:sessDelete(sess_file_name)"); // 获取第一个参数,也就是会话文件名 zenglApi_GetFunArg(VM_ARG,1,&arg); if(arg.type != ZL_EXP_FAT_STR) { zenglApi_Exit(VM_ARG,"the first argument [sess_file_name] of sessDelete must be string"); } // 如果是空的会话文件名,直接返回0 if(strlen(arg.val.str) == 0) { zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 0, 0); return; } char filename[SESSION_FILEPATH_MAX_LEN]; char * session_dir; long session_expire; // 先通过main_get_session_config函数获取会话目录,然后根据会话目录和会话文件名生成会话文件的相对路径 main_get_session_config(&session_dir, &session_expire, NULL); session_make_filename(filename, session_dir, arg.val.str); struct stat filestatus; if ( stat(filename, &filestatus) == 0) { remove(filename); // 删除会话文件 } zenglApi_SetRetVal(VM_ARG, ZL_EXP_FAT_INT, ZL_EXP_NULL, 1, 0); } |
use builtin, request, session; def TRUE 1; print '<!Doctype html> <html> <head><meta http-equiv="content-type" content="text/html;charset=utf-8" /> <title>删除会话测试</title> </head> <body>'; cookies = rqtGetCookie(); bltStr(&cookies['SESSION'], TRUE); if(bltCount(cookies['SESSION']) == 0) print 'cookie中的SESSION为空,没有要删除的会话!'; else sess_data = sessGetData(cookies['SESSION']); if(bltCount(sess_data) > 0) sessDelete(cookies['SESSION']); rqtSetResponseHeader("Set-Cookie: SESSION=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT;"); print '删除会话: ' + cookies['SESSION'] + ' 成功!'; else print '会话: ' + cookies['SESSION'] + ' 不存在,或者已经被删除!'; endif endif print '</body></html>'; |
/** * 判断指针con对应的连接,是否是有效的mysql连接 */ static ZL_EXP_BOOL is_valid_mysql_connection(RESOURCE_LIST * resource_list, void * con) { int ret = resource_list_get_ptr_idx(resource_list, con, module_mysql_free_connection_resource_callback); if(ret >= 0) return ZL_EXP_TRUE; else return ZL_EXP_FALSE; } /** * 判断指针res对应的结果集,是否是有效的mysql结果集 */ static ZL_EXP_BOOL is_valid_mysql_result(RESOURCE_LIST * resource_list, void * res) { int ret = resource_list_get_ptr_idx(resource_list, res, module_mysql_free_result_resource_callback); if(ret >= 0) return ZL_EXP_TRUE; else return ZL_EXP_FALSE; } ................................................. /** * mysqlGetServerVersion模块函数对应的C函数 * 通过mysql_get_server_version官方库函数,获取服务端的版本号信息, * 主版本,子版本,修正版本号会依次存储在返回数组的前三个成员中 */ ZL_EXP_VOID module_mysql_get_server_version(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ..................................................... MYSQL *con = (MYSQL *)arg.val.integer; MAIN_DATA * my_data = zenglApi_GetExtraData(VM_ARG, "my_data"); if(!is_valid_mysql_connection(&(my_data->resource_list), con)) { zenglApi_Exit(VM_ARG,"mysqlGetServerVersion runtime error: invalid connection"); } ..................................................... } ................................................. /** * mysqlFreeResult模块函数对应的C函数 * 通过mysql_free_result官方库函数,将结果指针中的mysql_res给释放掉,再通过zenglApi_FreeMem接口将结果指针释放掉 * 最后通过resource_list_remove_member函数,将结果指针从资源列表中移除 */ ZL_EXP_VOID module_mysql_free_result(ZL_EXP_VOID * VM_ARG,ZL_EXP_INT argcount) { ..................................................... MODULE_MYSQL_RES * result = (MODULE_MYSQL_RES *)arg.val.integer; MAIN_DATA * my_data = zenglApi_GetExtraData(VM_ARG, "my_data"); if(!is_valid_mysql_result(&(my_data->resource_list), result)) { zenglApi_Exit(VM_ARG,"mysqlFreeResult runtime error: invalid result"); } ..................................................... } ................................................. |
............................................... /** * 根据文件名后缀检测内容类型的结构体 */ typedef struct _SERVER_CONTENT_TYPE{ const char * suffix; // 文件名后缀 int suffix_length; // 后缀长度 const char * content_type; // 内容类型 } SERVER_CONTENT_TYPE; ............................................... // server_content_types数组中存储了文件名后缀与内容类型之间的对应关系 static SERVER_CONTENT_TYPE server_content_types[] = { {".html", 5, "text/html"}, {".css", 4, "text/css"}, {".js", 3, "application/javascript"}, {".png", 4, "image/png"}, {".jpg", 4, "image/jpeg"}, {".jpeg", 5, "image/jpeg"}, {".gif", 4, "image/gif"}, {".ico", 4, "image/x-icon"} }; // server_content_types数组的成员个数 static int server_content_types_number = 8; /** * 通过检测文件名后缀,在响应头中输出相应的Content-Type内容类型(IE高版本浏览器,css样式文件如果没有Content-Type,会报Mime类型不匹配而被忽略的警告信息,从而导致样式不生效) */ static int main_output_content_type(char * full_path, CLIENT_SOCKET_LIST * socket_list, int lst_idx) { int full_length = strlen(full_path); for(int i=0; i < server_content_types_number; i++) { SERVER_CONTENT_TYPE * sct = &server_content_types[i]; if(full_length > sct->suffix_length && (full_path[full_length -1] == sct->suffix[sct->suffix_length - 1])) { if(strncmp(full_path + (full_length - sct->suffix_length), sct->suffix, sct->suffix_length) == 0) { client_socket_list_append_send_data(socket_list, lst_idx, "Content-Type: ", 14); client_socket_list_append_send_data(socket_list, lst_idx, (char *)sct->content_type, strlen(sct->content_type)); client_socket_list_append_send_data(socket_list, lst_idx, "\r\n", 2); return 1; } } } return 0; } /** * 将buffer字符串解析成相应的时间结构 */ static void main_parse_date(const char *buffer, struct tm *date) { int len; char firstElement[20]; sscanf(buffer, "%s", firstElement); len = strlen(firstElement); switch (len) { /* RFC 822, updated by RFC 1123; firstElement "[wkday]," */ case 4: strptime(buffer, "%a, %d %b %Y %T GMT", date); break; /* ANSI C's asctime() format; firstElement "[wkday]" */ case 3: strptime(buffer, "%a %b %d %T %Y", date); break; /* RFC 850, obsoleted by RFC 1036; firstElement "[weekdey], * " */ default: strptime(buffer, "%A, %d-%b-%y %T GMT", date); } } /** * 比较两个时间结构,判断他们是否相等 */ static int main_compare_dates(const struct tm *date1, const struct tm *date2) { time_t sec1; time_t sec2; sec1 = mktime((struct tm*) date1); sec2 = mktime((struct tm*) date2); return (sec2 - sec1); } /** * 根据静态文件的修改时间,生成Last-Modified响应头 */ static void main_output_last_modified(struct stat * filestatus, CLIENT_SOCKET_LIST * socket_list, int lst_idx) { char dateLine[60]; struct tm * tempDate; tempDate = gmtime(&filestatus->st_mtim.tv_sec); strftime(dateLine, 60, "Last-Modified: %a, %d %b %Y %T GMT\r\n", tempDate); client_socket_list_append_send_data(socket_list, lst_idx, dateLine, strlen(dateLine)); } /** * 如果客户的的请求头中包含了If-Modified-Since字段的话,就将该字段的时间值,与所访问的静态文件的修改时间进行比较 * 如果两个时间相同,则返回304状态码 */ static void main_process_if_modified_since(char * request_header, int request_header_count, struct stat * filestatus, CLIENT_SOCKET_LIST * socket_list, int lst_idx, int * status_code) { const char * if_modified_since = "If-Modified-Since"; int if_modified_since_length = strlen(if_modified_since); char * tmp = request_header; char * end = request_header + request_header_count; do{ ZL_EXP_CHAR * field = tmp; ZL_EXP_CHAR * value = field + strlen(field) + 1; if(field >= end || value >= end) { break; } int field_len = strlen(field); if(field_len == if_modified_since_length) { if(!strcasecmp(field, if_modified_since)) { struct tm reqestedDate; main_parse_date(value, &reqestedDate); struct tm * fileModDate = gmtime(&(filestatus->st_mtime)); if(!main_compare_dates(&reqestedDate, fileModDate)) { if((*status_code) == 200) { (*status_code) = 304; } return; } } } tmp = value + strlen(value) + 1; } while(1); } .................................................. static int routine_process_client_socket(CLIENT_SOCKET_LIST * socket_list, int lst_idx) { .................................................. // 如果doc_fd大于0,则直接输出相关的静态文件的内容 if(doc_fd > 0) { client_socket_list_append_send_data(socket_list, lst_idx, "HTTP/1.1 ", 9); ZL_EXP_BOOL is_reg_file = ZL_EXP_TRUE; // 非常规文件,直接返回403禁止访问 if(!S_ISREG(filestatus.st_mode)) { status_code = 403; is_reg_file = ZL_EXP_FALSE; } else main_process_if_modified_since(parser_data->request_header.str, parser_data->request_header.count, &filestatus, socket_list, lst_idx, &status_code); switch(status_code){ case 403: client_socket_list_append_send_data(socket_list, lst_idx, "403 Forbidden\r\n", 15); break; case 404: client_socket_list_append_send_data(socket_list, lst_idx, "404 Not Found\r\n", 15); break; case 200: client_socket_list_append_send_data(socket_list, lst_idx, "200 OK\r\n", 8); client_socket_list_append_send_data(socket_list, lst_idx, "Cache-Control: public, max-age=600\r\n", 36); break; case 304: client_socket_list_append_send_data(socket_list, lst_idx, "304 Not Modified\r\n", 18); client_socket_list_append_send_data(socket_list, lst_idx, "Cache-Control: public, max-age=600\r\n", 36); break; } char doc_fd_content_length[20] = {0}; if(is_reg_file && status_code != 304) { // 获取常规文件的内容长度,并根据文件名后缀,在响应头中输出文件类型 content_length = (int)lseek(doc_fd, 0, SEEK_END); lseek(doc_fd, 0, SEEK_SET); if(main_output_content_type(full_path, socket_list, lst_idx) && (status_code == 200)) { main_output_last_modified(&filestatus, socket_list, lst_idx); } } else content_length = 0; sprintf(doc_fd_content_length, "%d", content_length); client_socket_list_append_send_data(socket_list, lst_idx, "Content-Length: ", 16); client_socket_list_append_send_data(socket_list, lst_idx, doc_fd_content_length, strlen(doc_fd_content_length)); client_socket_list_append_send_data(socket_list, lst_idx, "\r\nConnection: Closed\r\nServer: zenglServer\r\n\r\n", 45); if(is_reg_file && status_code != 304) { // 输出常规文件的内容 char buffer[1025]; int data_length; while((data_length = read(doc_fd, buffer, sizeof(buffer))) > 0){ client_socket_list_append_send_data(socket_list, lst_idx, buffer, data_length); } } close(doc_fd); } .................................................. } |
zenglServer v0.18.0 直接在命令行中执行脚本
zenglServer v0.15.0 - v0.15.1 增加curl模块,用于执行数据抓取操作
zenglServer v0.19.0 增加redis缓存相关的模块
zenglServer v0.24.0 增加bltVersionCompare,mysqlAffectedRows模块函数,为bltStr增加format可选参数
zenglServer v0.10.0 使用zengl脚本的编译缓存,跳过编译过程
zenglServer v0.10.1 添加bltInt,bltFloat,bltHtmlEscape模块函数,使用v1.8.1版本的zengl语言库