From 378ccb421f1d26f9e31b7e5da70441f6a3327b0d Mon Sep 17 00:00:00 2001 From: Lao Ke <36225368+kehengzhong@users.noreply.github.com> Date: Thu, 8 Apr 2021 22:54:06 +0800 Subject: [PATCH] Add files via upload --- src/http_cache.c | 2 +- src/http_cgi.c | 69 ++- src/http_chunk.c | 2 +- src/http_cli_io.c | 27 +- src/http_con.c | 2 +- src/http_cookie.c | 5 +- src/http_dispdir.c | 2 +- src/http_do.c | 4 +- src/http_fcgi_con.c | 2 +- src/http_fcgi_srv.c | 2 +- src/http_form.c | 23 +- src/http_handle.c | 27 +- src/http_header.c | 2 +- src/http_listen.c | 840 ++++++++++++++++++++++++------- src/http_log.c | 2 +- src/http_mgmt.c | 36 +- src/http_msg.c | 84 +++- src/http_pagetpl.c | 338 +++++++++++++ src/http_pump.c | 4 +- src/http_request.c | 2 +- src/http_response.c | 93 ++-- src/http_script.c | 1168 ++++++++++++++++++++++++++++++++++++------- src/http_sndpxy.c | 2 +- src/http_srv.c | 2 +- src/http_srv_io.c | 9 +- src/http_ssl.c | 4 +- src/http_status.c | 2 +- src/http_uri.c | 2 +- src/http_variable.c | 2 +- 29 files changed, 2275 insertions(+), 484 deletions(-) create mode 100644 src/http_pagetpl.c diff --git a/src/http_cache.c b/src/http_cache.c index 115d4b8..51806d8 100644 --- a/src/http_cache.c +++ b/src/http_cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_cgi.c b/src/http_cgi.c index 80b4f19..b6d498f 100644 --- a/src/http_cgi.c +++ b/src/http_cgi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -85,6 +85,15 @@ int RecycleFrame (void * vmsg, frame_p frame) return 0; } +int GetMethodInd (void * vmsg) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + + if (!msg) return 0; + + return msg->req_methind; +} + char * GetMethod (void * vmsg) { HTTPMsg * msg = (HTTPMsg *)vmsg; @@ -253,32 +262,40 @@ int GetReqPath (void * vmsg, char * path, int pathlen) char * GetRootPath (void * vmsg) { HTTPMsg * msg = (HTTPMsg *)vmsg; - HTTPLoc * ploc = NULL; + HTTPHost * phost = NULL; + HTTPLoc * ploc = NULL; - if (!msg || !msg->ploc) return "."; + if (!msg) return "."; + + if (!msg->ploc) { + if (msg->phost) { + phost = (HTTPHost *)msg->phost; + return phost->root; + } + return "."; + } - ploc = (HTTPLoc *)msg->ploc; - + ploc = (HTTPLoc *)msg->ploc; + return ploc->root; } int GetRealPath (void * vmsg, char * path, int len) { HTTPMsg * msg = (HTTPMsg *)vmsg; - HTTPLoc * ploc = NULL; + char * root = NULL; int slen = 0; int retlen = 0; - if (!msg || !msg->ploc) return -1; + if (!msg) return -1; if (!path || len <= 0) return -2; - ploc = (HTTPLoc *)msg->ploc; - - retlen = strlen(ploc->root); + root = GetRootPath(msg); + retlen = str_len(root); if (path && len > 0) - str_secpy(path, len, ploc->root, retlen); - + str_secpy(path, len, root, retlen); + if (path) { slen = strlen(path); uri_decode(msg->docuri->dir, msg->docuri->dirlen, path + slen, len - slen); @@ -294,19 +311,19 @@ int GetRealFile (void * vmsg, char * path, int len) { HTTPMsg * msg = (HTTPMsg *)vmsg; HTTPLoc * ploc = NULL; - int slen = 0; + char * root = NULL; + int i, slen = 0; int retlen = 0; - if (!msg || !msg->ploc) return -1; + if (!msg) return -1; if (!path || len <= 0) return -2; - ploc = (HTTPLoc *)msg->ploc; - - retlen = strlen(ploc->root); + root = GetRootPath(msg); + retlen = str_len(root); if (path && len > 0) - str_secpy(path, len, ploc->root, retlen); - + str_secpy(path, len, root, retlen); + if (msg->docuri->path && msg->docuri->pathlen > 0) { if (path) { slen = strlen(path); @@ -322,7 +339,19 @@ int GetRealFile (void * vmsg, char * path, int len) retlen += 1; } + if (path && file_is_dir(path) && (ploc = msg->ploc)) { + slen = strlen(path); + for (i = 0; i < ploc->indexnum; i++) { + snprintf(path + slen, len - slen, "%s", ploc->index[i]); + if (file_is_regular(path)) { + return strlen(path); + } + } + path[slen] = '\0'; + } + if (path) return strlen(path); + return retlen; } @@ -1935,7 +1964,7 @@ int AddResFile (void * vmsg, char * filename, int64 startpos, int64 len) } addfile: - if (startpos >= st.st_size && st.st_size > 0) return -100; + if (startpos >= st.st_size) return -100; if (len < 0 || len > st.st_size - startpos) len = st.st_size - startpos; diff --git a/src/http_chunk.c b/src/http_chunk.c index 5e4f555..af2df99 100644 --- a/src/http_chunk.c +++ b/src/http_chunk.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_cli_io.c b/src/http_cli_io.c index 1db6bb7..5020c2d 100644 --- a/src/http_cli_io.c +++ b/src/http_cli_io.c @@ -118,7 +118,7 @@ int http_cli_accept (void * vmgmt, void * listendev) #ifdef HAVE_OPENSSL if (pcon->ssl_link) { - pcon->sslctx = http_listen_ssl_ctx_get(hl, pcon); + pcon->sslctx = http_listen_ssl_ctx_get(hl); pcon->ssl = http_ssl_new(pcon->sslctx, pcon); pcon->ssl_handshaked = 0; pcon->rcv_state = HTTP_CON_SSL_HANDSHAKING; @@ -250,6 +250,7 @@ int http_cli_recv_parse (void * vcon) int64 hdrlen = 0; uint8 * pbyte = NULL; uint8 * pbgn = NULL; + char buf[2048]; HTTPMsg * proxymsg = NULL; FcgiMsg * cgimsg = NULL; @@ -381,6 +382,12 @@ int http_cli_recv_parse (void * vcon) http_req_set_docuri(msg, frameP(msg->uri->uri), frameL(msg->uri->uri), 0, 0); } + /* if set the check callback, all requests including proxy mode will be checked */ + if (mgmt->req_check) { + msg->GetRealFile(msg, buf, sizeof(buf)-1); + (*mgmt->req_check)(mgmt->req_checkobj, msg, buf); + } + /* determine if request body is following, set the rcv_state of HTTPCon */ if ( ( msg->req_body_flag == BC_CONTENT_LENGTH && msg->req_body_length > 0 ) || @@ -396,7 +403,7 @@ int http_cli_recv_parse (void * vcon) if (http_fcgi_handle(msg) >= 0) return 0; - + return http_reqbody_handle(msg); } @@ -408,12 +415,12 @@ int http_reqbody_handle (void * vmsg) HTTPMsg * msg = (HTTPMsg *)vmsg; HTTPCon * pcon = NULL; int ret = 0; - + if (!msg) return -1; - + pcon = (HTTPCon *)msg->pcon; if (!pcon) return -2; - + /* HTTP POST/PUT request body may be encoded as following enctype: (1) application/x-www-form-urlencoded (2) multipart/form-data @@ -421,7 +428,7 @@ int http_reqbody_handle (void * vmsg) (4) text/xml (5) application/octet-stream */ - + switch (msg->req_body_flag) { case BC_CONTENT_LENGTH: case BC_TE: @@ -432,15 +439,15 @@ int http_reqbody_handle (void * vmsg) pcon->rcv_state = HTTP_CON_WAITING_BODY; } else { pcon->rcv_state = HTTP_CON_READY; - + return 1; } break; - + case BC_TE_INVALID: case BC_UNKNOWN: return -108; - + case BC_NONE: case BC_TUNNEL: default: @@ -448,7 +455,7 @@ int http_reqbody_handle (void * vmsg) return 2; break; } - + return 0; } diff --git a/src/http_con.c b/src/http_con.c index 2f4647b..e686346 100644 --- a/src/http_con.c +++ b/src/http_con.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_cookie.c b/src/http_cookie.c index a891baf..2a05ca5 100644 --- a/src/http_cookie.c +++ b/src/http_cookie.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -281,10 +281,11 @@ int cookie_mgmt_read (void * vmgmt, char * cookiefile) mgmt->cookie_file = cookiefile; + buf[0] = '\0'; for ( ; !feof(fp); ) { fgets(buf, sizeof(buf)-1, fp); p = str_trim(buf); - len = strlen(buf); + len = strlen(p); if (len <= 0 || *p == '#') continue; diff --git a/src/http_dispdir.c b/src/http_dispdir.c index 13eb67c..b9e4c25 100644 --- a/src/http_dispdir.c +++ b/src/http_dispdir.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_do.c b/src/http_do.c index 69ec05c..360fb2f 100644 --- a/src/http_do.c +++ b/src/http_do.c @@ -162,7 +162,7 @@ void * do_http_get_msg (void * vmgmt, char * url, int urllen, msg->dstport = msg->req_port; - msg->SetResponseHandle(msg, resfunc, para, cbval, resfile, resoff, rcvprocfunc, funcpara); + msg->SetResponseNotify(msg, resfunc, para, cbval, resfile, resoff, rcvprocfunc, funcpara); http_header_append(msg, 0, "Accept", -1, hdr_accept, strlen(hdr_accept)); http_header_append(msg, 0, "Accept-Charset", -1, hdr_accept_charset, strlen(hdr_accept_charset)); @@ -228,7 +228,7 @@ void * do_http_post_msg (void * vmgmt, char * url, int urllen, char * mime, msg->dstport = msg->req_port; - msg->SetResponseHandle(msg, resfunc, para, cbval, resfile, resoff, rcvprocfunc, rcvpara); + msg->SetResponseNotify(msg, resfunc, para, cbval, resfile, resoff, rcvprocfunc, rcvpara); http_header_append(msg, 0, "Accept", -1, hdr_accept, strlen(hdr_accept)); http_header_append(msg, 0, "Accept-Charset", -1, hdr_accept_charset, strlen(hdr_accept_charset)); diff --git a/src/http_fcgi_con.c b/src/http_fcgi_con.c index eade6da..b6f3f99 100644 --- a/src/http_fcgi_con.c +++ b/src/http_fcgi_con.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_fcgi_srv.c b/src/http_fcgi_srv.c index 90668b0..688102d 100644 --- a/src/http_fcgi_srv.c +++ b/src/http_fcgi_srv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_form.c b/src/http_form.c index 70a34c0..13cfaf6 100644 --- a/src/http_form.c +++ b/src/http_form.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -95,6 +95,27 @@ void http_form_free (void * vform) kfree(form); } +void * http_form_node (void * vmsg, char * key) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + http_form_t * form = NULL; + int i, num; + + if (!msg || !key) return NULL; + + num = arr_num(msg->req_formlist); + for (i = 0; i < num; i++) { + form = arr_value(msg->req_formlist, i); + if (!form) continue; + + if (form->name && strcasecmp(key, form->name) == 0) { + return form; + } + } + + return NULL; +} + int http_form_get (void * vmsg, char * key, char ** ctype, uint8 * formtype, char ** fname, int64 * valuelen) { HTTPMsg * msg = (HTTPMsg *)vmsg; diff --git a/src/http_handle.c b/src/http_handle.c index 4ac77c5..dc075ab 100644 --- a/src/http_handle.c +++ b/src/http_handle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -134,7 +134,7 @@ int http_request_process (void * vcon, void * vmsg) HTTPMgmt * mgmt = NULL; CacheInfo * cacinfo = NULL; char path[1024]; - int i, ret = -100; + int i, fret, ret = -100; ulong msgid = 0; if (!pcon) return -1; @@ -184,14 +184,23 @@ int http_request_process (void * vcon, void * vmsg) http_req_set_docuri(msg, frameP(msg->uri->uri), frameL(msg->uri->uri), 0, 0); } - if (msg->issued <= 0 && mgmt->req_handler) { - msg->cbobj = mgmt->req_cbobj; - ret = (*mgmt->req_handler)(mgmt->req_cbobj, msg); + ploc = (HTTPLoc *)msg->ploc; + + fret = msg->GetRealFile(msg, path, sizeof(path) - 1); + + if (msg->issued <= 0 && ploc && (ploc->type & SERV_CALLBACK) && ploc->cbfunc) { + msg->cbobj = ploc->cbobj; + ret = (*ploc->cbfunc)(ploc->cbobj, msg, ploc->tplfile ? ploc->tplfile : path); } if (msg->issued <= 0 && hl->cbfunc) { msg->cbobj = hl->cbobj; - ret = (*hl->cbfunc)(hl->cbobj, msg); + ret = (*hl->cbfunc)(hl->cbobj, msg, path); + } + + if (msg->issued <= 0 && mgmt->req_handler) { + msg->cbobj = mgmt->req_cbobj; + ret = (*mgmt->req_handler)(mgmt->req_cbobj, msg, path); } /* if the upper callback handled and replied the request, the msg already recycled. @@ -203,14 +212,12 @@ int http_request_process (void * vcon, void * vmsg) return msg->Reply(msg); } - ret = msg->GetRealFile(msg, path, sizeof(path)); - if (strstr(path, "../")) { msg->SetStatus(msg, 404, NULL); return msg->Reply(msg); } - if (ret > 0 && file_is_regular(path)) { + if (fret > 0 && file_is_regular(path)) { if (msg->AddResFile(msg, path, 0, -1) < 0) msg->SetStatus(msg, 404, NULL); else @@ -232,7 +239,7 @@ int http_request_process (void * vcon, void * vmsg) } /* read the current directory to reply. - Caution: uncommenting following fractions is dangerous for + Caution: uncommenting following fractions is dangerous for exposure of file system. please watch your step! */ /*ret = msg->DisplayDirectory(msg); if (ret >= 0) return 0;*/ diff --git a/src/http_header.c b/src/http_header.c index 10c27d9..44f0603 100644 --- a/src/http_header.c +++ b/src/http_header.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_listen.c b/src/http_listen.c index b0d8b16..517c27f 100644 --- a/src/http_listen.c +++ b/src/http_listen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -15,17 +15,19 @@ #include "http_pump.h" #include "http_variable.h" #include "http_script.h" +#include "http_pagetpl.h" -void * http_loc_alloc (char * path, int type, char * root) +void * http_loc_alloc (char * path, int pathlen, uint8 pathdup, int matchtype, int servtype, char * root) { HTTPLoc * ploc = NULL; char * ptmp = NULL; - if (!path || strlen(path) <= 0) - return NULL; + if (!path) return NULL; + if (pathlen < 0) pathlen = strlen(path); + if (pathlen <= 0) return NULL; - if (type == SERV_SERVER || type == SERV_UPLOAD) { //file or upload + if (servtype == SERV_SERVER || servtype == SERV_UPLOAD) { //file or upload /* check if the root path exists */ if (!root) return NULL; } @@ -33,10 +35,18 @@ void * http_loc_alloc (char * path, int type, char * root) ploc = kzalloc(sizeof(*ploc)); if (!ploc) return NULL; - ploc->path = path; - ploc->type = type; + if (pathdup) { + ploc->path = str_dup(path, pathlen); + ploc->path_dup = 1; + } else { + ploc->path = path; + ploc->path_dup = 0; + } + + ploc->matchtype = matchtype; + ploc->type = servtype; - if (!root) root = "."; + //if (!root) root = "."; if (root && strlen(root) > 0 && (ptmp = realpath(root, NULL))) { str_secpy(ploc->root, sizeof(ploc->root)-1, ptmp, strlen(ptmp)); @@ -51,6 +61,7 @@ void * http_loc_alloc (char * path, int type, char * root) } ploc->script_list = arr_new(2); + ploc->reply_script_list = arr_new(2); return ploc; } @@ -61,6 +72,9 @@ void http_loc_free (void * vloc) if (!ploc) return; + if (ploc->path_dup) kfree(ploc->path); + + arr_pop_kfree(ploc->reply_script_list); arr_pop_kfree(ploc->script_list); kfree(ploc); @@ -164,22 +178,24 @@ int http_loc_build (void * vhost, void * jhost) root = host->root; } - ploc = http_loc_alloc(path, type, root); + ploc = http_loc_alloc(path, -1, 0, matchtype, type, root); if (!ploc) goto nextloc; ploc->jsonobj = jloc; ploc->matchtype = matchtype; - if (ploc->type == SERV_UPLOAD) {//upload + if (ploc->type & SERV_UPLOAD) {//upload if (host->uploadloc) http_loc_free(host->uploadloc); host->uploadloc = ploc; } else { + EnterCriticalSection(&host->hostCS); + switch (ploc->matchtype) { case MATCH_DEFAULT: //default loc - if (ploc->type == SERV_PROXY || ploc->type == SERV_FASTCGI) { //proxy or fastcgi + if (ploc->type & SERV_PROXY || ploc->type & SERV_FASTCGI) { //proxy or fastcgi ploc->matchtype = MATCH_PREFIX; //prefix matching arr_push(host->prefix_loc_list, ploc); actrie_add(host->prefix_actrie, ploc->path, -1, ploc); @@ -211,15 +227,17 @@ int http_loc_build (void * vhost, void * jhost) preg = kzalloc(sizeof(regex_t)); if (ploc->matchtype == MATCH_REGEX_CASE) { //case censitive - regcomp(preg, path, REG_EXTENDED); + regcomp(preg, ploc->path, REG_EXTENDED); } else { //ignoring case - regcomp(preg, path, REG_EXTENDED | REG_ICASE); + regcomp(preg, ploc->path, REG_EXTENDED | REG_ICASE); } arr_push(host->regex_list, preg); break; } + + LeaveCriticalSection(&host->hostCS); } ret = json_mgetP(jloc, "index", -1, (void **)&value, &valuelen); @@ -267,6 +285,19 @@ int http_loc_build (void * vhost, void * jhost) } } + ret = json_mgetP(jloc, "reply_script", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + arr_push(ploc->reply_script_list, ckstr_new(value, valuelen)); + + for (j = 1; j < ret; j++) { + sprintf(key, "reply_script[%d]", j); + subret = json_mgetP(jloc, key, -1, (void **)&value, &valuelen); + if (subret > 0 && value && valuelen > 0) { + arr_push(ploc->reply_script_list, ckstr_new(value, valuelen)); + } + } + } + nextloc: sprintf(key, "location[%d]", i); ret = json_mget_obj(jhost, key, -1, &jloc); @@ -277,16 +308,20 @@ int http_loc_build (void * vhost, void * jhost) } -void * http_host_alloc (char * hostname) +void * http_host_alloc (char * hostn, int hostlen) { HTTPHost * host = NULL; - if (!hostname) return NULL; + if (!hostn) return NULL; + + if (hostlen < 0) hostlen = strlen(hostn); host = kzalloc(sizeof(*host)); if (!host) return NULL; - str_secpy(host->hostname, sizeof(host->hostname)-1, hostname, strlen(hostname)); + str_secpy(host->hostname, sizeof(host->hostname)-1, hostn, hostlen); + + InitializeCriticalSection(&host->hostCS); host->exact_loc_table = ht_new(64, http_loc_cmp_path); @@ -300,6 +335,16 @@ void * http_host_alloc (char * hostname) host->defaultloc = NULL; host->script_list = arr_new(2); + host->reply_script_list = arr_new(2); + + + InitializeCriticalSection(&host->texttplCS); + host->texttpl_tab = ht_new(300, http_pagetpl_cmp_key); + ht_set_hash_func(host->texttpl_tab, ckstr_string_hash); + + InitializeCriticalSection(&host->listtplCS); + host->listtpl_tab = ht_new(300, http_pagetpl_cmp_key); + ht_set_hash_func(host->listtpl_tab, ckstr_string_hash); return host; } @@ -365,19 +410,96 @@ void http_host_free (void * vhost) } arr_pop_kfree(host->script_list); + arr_pop_kfree(host->reply_script_list); + + DeleteCriticalSection(&host->hostCS); + + DeleteCriticalSection(&host->texttplCS); + if (host->texttpl_tab) { + ht_free_all(host->texttpl_tab, http_pagetpl_free); + host->texttpl_tab = NULL; + } + + DeleteCriticalSection(&host->listtplCS); + if (host->listtpl_tab) { + ht_free_all(host->listtpl_tab, http_pagetpl_free); + host->listtpl_tab = NULL; + } kfree(host); } +void * http_host_create (void * vhl, char * hostn, int hostlen, char * root, + char * cert, char * prikey, char * cacert) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + ckstr_t key; + + if (!hl) return NULL; + + if (hostn && hostlen < 0) hostlen = strlen(hostn); + + EnterCriticalSection(&hl->hlCS); + + if (!hostn || hostlen <= 0 || (hostlen == 1 && hostn[0] == '*')) { + if (!hl->defaulthost) + hl->defaulthost = http_host_alloc("*", 1); + + host = hl->defaulthost; + + } else { + key.p = hostn; key.len = hostlen; + + host = ht_get(hl->host_table, &key); + if (!host) { + host = http_host_alloc(hostn, hostlen); + ht_set(hl->host_table, &key, host); + } + } + + LeaveCriticalSection(&hl->hlCS); + + if (!host) return NULL; + + if (root && strlen(root) > 0) { + str_secpy(host->root, sizeof(host->root), root, strlen(root)); + } else if (root) { + host->root[0] = '\0'; + } + + /* SNI mechanism in TLS spec enables the client can select one + from multiple cetificates coresponding to different host-names. + Therefore, NULL host-name can not be bound SSL certificate, key. */ + + if (hl->ssl_link && host->cert && strlen(host->cert) > 0 && + host->prikey && strlen(host->prikey) > 0) + { + host->cert = cert; + host->prikey = prikey; + host->cacert = cacert; + +#ifdef HAVE_OPENSSL + host->sslctx = http_ssl_server_ctx_init(host->cert, host->prikey, host->cacert); +#endif + } + + return host; +} + int http_host_cmp (void * vhost, void * vname) { HTTPHost * host = (HTTPHost *)vhost; - char * hostname = (char *)vname; + ckstr_t * ckstr = (ckstr_t *)vname; + ckstr_t tmp; if (!host) return -1; - if (!hostname) return 1; + if (!ckstr) return 1; - return strcasecmp(host->hostname, hostname); + tmp.p = host->hostname; + tmp.len = strlen(host->hostname); + + return ckstr_casecmp(&tmp, ckstr); } int http_host_build (void * vhl, void * jhl) @@ -385,7 +507,6 @@ int http_host_build (void * vhl, void * jhl) HTTPListen * hl = (HTTPListen *)vhl; HTTPHost * host = NULL; - uint8 defhost = 0; int i, hostnum; int ret = 0, subret; int j, num = 0; @@ -398,6 +519,11 @@ int http_host_build (void * vhl, void * jhl) void * jhost = NULL; char * hname = NULL; + int hnamelen = 0; + char * root = NULL; + char * cert = NULL; + char * prikey = NULL; + char * cacert = NULL; void * jerrpage = NULL; @@ -415,56 +541,40 @@ int http_host_build (void * vhl, void * jhl) for (hostnum = ret, i = 1; i <= hostnum && jhost != NULL; i++) { hname = NULL; - defhost = 0; + hnamelen = 0; + root = NULL; + cert = NULL; prikey = NULL; cacert = NULL; ret = json_mgetP(jhost, "host name", -1, (void **)&value, &valuelen); if (ret > 0 && value && valuelen > 0) { hname = value; - } else { - defhost = 1; } + hnamelen = valuelen; - /* create HTTPHost instance */ - - if (defhost || (hname && strlen(hname) == 1 && hname[0] == '*')) { - if (hl->defaulthost) - http_host_free(hl->defaulthost); - - host = hl->defaulthost = http_host_alloc("*"); - - } else { - host = ht_get(hl->host_table, hname); - if (!host) { - host = http_host_alloc(hname); - ht_set(hl->host_table, hname, host); - } + ret = json_mgetP(jhost, "root", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + root = value; + } - /* SNI mechanism in TLS spec enables the client can select one - from multiple cetificates coresponding to different host-names. - Therefore, NULL host-name can not be bound SSL certificate, key. */ + ret = json_mgetP(jhost, "ssl certificate", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + cert = value; + } + + ret = json_mgetP(jhost, "ssl private key", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + prikey = value; + } + + ret = json_mgetP(jhost, "ssl ca certificate", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + cacert = value; + } -#ifdef HAVE_OPENSSL - if (hl->ssl_link && host->sslctx == NULL) { - ret = json_mgetP(jhost, "ssl certificate", -1, (void **)&value, &valuelen); - if (ret > 0 && value && valuelen > 0) { - host->cert = value; - } - - ret = json_mgetP(jhost, "ssl private key", -1, (void **)&value, &valuelen); - if (ret > 0 && value && valuelen > 0) { - host->prikey = value; - } - - ret = json_mgetP(jhost, "ssl ca certificate", -1, (void **)&value, &valuelen); - if (ret > 0 && value && valuelen > 0) { - host->cacert = value; - } + /* create HTTPHost instance */ - if (host->cert && strlen(host->cert) > 0 && host->prikey && strlen(host->prikey) > 0) - host->sslctx = http_ssl_server_ctx_init(host->cert, host->prikey, host->cacert); - } -#endif - } + host = http_host_create(hl, hname, hnamelen, root, cert, prikey, cacert); + if (!host) break; host->jsonobj = jhost; @@ -480,11 +590,16 @@ int http_host_build (void * vhl, void * jhl) } } - ret = json_mgetP(jhost, "root", -1, (void **)&value, &valuelen); + ret = json_mgetP(jhost, "reply_script", -1, (void **)&value, &valuelen); if (ret > 0 && value && valuelen > 0) { - str_secpy(host->root, sizeof(host->root)-1, value, valuelen); - } else { - host->root[0] = '\0'; + arr_push(host->reply_script_list, ckstr_new(value, valuelen)); + + for (j = 1; j < ret; j++) { + sprintf(key, "reply_script[%d]", j); + subret = json_mgetP(jhost, key, -1, (void **)&value, &valuelen); + if (subret > 0 && value && valuelen > 0) + arr_push(host->reply_script_list, ckstr_new(value, valuelen)); + } } ret = json_mgetP(jhost, "gzip", -1, (void **)&value, &valuelen); @@ -528,12 +643,9 @@ int http_host_build (void * vhl, void * jhl) } -void * http_listen_alloc (char * localip, int port, int ssl, char * cblibfile) +void * http_listen_alloc (char * localip, int port, uint8 fwdpxy) { HTTPListen * hl = NULL; - char * err = NULL; - char * argv[16]; - int i, plen[16]; if (port == 0) return NULL; @@ -546,70 +658,22 @@ void * http_listen_alloc (char * localip, int port, int ssl, char * cblibfile) if (localip) strncpy(hl->localip, localip, sizeof(localip)-1); hl->port = port; - hl->forwardproxy = 0; - - hl->ssl_link = ssl > 0 ? 1 : 0; - - if (cblibfile) { - hl->cbargc = string_tokenize(cblibfile, -1, " \t\r\n\f\v", 6, (void **)argv, plen, 16); - for (i = 0; i < hl->cbargc; i++) { - hl->cbargv[i] = str_dup(argv[i], plen[i]); - } - - hl->cblibfile = cblibfile; - - hl->cbhandle = dlopen(hl->cbargv[0], RTLD_LAZY | RTLD_GLOBAL); - err = dlerror(); - - if (!hl->cbhandle) { - tolog(1, "eJet - HTTP Listen <%s:%d%s> Loading DynLib <%s> error! %s\n", - strlen(hl->localip) > 0 ? hl->localip : "*", - hl->port, hl->ssl_link ? " SSL" : "", - cblibfile, err ? err : ""); - - } else { - hl->cbinit = dlsym(hl->cbhandle, "http_handle_init"); - if ((err = dlerror()) != NULL) { - tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle_init' load failed! %s\n", - strlen(hl->localip) > 0 ? hl->localip : "*", - hl->port, hl->ssl_link ? " SSL" : "", - hl->cblibfile, err); - hl->cbinit = NULL; - } - - hl->cbfunc = dlsym(hl->cbhandle, "http_handle"); - if ((err = dlerror()) != NULL) { - tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle' load failed! %s\n", - strlen(hl->localip) > 0 ? hl->localip : "*", - hl->port, hl->ssl_link ? " SSL" : "", - hl->cblibfile, err); - hl->cbfunc = NULL; - } - - hl->cbclean = dlsym(hl->cbhandle, "http_handle_clean"); - if ((err = dlerror()) != NULL) { - tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle_clean' load failed! %s\n", - strlen(hl->localip) > 0 ? hl->localip : "*", - hl->port, hl->ssl_link ? " SSL" : "", - hl->cblibfile, err); - hl->cbclean = NULL; - } - - tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> load successfully!\n", - strlen(hl->localip) > 0 ? hl->localip : "*", - hl->port, hl->ssl_link ? " SSL" : "", hl->cblibfile); - } - } + hl->forwardproxy = fwdpxy; hl->mlisten = NULL; + InitializeCriticalSection(&hl->hlCS); + hl->host_table = ht_only_new(64, http_host_cmp); + ht_set_hash_func(hl->host_table, ckstr_string_hash); + hl->defaulthost = NULL; hl->reqdiag = NULL; hl->reqdiagobj = NULL; hl->script_list = arr_new(2); + hl->reply_script_list = arr_new(2); return hl; } @@ -622,6 +686,7 @@ void http_listen_free (void * vhl) if (!hl) return; arr_pop_kfree(hl->script_list); + arr_pop_kfree(hl->reply_script_list); if (hl->mlisten) { mlisten_close(hl->mlisten); @@ -635,6 +700,8 @@ void http_listen_free (void * vhl) } #endif + DeleteCriticalSection(&hl->hlCS); + if (hl->host_table) { ht_free_all(hl->host_table, http_host_free); hl->host_table = NULL; @@ -663,7 +730,33 @@ void http_listen_free (void * vhl) kfree(hl); } -void * http_listen_ssl_ctx_get (void * vhl, void * vcon) +int http_listen_ssl_ctx_set (void * vhl, char * cert, char * prikey, char * cacert) +{ + HTTPListen * hl = (HTTPListen *)vhl; + + if (!hl) return -1; + + hl->ssl_link = 1; + +#ifdef HAVE_OPENSSL + if (hl->sslctx) { + http_ssl_ctx_free(hl->sslctx); + hl->sslctx = NULL; + } +#endif + + hl->cert = cert; + hl->prikey = prikey; + hl->cacert = cacert; + +#ifdef HAVE_OPENSSL + hl->sslctx = http_ssl_server_ctx_init(hl->cert, hl->prikey, hl->cacert); +#endif + + return 0; +} + +void * http_listen_ssl_ctx_get (void * vhl) { HTTPListen * hl = (HTTPListen *)vhl; @@ -672,13 +765,107 @@ void * http_listen_ssl_ctx_get (void * vhl, void * vcon) return hl->sslctx; } -void * http_listen_get_host (void * vhl, char * servname) +void * http_listen_host_get (void * vhl, char * servname) { HTTPListen * hl = (HTTPListen *)vhl; + ckstr_t key; + void * host = NULL; if (!hl) return NULL; - return ht_get(hl->host_table, servname); + key.p = servname; key.len = str_len(servname); + + EnterCriticalSection(&hl->hlCS); + host = ht_get(hl->host_table, &key); + LeaveCriticalSection(&hl->hlCS); + + return host; +} + +int http_listen_cblibfile_set (void * vhl, char * cblibfile) +{ + HTTPListen * hl = (HTTPListen *)vhl; + char * err = NULL; + char * argv[16]; + int i, plen[16]; + + if (!hl) return -1; + + if (!cblibfile) return -2; + + /* firstly release all resources allocated before */ + + if (hl->cbhandle) { + if (hl->cbclean) + (*hl->cbclean)(hl->cbobj); + + dlclose(hl->cbhandle); + hl->cbhandle = NULL; + } + + for (i = 0; i < hl->cbargc; i++) { + kfree(hl->cbargv[i]); + hl->cbargv[i] = NULL; + } + hl->cbargc = 0; + + /* now create new instance for new lib-file */ + + hl->cbargc = string_tokenize(cblibfile, -1, " \t\r\n\f\v", 6, (void **)argv, plen, 16); + for (i = 0; i < hl->cbargc; i++) { + hl->cbargv[i] = str_dup(argv[i], plen[i]); + } + + hl->cblibfile = cblibfile; + + hl->cbhandle = dlopen(hl->cbargv[0], RTLD_LAZY | RTLD_GLOBAL); + err = dlerror(); + + if (!hl->cbhandle) { + tolog(1, "eJet - HTTP Listen <%s:%d%s> Loading DynLib <%s> error! %s\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : "", + cblibfile, err ? err : ""); + return -100; + } + + hl->cbinit = dlsym(hl->cbhandle, "http_handle_init"); + if ((err = dlerror()) != NULL) { + tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle_init' load failed! %s\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : "", + hl->cblibfile, err); + hl->cbinit = NULL; + } + + hl->cbfunc = dlsym(hl->cbhandle, "http_handle"); + if ((err = dlerror()) != NULL) { + tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle' load failed! %s\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : "", + hl->cblibfile, err); + hl->cbfunc = NULL; + } + + hl->cbclean = dlsym(hl->cbhandle, "http_handle_clean"); + if ((err = dlerror()) != NULL) { + tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> callback 'http_handle_clean' load failed! %s\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : "", + hl->cblibfile, err); + hl->cbclean = NULL; + } + + if (hl->cbhandle && hl->cbinit) { + hl->cbobj = (*hl->cbinit)(hl->httpmgmt, hl->cbargc, hl->cbargv); + } + + if (hl->cbfunc) + tolog(1, "eJet - HTTP Listen <%s:%d%s> DynLib <%s> load successfully!\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : "", hl->cblibfile); + + return 0; } @@ -723,7 +910,7 @@ int http_listen_cleanup (void * vmgmt) return 0; } -void * http_listen_add (void * vmgmt, char * localip, int port, int ssl, char * libfile) +void * http_listen_add (void * vmgmt, char * localip, int port, uint8 fwdpxy) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; HTTPListen * hl = NULL; @@ -732,35 +919,31 @@ void * http_listen_add (void * vmgmt, char * localip, int port, int ssl, char * if (!mgmt) return NULL; if (port == 0) return NULL; - + if (localip == NULL) localip = ""; else if (strcmp(localip, "*") == 0) localip = ""; - + num = arr_num(mgmt->listen_list); for (i = 0; i < num; i++) { - + hl = (HTTPListen *)arr_value(mgmt->listen_list, i); if (!hl) continue; - + if (hl->port == port && strcasecmp(hl->localip, localip) == 0) return hl; } - - hl = http_listen_alloc(localip, port, ssl, libfile); + + hl = http_listen_alloc(localip, port, fwdpxy); if (hl) { hl->httpmgmt = mgmt; arr_push(mgmt->listen_list, hl); - - if (hl->cbhandle && hl->cbinit) { - hl->cbobj = (*hl->cbinit)(hl->httpmgmt, hl->cbargc, hl->cbargv); - } } return hl; } -int http_listen_start (void * vmgmt) +int http_listen_start_all (void * vmgmt) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; void * mlisten = NULL; @@ -789,11 +972,6 @@ int http_listen_start (void * vmgmt) hl->mlisten = mlisten; - #if defined _DEBUG - printf("HTTPListen: LocalIP=%s Port=%d %s being listened...\n", - strlen(hl->localip) ? hl->localip : "*", hl->port, hl->ssl_link ? "SSL" : ""); - #endif - tolog(1, "eJet - HTTP Listen <%s:%d%s> started.\n", strlen(hl->localip) > 0 ? hl->localip : "*", hl->port, hl->ssl_link ? " SSL" : ""); @@ -802,7 +980,60 @@ int http_listen_start (void * vmgmt) return 0; } -void * http_listen_find (void * vmgmt, int port) + +void * http_ssl_listen_start (void * vmgmt, char * localip, int port, uint8 fwdpxy, + uint8 ssl, char * cert, char * prikey, char * cacert, char * libfile) +{ + HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; + HTTPListen * hl = NULL; + void * mlisten = NULL; + + if (!mgmt) return NULL; + + hl = http_listen_add(mgmt, localip, port, fwdpxy); + if (!hl) return NULL; + + if (ssl > 0) + http_listen_ssl_ctx_set(hl, cert, prikey, cacert); + + if (libfile) + http_listen_cblibfile_set(hl, libfile); + + if (!hl->defaulthost) + http_host_create(hl, NULL, -1, NULL, NULL, NULL, NULL); + + if (hl->mlisten) return hl; + + mlisten = eptcp_mlisten(mgmt->pcore, + strlen(hl->localip) > 0 ? hl->localip : NULL, + hl->port, hl, (IOHandler *)http_pump, mgmt); + if (!mlisten) { + tolog(1, "eJet - HTTP Listen <%s:%d%s> failed.\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : ""); + return hl; + } + + hl->mlisten = mlisten; + + tolog(1, "eJet - HTTP Listen <%s:%d%s> started.\n", + strlen(hl->localip) > 0 ? hl->localip : "*", + hl->port, hl->ssl_link ? " SSL" : ""); + + return hl; +} + + +void * http_listen_start (void * vmgmt, char * localip, int port, uint8 fwdpxy, char * libfile) +{ + HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; + + if (!mgmt) return NULL; + + return http_ssl_listen_start(mgmt, localip, port, fwdpxy, 0, NULL, NULL, NULL, libfile); +} + +void * http_listen_find (void * vmgmt, char * localip, int port) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; HTTPListen * hl = NULL; @@ -810,6 +1041,9 @@ void * http_listen_find (void * vmgmt, int port) if (!mgmt) return NULL; + if (localip == NULL) localip = ""; + else if (strcmp(localip, "*") == 0) localip = ""; + num = arr_num(mgmt->listen_list); for (i = 0; i < num; i++) { @@ -817,7 +1051,7 @@ void * http_listen_find (void * vmgmt, int port) hl = (HTTPListen *)arr_value(mgmt->listen_list, i); if (!hl) continue; - if (hl->port == port) { + if (hl->port == port && strcasecmp(hl->localip, localip) == 0) { return hl; } } @@ -826,7 +1060,7 @@ void * http_listen_find (void * vmgmt, int port) } -int http_listen_stop (void * vmgmt, int port) +int http_listen_stop (void * vmgmt, char * localip, int port) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; HTTPListen * hl = NULL; @@ -835,6 +1069,9 @@ int http_listen_stop (void * vmgmt, int port) if (!mgmt) return -1; if (port == 0) return -2; + if (localip == NULL) localip = ""; + else if (strcmp(localip, "*") == 0) localip = ""; + num = arr_num(mgmt->listen_list); for (i = 0; i < num; i++) { @@ -848,7 +1085,9 @@ int http_listen_stop (void * vmgmt, int port) continue; } - if (hl->port == port && mlisten_port(hl->mlisten) == port) { + if (hl->port == port && mlisten_port(hl->mlisten) == port && + strcasecmp(hl->localip, localip) == 0) + { arr_delete(mgmt->listen_list, i); http_listen_free(hl); return 0; @@ -864,7 +1103,7 @@ int http_listen_check_self (void * vmgmt, char * host, int hostlen, char * dstip HTTPListen * hl = NULL; int i, j, num; int port_listened = 0; - char buf[256]; + ckstr_t key; if (!mgmt) return -1; @@ -877,8 +1116,9 @@ int http_listen_check_self (void * vmgmt, char * host, int hostlen, char * dstip port_listened++; - str_secpy(buf, sizeof(buf)-1, host, hostlen); - if (ht_get(hl->host_table, buf) != NULL) { + key.p = host; key.len = hostlen; + + if (ht_get(hl->host_table, &key) != NULL) { /* checked host is one of hosts under listened port */ return 1; } @@ -984,20 +1224,15 @@ int http_listen_build (void * vmgmt) libfile = value; } - hl = http_listen_add(mgmt, ip, port, ssl, libfile); + hl = http_listen_add(mgmt, ip, port, forwardproxy); if (hl) { hl->jsonobj = jhl; - hl->forwardproxy = forwardproxy; - hl->cert = cert; - hl->prikey = prikey; - hl->cacert = cacert; + if (ssl) + http_listen_ssl_ctx_set(hl, cert, prikey, cacert); -#ifdef HAVE_OPENSSL - if (hl->ssl_link) { - hl->sslctx = http_ssl_server_ctx_init(hl->cert, hl->prikey, hl->cacert); - } -#endif + if (libfile) + http_listen_cblibfile_set(hl, libfile); ret = json_mgetP(jhl, "script", -1, (void **)&value, &valuelen); if (ret > 0 && value && valuelen > 0) { @@ -1011,6 +1246,18 @@ int http_listen_build (void * vmgmt) } } + ret = json_mgetP(jhl, "reply_script", -1, (void **)&value, &valuelen); + if (ret > 0 && value && valuelen > 0) { + arr_push(hl->reply_script_list, ckstr_new(value, valuelen)); + + for (j = 1; j < ret; j++) { + sprintf(key, "reply_script[%d]", j); + subret = json_mgetP(jhl, key, -1, (void **)&value, &valuelen); + if (subret > 0 && value && valuelen > 0) + arr_push(hl->reply_script_list, ckstr_new(value, valuelen)); + } + } + http_host_build(hl, jhl); } @@ -1019,7 +1266,7 @@ int http_listen_build (void * vmgmt) if (ret <= 0) break; } - http_listen_start(mgmt); + http_listen_start_all(mgmt); return 0; } @@ -1030,20 +1277,25 @@ void * http_host_instance (void * vmsg) HTTPMsg * msg = (HTTPMsg *)vmsg; HTTPListen * hl = NULL; HTTPHost * host = NULL; - char buf[256]; - + ckstr_t key; + if (!msg) return NULL; - + hl = (HTTPListen *)msg->hl; if (!hl) return NULL; - - str_secpy(buf, sizeof(buf)-1, msg->req_host, msg->req_hostlen); - - host = ht_get(hl->host_table, buf); + + key.p = msg->req_host; + key.len = msg->req_hostlen; + + EnterCriticalSection(&hl->hlCS); + + host = ht_get(hl->host_table, &key); if (!host) { host = hl->defaulthost; } + LeaveCriticalSection(&hl->hlCS); + return host; } @@ -1053,6 +1305,7 @@ void * http_loc_instance (void * vmsg) HTTPListen * hl = NULL; HTTPHost * host = NULL; HTTPLoc * ploc = NULL; + ckstr_t key; char buf[4096]; int ret = 0; int i, j, num; @@ -1067,13 +1320,18 @@ void * http_loc_instance (void * vmsg) if (++msg->locinst_times >= 16) return NULL; - buf[0] = '\0'; - str_secpy(buf, sizeof(buf)-1, msg->req_host, msg->req_hostlen); + key.p = msg->req_host; + key.len = msg->req_hostlen; - host = ht_get(hl->host_table, buf); + EnterCriticalSection(&hl->hlCS); + + host = ht_get(hl->host_table, &key); if (!host) { host = hl->defaulthost; } + + LeaveCriticalSection(&hl->hlCS); + if (!host) return NULL; msg->phost = host; @@ -1226,9 +1484,18 @@ int http_loc_passurl_get (void * vmsg, int servtype, char * url, int urllen) char * http_root_path (void * vmsg) { HTTPMsg * msg = (HTTPMsg *)vmsg; + HTTPHost * phost = NULL; HTTPLoc * ploc = NULL; - if (!msg || !msg->ploc) return ""; + if (!msg) return "."; + + if (!msg->ploc) { + if (msg->phost) { + phost = (HTTPHost *)msg->phost; + return phost->root; + } + return "."; + } ploc = (HTTPLoc *)msg->ploc; @@ -1239,18 +1506,18 @@ int http_real_file (void * vmsg, char * path, int len) { HTTPMsg * msg = (HTTPMsg *)vmsg; HTTPLoc * ploc = NULL; - int slen = 0; + char * root = NULL; + int i, slen = 0; int retlen = 0; - if (!msg || !msg->ploc) return -1; + if (!msg) return -1; if (!path || len <= 0) return -2; - ploc = (HTTPLoc *)msg->ploc; - - retlen = strlen(ploc->root); + root = http_root_path(msg); + retlen = str_len(root); if (path && len > 0) - str_secpy(path, len, ploc->root, retlen); + str_secpy(path, len, root, retlen); if (msg->docuri->path && msg->docuri->pathlen > 0) { if (path) { @@ -1267,6 +1534,17 @@ int http_real_file (void * vmsg, char * path, int len) retlen += 1; } + if (path && file_is_dir(path) && (ploc = msg->ploc)) { + slen = strlen(path); + for (i = 0; i < ploc->indexnum; i++) { + snprintf(path + slen, len - slen, "%s", ploc->index[i]); + if (file_is_regular(path)) { + return strlen(path); + } + } + path[slen] = '\0'; + } + if (path) return strlen(path); return retlen; } @@ -1274,19 +1552,18 @@ int http_real_file (void * vmsg, char * path, int len) int http_real_path (void * vmsg, char * path, int len) { HTTPMsg * msg = (HTTPMsg *)vmsg; - HTTPLoc * ploc = NULL; + char * root = NULL; int slen = 0; int retlen = 0; - if (!msg || !msg->ploc) return -1; + if (!msg) return -1; if (!path || len <= 0) return -2; - ploc = (HTTPLoc *)msg->ploc; - - retlen = strlen(ploc->root); + root = http_root_path(msg); + retlen = str_len(root); if (path && len > 0) - str_secpy(path, len, ploc->root, retlen); + str_secpy(path, len, root, retlen); if (path) { slen = strlen(path); @@ -1299,3 +1576,198 @@ int http_real_path (void * vmsg, char * path, int len) return retlen; } + +int http_prefix_match_cb (void * vhl, char * hostn, int hostlen, char * matstr, int len, + char * root, void * cbfunc, void * cbobj, void * tplfile) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + HTTPLoc * ploc = NULL; + char * ptmp = NULL; + int i, num; + + if (!hl) return -1; + if (!matstr) return -2; + if (len < 0) len = strlen(matstr); + if (len <= 0) return -3; + + host = http_host_create(hl, hostn, hostlen, NULL, NULL, NULL, NULL); + if (!host) return -100; + + EnterCriticalSection(&host->hostCS); + + num = arr_num(host->prefix_loc_list); + for (i = 0; i < num; i++) { + ploc = arr_value(host->prefix_loc_list, i); + if (!ploc) continue; + + if (ploc->path && str_len(ploc->path) == len && + str_ncmp(ploc->path, matstr, len) == 0) + { + break; + } + } + + if (!ploc || i >= num) { + ploc = http_loc_alloc(matstr, len, 1, MATCH_PREFIX, SERV_CALLBACK, root); + if (!ploc) { + LeaveCriticalSection(&host->hostCS); + return -110; + } + + arr_push(host->prefix_loc_list, ploc); + actrie_add(host->prefix_actrie, ploc->path, -1, ploc); + + } else { + ploc->matchtype = MATCH_PREFIX; + ploc->type |= SERV_CALLBACK; + + if (root && strlen(root) > 0 && (ptmp = realpath(root, NULL))) { + str_secpy(ploc->root, sizeof(ploc->root)-1, ptmp, strlen(ptmp)); + free(ptmp); + + if (ploc->root[strlen(ploc->root) - 1] == '/') + ploc->root[strlen(ploc->root) - 1] = '\0'; + } + } + + LeaveCriticalSection(&host->hostCS); + + ploc->cbfunc = cbfunc; + ploc->cbobj = cbobj; + ploc->tplfile = tplfile; + + return 0; +} + + +int http_exact_match_cb (void * vhl, char * hostn, int hostlen, char * matstr, int len, + char * root, void * cbfunc, void * cbobj, void * tplfile) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + HTTPLoc * ploc = NULL; + char * ptmp = NULL; + char buf[1024]; + + if (!hl) return -1; + if (!matstr) return -2; + if (len < 0) len = strlen(matstr); + if (len <= 0) return -3; + + host = http_host_create(hl, hostn, hostlen, NULL, NULL, NULL, NULL); + if (!host) return -100; + + str_secpy(buf, sizeof(buf)-1, matstr, len); + + EnterCriticalSection(&host->hostCS); + + ploc = ht_get(host->exact_loc_table, buf); + + if (!ploc) { + ploc = http_loc_alloc(matstr, len, 1, MATCH_EXACT, SERV_CALLBACK, root); + if (!ploc) { + LeaveCriticalSection(&host->hostCS); + return -110; + } + + ht_set(host->exact_loc_table, ploc->path, ploc); + + } else { + ploc->matchtype = MATCH_EXACT; + ploc->type |= SERV_CALLBACK; + + if (root && strlen(root) > 0 && (ptmp = realpath(root, NULL))) { + str_secpy(ploc->root, sizeof(ploc->root)-1, ptmp, strlen(ptmp)); + free(ptmp); + + if (ploc->root[strlen(ploc->root) - 1] == '/') + ploc->root[strlen(ploc->root) - 1] = '\0'; + } + } + + LeaveCriticalSection(&host->hostCS); + + ploc->cbfunc = cbfunc; + ploc->cbobj = cbobj; + ploc->tplfile = tplfile; + + return 0; +} + + +int http_regex_match_cb (void * vhl, char * hostn, int hostlen, char * matstr, int len, int ignorecase, + char * root, void * cbfunc, void * cbobj, void * tplfile) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + HTTPLoc * ploc = NULL; + regex_t * preg = NULL; + char * ptmp = NULL; + int i, num; + + if (!hl) return -1; + if (!matstr) return -2; + if (len < 0) len = strlen(matstr); + if (len <= 0) return -3; + + host = http_host_create(hl, hostn, hostlen, NULL, NULL, NULL, NULL); + if (!host) return -100; + + EnterCriticalSection(&host->hostCS); + + num = arr_num(host->regex_loc_list); + for (i = 0; i < num; i++) { + ploc = arr_value(host->regex_loc_list, i); + if (!ploc) continue; + + if (ploc->path && str_len(ploc->path) == len && + str_ncmp(ploc->path, matstr, len) == 0) + { + break; + } + } + + if (!ploc || i >= num) { + ploc = http_loc_alloc(matstr, len, 1, + ignorecase ? MATCH_REGEX_NOCASE : MATCH_REGEX_CASE, + SERV_CALLBACK, root); + if (!ploc) { + LeaveCriticalSection(&host->hostCS); + return -110; + } + + arr_push(host->regex_loc_list, ploc); + + preg = kzalloc(sizeof(regex_t)); + if (ploc->matchtype == MATCH_REGEX_CASE) { //case censitive + regcomp(preg, ploc->path, REG_EXTENDED); + + } else { //ignoring case + regcomp(preg, ploc->path, REG_EXTENDED | REG_ICASE); + } + + arr_push(host->regex_list, preg); + + } else { + ploc->matchtype = MATCH_PREFIX; + ploc->type |= SERV_CALLBACK; + + if (root && strlen(root) > 0 && (ptmp = realpath(root, NULL))) { + str_secpy(ploc->root, sizeof(ploc->root)-1, ptmp, strlen(ptmp)); + free(ptmp); + + if (ploc->root[strlen(ploc->root) - 1] == '/') + ploc->root[strlen(ploc->root) - 1] = '\0'; + } + } + + LeaveCriticalSection(&host->hostCS); + + ploc->cbfunc = cbfunc; + ploc->cbobj = cbobj; + ploc->tplfile = tplfile; + + return 0; +} + diff --git a/src/http_log.c b/src/http_log.c index a394228..f3ed8a4 100644 --- a/src/http_log.c +++ b/src/http_log.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_mgmt.c b/src/http_mgmt.c index 983f5fb..5a20b7c 100644 --- a/src/http_mgmt.c +++ b/src/http_mgmt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -24,6 +24,7 @@ #include "http_fcgi_srv.h" #include "http_log.h" #include "http_cache.h" +#include "http_script.h" char * g_http_version = "1.1.2"; char * g_http_build = "eJet/1.1.2 Web Server built "__DATE__" "__TIME__" " @@ -51,7 +52,7 @@ int http_mgmt_get_conf (void * vmgmt) sprintf(key, "http.url not escape char"); keylen = strlen(key); ret = json_mgetP(mgmt->cnfjson, key, keylen, (void **)&mgmt->uri_unescape_char, NULL); if (ret <= 0) - mgmt->uri_unescape_char = NULL; + mgmt->uri_unescape_char = "-_.~!*'();:@&=+$,/?#]["; sprintf(key, "http.cookie file"); keylen = strlen(key); ret = json_mgetP(mgmt->cnfjson, key, keylen, (void **)&mgmt->cookie_file, NULL); @@ -366,6 +367,8 @@ int http_mgmt_init (void * vmgmt) mgmt->cookiemgmt = cookie_mgmt_alloc(mgmt, mgmt->cookie_file); + script_parser_init(); + http_listen_init(mgmt); tolog(0, "\n"); @@ -381,6 +384,8 @@ int http_mgmt_cleanup (void * vmgmt) tolog(0, "\n"); + script_parser_clean(); + http_var_free(mgmt); if (mgmt->srv_sslctx) { @@ -573,7 +578,7 @@ void http_overhead_recv (void * vmgmt, long recv) LeaveCriticalSection(&mgmt->countCS); } -int http_set_reqhandler (void * vmgmt, RequestHandler * reqhandler, void * cbobj) +int http_set_reqhandler (void * vmgmt, HTTPCBHandler * reqhandler, void * cbobj) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; @@ -585,6 +590,31 @@ int http_set_reqhandler (void * vmgmt, RequestHandler * reqhandler, void * cbobj return 0; } +int http_set_reqcheck(void * vmgmt, HTTPCBHandler * reqcheck, void * checkobj) +{ + HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; + + if (!mgmt) return -1; + + mgmt->req_check = reqcheck; + mgmt->req_checkobj = checkobj; + + return 0; +} + +int http_set_rescheck(void * vmgmt, HTTPCBHandler * rescheck, void * checkobj) +{ + HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; + + if (!mgmt) return -1; + + mgmt->res_check = rescheck; + mgmt->res_checkobj = checkobj; + + return 0; +} + + int http_mgmt_con_add (void * vmgmt, void * vcon) { HTTPMgmt * mgmt = (HTTPMgmt *)vmgmt; diff --git a/src/http_msg.c b/src/http_msg.c index 18985f1..964d64a 100644 --- a/src/http_msg.c +++ b/src/http_msg.c @@ -20,6 +20,7 @@ #include "http_form.h" #include "http_dispdir.h" #include "http_cgi.h" +#include "http_pagetpl.h" extern HTTPMgmt * gp_httpmgmt; @@ -208,7 +209,12 @@ int http_msg_init_method (void * vmsg) if (!msg) return -1; msg->SetTearDownNotify = http_msg_set_teardown_notify; - msg->SetResponseHandle = http_msg_set_response_handle; + msg->SetResponseNotify = http_msg_set_response_notify; + + msg->SetResStoreFile = http_msg_set_res_store_file; + msg->SetResRecvAllNotify = http_msg_set_res_recvall_notify; + msg->SetResRecvProcNotify = http_msg_set_res_recvproc_notify; + msg->SetReqSendProcNotify = http_msg_set_req_sendproc_notify; msg->GetMIME = http_msg_get_mime; msg->GetMIMEMgmt = http_msg_get_mimemgmt; @@ -238,6 +244,7 @@ int http_msg_init_method (void * vmsg) msg->GetSrcPort = http_msg_srcport; msg->GetMsgID = http_msg_id; msg->GetMethod = GetMethod; + msg->GetMethodInd = GetMethodInd; msg->SetMethod = http_req_set_reqmeth; msg->GetURL = GetURL; @@ -382,6 +389,7 @@ int http_msg_init_method (void * vmsg) msg->AddResContentPtr = AddResContentPtr; msg->AddResFile = AddResFile; msg->AddResAppCBContent = AddResAppCBContent; + msg->AddResTplFile = http_pagetpl_add; msg->RedirectReply = RedirectReply; msg->Reply = Reply; @@ -457,10 +465,10 @@ int http_msg_init (void * vmsg) http_msg_init_res(msg); - msg->reshandle = NULL; - msg->reshandle_called = 0; - msg->reshandle_para = NULL; - msg->reshandle_cbval = NULL; + msg->resnotify = NULL; + msg->resnotify_called = 0; + msg->resnotify_para = NULL; + msg->resnotify_cbval = NULL; msg->res_store_file = NULL; msg->res_store_offset = 0; @@ -499,9 +507,9 @@ int http_msg_recycle (void * vmsg) ht_free_member(msg->script_var_tab, var_obj_free); } - if (msg->reshandle && !msg->reshandle_called) { - (*msg->reshandle)(msg, msg->reshandle_para, msg->reshandle_cbval, msg->res_status); - msg->reshandle_called = 1; + if (msg->resnotify && !msg->resnotify_called) { + (*msg->resnotify)(msg, msg->resnotify_para, msg->resnotify_cbval, msg->res_status); + msg->resnotify_called = 1; } if (msg->pcon) { @@ -999,7 +1007,7 @@ int http_msg_set_teardown_notify (void * vmsg, void * func, void * para) return 0; } -int http_msg_set_response_handle (void * vmsg, void * func, void * para, void * cbval, +int http_msg_set_response_notify (void * vmsg, void * func, void * para, void * cbval, char * storefile, int64 offset, void * procnotify, void * notifypara) { @@ -1007,10 +1015,10 @@ int http_msg_set_response_handle (void * vmsg, void * func, void * para, void * if (!msg) return -1; - msg->reshandle = func; - msg->reshandle_called = 0; - msg->reshandle_para = para; - msg->reshandle_cbval = cbval; + msg->resnotify = func; + msg->resnotify_called = 0; + msg->resnotify_para = para; + msg->resnotify_cbval = cbval; msg->res_store_file = storefile; msg->res_store_offset = offset; @@ -1021,6 +1029,56 @@ int http_msg_set_response_handle (void * vmsg, void * func, void * para, void * return 0; } +int http_msg_set_res_recvall_notify (void * vmsg, void * func, void * para, void * cbval) +{ + HTTPMsg * msg = (HTTPMsg *) vmsg; + + if (!msg) return -1; + + msg->resnotify = func; + msg->resnotify_called = 0; + msg->resnotify_para = para; + msg->resnotify_cbval = cbval; + + return 0; +} + +int http_msg_set_res_store_file (void * vmsg, char * storefile, int64 offset) +{ + HTTPMsg * msg = (HTTPMsg *) vmsg; + + if (!msg) return -1; + + msg->res_store_file = storefile; + msg->res_store_offset = offset; + + return 0; +} + +int http_msg_set_res_recvproc_notify (void * vmsg, void * procnotify, void * notifypara) +{ + HTTPMsg * msg = (HTTPMsg *) vmsg; + + if (!msg) return -1; + + msg->res_recv_procnotify = procnotify; + msg->res_recv_procnotify_para = notifypara; + + return 0; +} + +int http_msg_set_req_sendproc_notify (void * vmsg, void * procnotify, void * notifypara) +{ + HTTPMsg * msg = (HTTPMsg *) vmsg; + + if (!msg) return -1; + + msg->req_send_procnotify = procnotify; + msg->req_send_procnotify_para = notifypara; + + return 0; +} + /* 1 - temporary cache file 2 - application-given file for storing response body 3 - proxy cache file with partial content diff --git a/src/http_pagetpl.c b/src/http_pagetpl.c new file mode 100644 index 0000000..d7094ac --- /dev/null +++ b/src/http_pagetpl.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2003-2021 Ke Hengzhong + * All rights reserved. See MIT LICENSE for redistribution. + */ + +#include "adifall.ext" +#include "epump.h" +#include "http_listen.h" +#include "http_msg.h" +#include "http_mgmt.h" +#include "http_pagetpl.h" + +int http_pagetpl_cmp_key (void * a, void * b) +{ + HTTPPageTpl * ptpl = (HTTPPageTpl *)a; + ckstr_t * key = (ckstr_t *)b; + ckstr_t tpl; + + if (!ptpl || !key) return -1; + + tpl.p = ptpl->text; tpl.len = ptpl->textlen; + + return ckstr_cmp(&tpl, key); +} + +void http_pagetpl_free (void * a) +{ + HTTPPageTpl * ptpl = (HTTPPageTpl *)a; + + if (ptpl) kfree(ptpl); +} + +int http_pagetpl_callback (void * vmsg, void * vtplunit, void * tplvar, frame_p cfrm) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + PageTplUnit * tplunit = (PageTplUnit *)vtplunit; + HTTPPageTpl * pagetpl = NULL; + HTTPHost * host = NULL; + ckstr_t key; + + if (!msg) return -1; + if (!tplunit) return -2; + + host = msg->phost; + if (!host) return -10; + + key.p = tplunit->text; + key.len = tplunit->textlen; + + //1-TEXT, 2-LINK, 3-IMG, 4-LIST, 0-Unknown + if (tplunit->type == 1 || tplunit->type == 2 || tplunit->type == 3) { + EnterCriticalSection(&host->texttplCS); + pagetpl = ht_get(host->texttpl_tab, &key); + LeaveCriticalSection(&host->texttplCS); + + } else if (tplunit->type == 4) { + EnterCriticalSection(&host->listtplCS); + pagetpl = ht_get(host->listtpl_tab, &key); + LeaveCriticalSection(&host->listtplCS); + } + + if (!pagetpl || !pagetpl->func) return -100; + + return (*pagetpl->func)(pagetpl->cbobj, msg, tplvar, tplunit, cfrm); +} + + +int http_pagetpl_add (void * vmsg, char * tplfile, void * tplvar) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + + struct stat st; + int fd; + char * pbyte = NULL; + + char * pbgn = NULL; + char * pend = NULL; + char * pval = NULL; + char * pvalend = NULL; + char * poct = NULL; + char * ptxt = NULL; + + int len, tplnum = 0; + PageTplUnit tpl; + frame_p cfrm = NULL; + char fname[1024]; + + if (!msg) return -1; + + if (file_stat(tplfile, &st) < 0) + return -100; + + if (st.st_size > 128*1024*1024) + return -101; + + fd = open(tplfile, O_RDONLY); + if (fd < 0) return -200; + + pbyte = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (!pbyte) { + close(fd); + return -300; + } + + pbgn = pbyte; + pend = pbyte + st.st_size; + + cfrm = msg->GetFrame(msg); + + for ( ; pbgn < pend; ) { + /* */ + /* */ + /* */ + /* */ + /* */ + + pval = sun_find_string(pbgn, pend - pbgn, "= pend) break; + + pvalend = sun_find_string(pval + 8, pend - pval - 8, "?>", 2, NULL); + if (pvalend >= pend) break; + + if (pval > pbgn) { + chunk_add_file(msg->res_body_chunk, tplfile, pbgn - pbyte, pval - pbgn, 1); + } + + memset(&tpl, 0, sizeof(tpl)); + tpl.bgnpos = pval - pbyte; + tpl.endpos = pvalend + 2 - pbyte; + tpl.tplfile = tplfile; + + /* move to the end of pagetpl tag: */ + pbgn = pvalend + 2; + + /* pval is begining of command keyword, poct is the end of command. + | | + V V + xxxxxx */ + pval = skipOver(pval, pvalend - pval, " \t\r\n\f\v", 6); + if (pval >= pvalend) continue; + poct = skipTo(pval, pvalend-pval, ",; \t\r\n\f\v", 8); + + ptxt = pval; + len = poct - pval; + + /* pval is begining of command content, poct is the end of content. + | | + V V + xxxxxx */ + pval = skipOver(poct, pvalend - poct, ",; \t\r\n\f\v", 8); + if (pval >= pvalend) continue; + poct = skipTo(pval, pvalend-pval, ",; \t\r\n\f\v", 8); + + frame_empty(cfrm); + + if (len == 4 && str_ncasecmp(ptxt, "TEXT", 4) == 0) { + tpl.type = 1; + + } else if (len == 4 && str_ncasecmp(ptxt, "LINK", 4) == 0) { + /* */ + tpl.type = 2; + + } else if (len == 3 && str_ncasecmp(ptxt, "IMG", 3) == 0) { + /* */ + tpl.type = 3; + + } else if (len == 4 && str_ncasecmp(ptxt, "LIST", 4) == 0) { + tpl.type = 4; + + } else if (len == 7 && str_ncasecmp(ptxt, "INCLUDE", 7) == 0) { + /* */ + tpl.type = 5; + + pval = skipOver(pval, poct-pval, "'\"", 2); + poct = rskipOver(poct-1, poct-pval, "'\"", 2); + if (poct < pval) continue; + + tpl.url = pval; tpl.urllen = poct - pval + 1; + str_secpy(fname, sizeof(fname)-1, tpl.url, tpl.urllen); + + if (file_is_regular(fname)) { + http_pagetpl_add(msg, fname, tplvar); + + } else { + msg->GetRealPath(msg, fname, sizeof(fname)-1); + len = strlen(fname); + str_secpy(fname + len, sizeof(fname)-1-len, tpl.url, tpl.urllen); + if (file_is_regular(fname)) + http_pagetpl_add(msg, fname, tplvar); + } + tplnum++; + continue; + + } else { + continue; + } + + tpl.text = pval; + tpl.textlen = poct - pval; + if (tpl.textlen <= 0) continue; + + if (tpl.text[0] != '$') { + frame_put_nlast(cfrm, tpl.text, tpl.textlen); + } else { + tpl.text++; tpl.textlen--; + if (tpl.textlen <= 0) continue; + + str_value_by_key(pval, pvalend-pval, "PARA", (void **)&tpl.para, &tpl.paralen); + if (tpl.type == 2 || tpl.type == 3) { + str_value_by_key(pval, pvalend-pval, "URL", (void **)&tpl.url, &tpl.urllen); + str_value_by_key(pval, pvalend-pval, "SHOW", (void **)&tpl.show, &tpl.showlen); + } + + http_pagetpl_callback(msg, &tpl, tplvar, cfrm); + } + tplnum++; + + if (frameL(cfrm) > 0) + chunk_add_buffer(msg->res_body_chunk, frameP(cfrm), frameL(cfrm)); + } + + msg->RecycleFrame(msg, cfrm); + + if (pbgn < pend) + chunk_add_file(msg->res_body_chunk, tplfile, pbgn - pbyte, pend - pbgn, 1); + + munmap(pbyte, st.st_size); + close(fd); + + return 0; +} + +int http_pagetpl_reply (void * vmsg, char * tplfile, void * tplvar) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + int ret = 0; + + if (!msg) return -1; + + ret = http_pagetpl_add(msg, tplfile, tplvar); + if (ret < 0) return ret; + + msg->SetResContentType (msg, "text/html", 9); + msg->Reply(msg); + + return 0; +} + + +int http_pagetpl_text_cb (void * vhl, char * hostn, int hostlen, + void * text, int textlen, void * func, void * cbobj) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + ckstr_t key; + HTTPPageTpl * ptpl = NULL; + + if (!hl) return -1; + if (!text) return -2; + if (textlen < 0) textlen = strlen(text); + if (textlen <= 0) return -3; + + host = http_host_create(hl, hostn, hostlen, NULL, NULL, NULL, NULL); + if (!host) return -100; + + key.p = text; + key.len = textlen; + + EnterCriticalSection(&host->texttplCS); + + ptpl = ht_get(host->texttpl_tab, &key); + if (!ptpl) { + ptpl = kzalloc(sizeof(*ptpl)); + + str_secpy(ptpl->text, sizeof(ptpl->text)-1, text, textlen); + ptpl->textlen = textlen; + ptpl->func = func; + ptpl->cbobj = cbobj; + + ht_set(host->texttpl_tab, &key, ptpl); + + } else { + str_secpy(ptpl->text, sizeof(ptpl->text)-1, text, textlen); + ptpl->textlen = textlen; + ptpl->func = func; + ptpl->cbobj = cbobj; + } + + LeaveCriticalSection(&host->texttplCS); + + return 0; + +} + +int http_pagetpl_list_cb (void * vhl, char * hostn, int hostlen, + void * text, int textlen, void * func, void * cbobj) +{ + HTTPListen * hl = (HTTPListen *)vhl; + HTTPHost * host = NULL; + ckstr_t key; + HTTPPageTpl * ptpl = NULL; + + if (!hl) return -1; + if (!text) return -2; + if (textlen < 0) textlen = strlen(text); + if (textlen <= 0) return -3; + + host = http_host_create(hl, hostn, hostlen, NULL, NULL, NULL, NULL); + if (!host) return -100; + + key.p = text; + key.len = textlen; + + EnterCriticalSection(&host->listtplCS); + + ptpl = ht_get(host->listtpl_tab, &key); + if (!ptpl) { + ptpl = kzalloc(sizeof(*ptpl)); + + str_secpy(ptpl->text, sizeof(ptpl->text)-1, text, textlen); + ptpl->textlen = textlen; + ptpl->func = func; + ptpl->cbobj = cbobj; + + ht_set(host->listtpl_tab, &key, ptpl); + + } else { + str_secpy(ptpl->text, sizeof(ptpl->text)-1, text, textlen); + ptpl->textlen = textlen; + ptpl->func = func; + ptpl->cbobj = cbobj; + } + + LeaveCriticalSection(&host->listtplCS); + + return 0; +} + diff --git a/src/http_pump.c b/src/http_pump.c index 5edeeb9..f87427f 100644 --- a/src/http_pump.c +++ b/src/http_pump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -33,7 +33,7 @@ int http_pump (void * vmgmt, void * vobj, int event, int fdtype) if (fdtype != FDT_LISTEN) return -1; - hl = (HTTPListen *)http_listen_find(mgmt, iodev_lport(vobj)); + hl = (HTTPListen *)http_listen_find(mgmt, iodev_lip(vobj), iodev_lport(vobj)); if (!hl) return -1; return http_cli_accept(mgmt, vobj); diff --git a/src/http_request.c b/src/http_request.c index fa19022..e9e6c12 100644 --- a/src/http_request.c +++ b/src/http_request.c @@ -404,7 +404,7 @@ int http_req_set_docuri (void * vmsg, char * puri, int urilen, int decode, int i ploc = (HTTPLoc *)msg->ploc; if (!ploc) return -201; - if (ploc->type == SERV_PROXY || ploc->type == SERV_FASTCGI) + if ((ploc->type & SERV_PROXY) || (ploc->type & SERV_FASTCGI)) return 0; /* only directory request needs to append its index file */ diff --git a/src/http_response.c b/src/http_response.c index 7eab7d2..a51ff29 100644 --- a/src/http_response.c +++ b/src/http_response.c @@ -13,9 +13,11 @@ #include "http_request.h" #include "http_listen.h" #include "http_con.h" +#include "http_script.h" //#include "zlibgzip.h" //#include "xml.h" +extern HTTPMgmt * gp_httpmgmt; int http_res_getstatus (void * vmsg) { @@ -421,46 +423,46 @@ int http_res_errpage (void * vmsg) char * reason = NULL; char * desc = NULL; int ind = 0; - + if (!msg) return -1; - + if (msg->res_status < 400 || chunk_size(msg->res_body_chunk, 0) > 0) return 0; - + if (msg->phost) { phost = msg->phost; - + if (msg->res_status < 500) { ind = msg->res_status - 400; if (ind < 20) errfile = phost->errpage.err400[ind]; - + } else { ind = msg->res_status - 500; if (ind < 20) errfile = phost->errpage.err500[ind]; } - + if (errfile && strlen(errfile) > 0) { if (phost->errpage.root) snprintf(path, sizeof(path)-1, "%s/%s", phost->errpage.root, errfile); else snprintf(path, sizeof(path)-1, "%s", errfile); - + if (msg->AddResFile(msg, path, 0, -1) >= 0) { msg->res_body_length = chunk_size(msg->res_body_chunk, 0); msg->SetResContentLength(msg, msg->res_body_length); } } } - + if (chunk_size(msg->res_body_chunk, 0) <= 0) { http_get_status2(msg->httpmgmt, msg->res_status, &reason); if (!reason) reason = ""; - + frm = frame_new(512); frame_append(frm, "\n"); - + switch (msg->res_status) { case 400: reason = "Bad Request"; @@ -512,45 +514,55 @@ int http_res_errpage (void * vmsg) desc = ""; break; } - + frame_appendf(frm, "%d %s", msg->res_status, reason); frame_appendf(frm, "\n\n

"); frame_appendf(frm, "%d %s", msg->res_status, reason); frame_appendf(frm, "

\n

"); frame_appendf(frm, "The requested URL %s", frameS(msg->absuri->uri)); frame_appendf(frm, "%s", desc); - + frame_appendf(frm, ".

\n
eJet/%s
", g_http_version); frame_html_escape(g_http_author, -1, frm); frame_append(frm, "
\n\n"); - + msg->AddResContent(msg, frameP(frm), frameL(frm)); msg->SetResContentType(msg, "text/html", -1); msg->SetResContentLength(msg, frameL(frm)); frame_free(frm); } - + return 0; } int http_res_encoding (void * vmsg) { HTTPMsg * msg = (HTTPMsg *)vmsg; + HTTPMgmt * mgmt = NULL; HeaderUnit * punit = NULL; HeaderUnit * acchu = NULL; HTTPHost * phost = NULL; + char buf[2048]; int i, num; int ret = 0; time_t gmtval; if (!msg) return -1; + mgmt = (HTTPMgmt *)msg->httpmgmt; + if (!mgmt) mgmt = gp_httpmgmt; + if (!mgmt) return -2; + frame_empty(msg->res_stream); - /* building response line */ - ret = http_res_status_encode(msg, msg->res_stream); - if (ret < 0) return ret; + if (mgmt->res_check) { + msg->GetRealFile(msg, buf, sizeof(buf)-1); + (*mgmt->res_check)(mgmt->res_checkobj, msg, buf); + } + + /* now execute reply-scripts defined in configure file. */ + http_reply_script_exec(msg); if (msg->res_status >= 400 && chunk_size(msg->res_body_chunk, 0) <= 0) http_res_errpage(msg); @@ -561,6 +573,10 @@ int http_res_encoding (void * vmsg) http_header_append_date(msg, 1, "Date", 4, gmtval); } + /* building response line */ + ret = http_res_status_encode(msg, msg->res_stream); + if (ret < 0) return ret; + if (msg->res_body_flag == BC_CONTENT_LENGTH || msg->res_body_flag == BC_TE) { #if 0 HTTPMgmt * mgmt = NULL; @@ -577,7 +593,7 @@ int http_res_encoding (void * vmsg) acchu = http_header_get(msg, 0, "Accept-Charset", 14); if (!acchu) goto go_on_execute; - http_res_charset_conv(msg, acchu, HUValue(punit), punit->valuelen); + http_res_charset_conv (msg, acchu, HUValue(punit), punit->valuelen); } #endif @@ -601,10 +617,15 @@ int http_res_encoding (void * vmsg) } go_on_execute: - if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { - punit = http_header_get(msg, 1, "Content-Length", 14); - if (!punit) { - http_header_append_int64(msg, 1, "Content-Length", 14, chunk_size(msg->res_body_chunk, 0)); + if (msg->res_body_flag == BC_CONTENT_LENGTH) { + if (http_header_get(msg, 1, "Content-Length", 14) == NULL) { + if (msg->res_body_length <= 0) + msg->res_body_length = chunk_size(msg->res_body_chunk, 0); + http_header_append_int64(msg, 1, "Content-Length", 14, msg->res_body_length); + } + } else { + if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { + http_header_append(msg, 1, "Transfer-Encoding", 17, "chunked", 7); } } } @@ -652,9 +673,9 @@ int print_response (void * vmsg, FILE * fp) char buf[2048]; int i, num; char * poct = NULL; - + if (!msg) return -1; - + /* printf the response status line */ if (fp == stdout || fp == stderr) fprintf(fp, "\n-------------Response ConID=%lu reqnum=%d MsgID=%ld reqfd=%d " @@ -662,9 +683,9 @@ int print_response (void * vmsg, FILE * fp) http_con_id(msg->pcon), http_con_reqnum(msg->pcon), msg->msgid, iodev_fd(http_con_iodev(msg->pcon)), msg->srcip, msg->srcport); //fprintf(fp, "%s\n", frameString(msg->res_line)); - + poct = frameP(msg->res_line); - + /* print res_line: HTTP/1.1 200 OK */ str_secpy(buf, sizeof(buf)-1, poct + msg->res_verloc, msg->res_verlen); str_secat(buf, sizeof(buf)-1-strlen(buf), " ", 1); @@ -678,27 +699,27 @@ int print_response (void * vmsg, FILE * fp) for (i = 0; i < num; i++) { unit = arr_value(msg->res_header_list, i); if (!unit) continue; - + poct = HUName(unit); if (unit->namelen > 0) { str_secpy(buf, sizeof(buf)-1, poct, unit->namelen); fprintf(fp, " %s: ", buf); } else fprintf(fp, " : "); - + poct = HUValue(unit); if (unit->valuelen > 0) { str_secpy(buf, sizeof(buf)-1, poct, unit->valuelen); fprintf(fp, "%s\n", buf); } else fprintf(fp, "\n"); } - + /* printf the response body */ if (msg->res_body_length > 0) { int64 sndlen = 0; - + chunk_read_ptr(msg->res_body_chunk, msg->res_header_length, -1, (void **)&poct, &sndlen, 0); fprintf(fp, "response body %lld bytes, chunk len=%lld:\n", msg->res_body_length, sndlen); - + /*unit = http_header_get(msg, 1, "Content-Type", 12); if (unit && (strncasecmp(HUValue(unit), "text/", 5)==0 || strncasecmp(HUValue(unit), "application/json", 16)==0)) @@ -709,7 +730,7 @@ int print_response (void * vmsg, FILE * fp) printOctet(fp, poct, 0, sndlen, 2); //} } - + if (msg->res_file_cache > 0) { printf("response body stored %lld bytes in file:\n", msg->res_body_length); if (msg->res_file_cache == 1) @@ -717,15 +738,15 @@ int print_response (void * vmsg, FILE * fp) if (msg->res_file_cache == 2) printf(" ExternalFile: %s\n", msg->res_store_file); } - + print_hashtab(msg->res_header_table, fp); - + if (fp == stdout || fp == stderr) fprintf(fp, "------------------------end of the response: id=%ld " "--------------------\n", msg->msgid); - + fflush(fp); - + return 0; } diff --git a/src/http_script.c b/src/http_script.c index 3900f1b..999a40a 100644 --- a/src/http_script.c +++ b/src/http_script.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -10,9 +10,21 @@ #include "http_listen.h" #include "http_msg.h" #include "http_mgmt.h" +#include "http_header.h" #include "http_variable.h" #include "http_script.h" +typedef char * ScriptParser (void * vhsc, char * p, int slen); + +typedef struct script_cmd_s { + char * cmd; + int len; + void * parser; +} scmd_t; + +hashtab_t * script_parser_table = NULL; + + void * http_script_alloc () { HTTPScript * hsc = NULL; @@ -163,7 +175,6 @@ char * goto_var_end (char * p, int len) if (pbgn >= pend) return pbgn; return pbgn + 1; - } poct = pbgn; @@ -207,6 +218,11 @@ char * goto_symbol_end (char * p, int len) if (pbgn >= pend) return pbgn; pbgn++; + } else if (*pbgn == '(') { + pbgn = skipToPeer(pbgn, pend-pbgn, '(', ')'); + if (pbgn >= pend) return pbgn; + pbgn++; + } else if (ISSPACE(*pbgn)) { return pbgn; @@ -285,11 +301,11 @@ int get_var_value (void * vhsc, char * p, int len, char * value, int vallen, int if (len <= 0) return -3; if (!value || vallen <= 0) return -10; - + value[0] = '\0'; - + pend = pbgn + len; - + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); if (pbgn >= pend) return -100; @@ -297,8 +313,9 @@ int get_var_value (void * vhsc, char * p, int len, char * value, int vallen, int if (poct < pbgn) return -101; pend = poct + 1; - if ((*pbgn == '"' || *pbgn == '\'') && *poct == *pbgn) { - pbgn++; + if ( ((*pbgn == '"' || *pbgn == '\'') && *poct == *pbgn) || + (*pbgn == '(' && *poct == ')') ) { + pbgn++; poct--; pend--; if (pbgn >= pend) return 0; @@ -310,45 +327,38 @@ int get_var_value (void * vhsc, char * p, int len, char * value, int vallen, int return str_secpy(value, vallen, pbgn, pend-pbgn); } -int script_if_conditiion_parse (void * vhsc, char * cond, int condlen) + +/* if ( -d /opt/abc.html && -x aaa.txt ) */ + +static int script_if_file_parse (void * vhsc, char * pbgn, int len, char ** pterm) { HTTPScript * hsc = (HTTPScript *)vhsc; - char bufa[4096]; - char bufb[4096]; - char * pbgn = NULL; + char buf[4096]; char * pend = NULL; char * poct = NULL; char * pexpend = NULL; struct stat fs; - int reverse = 0; - char cmpsym[8]; - - regex_t regobj; - int ret = 0; - regmatch_t pmat[4]; - - if (!hsc) return 0; - - if (!cond) return 0; - if (condlen < 0) condlen = strlen(cond); - if (condlen <= 0) return 0; - pbgn = cond; - pend = cond + condlen; + if (pterm) *pterm = pbgn; - pbgn = skipOver(pbgn, condlen, " \t\r\n\f\v", 6); - if (pbgn >= pend) return 0; + if (!hsc || !pbgn || len <= 0) return 0; - pexpend = rskipOver(pend-1, pend-pbgn, " \t\r\n\f\v", 6); + pend = pbgn + len; if (pend - pbgn > 2 && pbgn[0] == '-' && (pbgn[1] == 'f' || pbgn[1] == 'd' || pbgn[1] == 'e' || pbgn[1] == 'x')) { poct = skipOver(pbgn+2, pend-pbgn-2, " \t\r\n\f\v", 6); - if (poct >= pend) return 0; + if (poct >= pend) { + if (pterm) *pterm = poct; + return 0; + } + + pexpend = goto_symbol_end(poct, pend-poct); + if (pterm) *pterm = pexpend; - get_var_value(hsc, poct, pexpend+1-poct, bufa, sizeof(bufa)-1, 1); - poct = trim_var(bufa, strlen(bufa)); + get_var_value(hsc, poct, pexpend-poct, buf, sizeof(buf)-1, 1); + poct = trim_var(buf, strlen(buf)); if (pbgn[1] == 'f') { if (file_is_regular(poct)) return 1; @@ -364,18 +374,42 @@ int script_if_conditiion_parse (void * vhsc, char * cond, int condlen) if (fs.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) return 1; } + } - return 0; - } + return 0; +} + +/* if ( !-d /opt/abc.html && -x aaa.txt ) */ + +static int script_if_not_file_parse (void * vhsc, char * pbgn, int len, char ** pterm) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + char buf[4096]; + char * pend = NULL; + char * poct = NULL; + char * pexpend = NULL; + struct stat fs; + + if (pterm) *pterm = pbgn; + + if (!hsc || !pbgn || len <= 0) return 0; + + pend = pbgn + len; if (pend - pbgn > 3 && pbgn[0] == '!' && pbgn[1] == '-' && (pbgn[2] == 'f' || pbgn[2] == 'd' || pbgn[2] == 'e' || pbgn[2] == 'x')) { poct = skipOver(pbgn+3, pend-pbgn-3, " \t\r\n\f\v", 6); - if (poct >= pend) return 0; + if (poct >= pend) { + if (pterm) *pterm = poct; + return 0; + } + + pexpend = goto_symbol_end(poct, pend-poct); + if (pterm) *pterm = pexpend; - get_var_value(hsc, poct, pexpend-poct+1, bufa, sizeof(bufa)-1, 1); - poct = trim_var(bufa, strlen(bufa)); + get_var_value(hsc, poct, pexpend-poct, buf, sizeof(buf)-1, 1); + poct = trim_var(buf, strlen(buf)); if (pbgn[2] == 'f') { if (!file_is_regular(poct)) return 1; @@ -391,81 +425,464 @@ int script_if_conditiion_parse (void * vhsc, char * cond, int condlen) if (!(fs.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; } - - return 0; } - if (*pbgn == '!') { pbgn++; reverse = 1; } + return 0; +} - poct = goto_symbol_end(pbgn, pexpend + 1 - pbgn); - get_var_value(hsc, pbgn, poct-pbgn, bufa, sizeof(bufa)-1, 1); +static int str_val_type (char * p, int len) +{ + int i; + int hasdot = 0; - pbgn = skipOver(poct, pexpend + 1 - poct, " \t\r\n\f\v", 6); - if (pbgn > pexpend) { - goto onevar; - } + if (!p) return -1; + if (len < 0) len = strlen(p); + if (len <= 0) return -2; - /* all kinds of comparing symbol: == != ~ ^~ ~* */ - for (poct = pbgn; poct < pexpend + 1; poct++) { - if (is_exp_char(*poct)) break; - if (ISSPACE(*poct)) break; - } - if (poct > pbgn) { - str_secpy(cmpsym, sizeof(cmpsym)-1, pbgn, poct-pbgn); - } else cmpsym[0] = '\0'; + if (p[0] < '0' || p[0] > '9') + return 0; //string - pbgn = skipOver(poct, pexpend + 1 - poct, " \t\r\n\f\v", 6); - if (pbgn > pexpend) { - goto onevar; + for (i = 1; i < len; i++) { + if (p[i] == '.') { + hasdot++; + if (hasdot > 1) return 0; + } else if (p[i] < '0' || p[i] > '9') { + return 0; //string + } } - /* extracting the second variable */ - poct = goto_symbol_end(pbgn, pexpend + 1 - pbgn); - get_var_value(hsc, pbgn, poct-pbgn, bufb, sizeof(bufb)-1, 1); + if (hasdot == 0) return 1; //integer + + return 2; //double +} + +static int script_if_objcmp (void * vhsc, char * avar, int avarlen, char * cmpsym, char * bvar, int bvarlen) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + + char bufa[4096]; + char bufb[4096]; + int lena = 0; + int lenb = 0; + char * pa = NULL; + char * pb = NULL; + + int valtypea = 0; + int valtypeb = 0; + int64 aival64 = 0; + int64 bival64 = 0; + double adval = 0; + double bdval = 0; + + regex_t regobj; + regmatch_t pmat[4]; + int ret = 0; + + if (!hsc) return 0; + + if (!avar || avarlen <= 0) return 0; + if (!cmpsym && strlen(cmpsym) <= 0) return 0; + if (!bvar || bvarlen <= 0) return 0; - pbgn = bufa; - poct = bufb; + get_var_value(hsc, avar, avarlen, bufa, sizeof(bufa)-1, 1); + get_var_value(hsc, bvar, bvarlen, bufb, sizeof(bufb)-1, 1); + + pa = trim_var(bufa, strlen(bufa)); + pb = trim_var(bufb, strlen(bufb)); + + lena = strlen(pa); + lenb = strlen(pb); /* do comparing or matching calculation */ if (strcasecmp(cmpsym, "==") == 0) { - return (strcasecmp(pbgn, poct) == 0) ? 1 : 0; + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 == bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval == bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) == 0) ? 1 : 0; + + } else if (strcasecmp(cmpsym, ">") == 0) { + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 > bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval > bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) > 0) ? 1 : 0; + + } else if (strcasecmp(cmpsym, ">=") == 0) { + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 >= bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval >= bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) >= 0) ? 1 : 0; + + } else if (strcasecmp(cmpsym, "<") == 0) { + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 < bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval < bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) < 0) ? 1 : 0; + + } else if (strcasecmp(cmpsym, "<=") == 0) { + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 <= bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval <= bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) <= 0) ? 1 : 0; } else if (strcasecmp(cmpsym, "!=") == 0) { - return (strcasecmp(pbgn, poct) == 0) ? 0 : 1; - + valtypea = str_val_type(pa, lena); + valtypeb = str_val_type(pb, lenb); + if (valtypea == 1 && valtypeb == 1) { + aival64 = strtoll(pa, NULL, 10); + bival64 = strtoll(pb, NULL, 10); + if (aival64 != bival64) return 1; + return 0; + } else if (valtypea == 2 && valtypeb == 2) { + adval = strtoll(pa, NULL, 10); + bdval = strtoll(pb, NULL, 10); + if (adval != bdval) return 1; + return 0; + } + return (strcasecmp(pa, pb) == 0) ? 0 : 1; + } else if (strcasecmp(cmpsym, "^~") == 0) { - return (strncasecmp(pbgn, poct, strlen(poct)) == 0) ? 1 : 0; - + return (strncasecmp(pa, pb, strlen(pb)) == 0) ? 1 : 0; + } else if (strcasecmp(cmpsym, "~") == 0) { memset(®obj, 0, sizeof(regobj)); - regcomp(®obj, bufb, REG_EXTENDED); - ret = regexec(®obj, bufa, 4, pmat, 0); + regcomp(®obj, pb, REG_EXTENDED); + ret = regexec(®obj, pa, 4, pmat, 0); regfree(®obj); - + if (ret == 0) return 1; if (ret == REG_NOMATCH) return 0; - + } else if (strcasecmp(cmpsym, "~*") == 0) { memset(®obj, 0, sizeof(regobj)); - regcomp(®obj, bufb, REG_EXTENDED | REG_ICASE); - - ret = regexec(®obj, bufa, 4, pmat, 0); + regcomp(®obj, pb, REG_EXTENDED | REG_ICASE); + + ret = regexec(®obj, pa, 4, pmat, 0); regfree(®obj); - + if (ret == 0) return 1; if (ret == REG_NOMATCH) return 0; } + + return 0; +} + +/* if ( $request_header[content-type] == "text/html" ) */ + +static int script_if_objcmp_parse (void * vhsc, char * pbgn, int len, char ** pterm, + char * pa, int palen, char * pcmp, char * pb, int pblen) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + char * pend = NULL; + char * poct = NULL; + + char * avar = NULL; + char * bvar = NULL; + int alen = 0; + int blen = 0; + + char cmpsym[8]; + int cmplen = 0; + + if (pterm) *pterm = pbgn; + + if (!hsc) return 0; + + if (pbgn && len > 0) { + pend = pbgn + len; + + pbgn = skipOver(pbgn, pend - pbgn, " \t\r\n\f\v", 6); + if (pbgn > pend) { + if (pterm) *pterm = pbgn; + return 0; + } + } + + if (pa && palen > 0) { + avar = pa; alen = palen; + + } else { + poct = goto_symbol_end(pbgn, pend - pbgn); + avar = pbgn; alen = poct - pbgn; + + if (pterm) *pterm = poct; + + pbgn = skipOver(poct, pend - poct, " \t\r\n\f\v", 6); + if (pbgn > pend) { + return 2; //indicate only one obj + } + } + + if (pcmp) { + str_secpy(cmpsym, sizeof(cmpsym)-1, pcmp, strlen(pcmp)); + } else { + /* all kinds of comparing symbol: == != ~ ^~ ~* > < >= <= */ + for (poct = pbgn; poct < pend; poct++) { + if (is_exp_char(*poct)) break; + if (ISSPACE(*poct)) break; + } + cmplen = poct - pbgn; + if (poct > pbgn) + str_secpy(cmpsym, sizeof(cmpsym)-1, pbgn, poct-pbgn); + else + cmpsym[0] = '\0'; + + pbgn = skipOver(poct, pend - poct, " \t\r\n\f\v", 6); + if (pbgn > pend) { + return 2; //indicate only one obj + } + } + cmplen = strlen(cmpsym); + + if (pa && palen > 0) { + bvar = pa; blen = palen; + + } else { + /* extracting the second variable */ + poct = goto_symbol_end(pbgn, pend - pbgn); + bvar = pbgn; blen = poct - pbgn; + + if (pterm) *pterm = poct; + } + + if (cmplen <= 0 || cmplen > 2) return 100; + if (cmplen == 1 && (cmpsym[0] != '~' && cmpsym[0] != '>' && cmpsym[0] != '<')) + return 101; + if (cmplen == 2 && (cmpsym[0] != '=' || cmpsym[1] != '=') && + (cmpsym[0] != '!' || cmpsym[1] != '=') && + (cmpsym[0] != '^' || cmpsym[1] != '~') && + (cmpsym[0] != '~' || cmpsym[1] != '*') && + (cmpsym[0] != '>' || cmpsym[1] != '=') && + (cmpsym[0] != '<' || cmpsym[1] != '=') ) + { + return 102; + } + + return script_if_objcmp(hsc, avar, alen, cmpsym, bvar, blen); +} + +int script_if_condition_parse (void * vhsc, char * cond, int condlen, char ** pterm) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + char buf[4096]; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + char * pval = NULL; + char * pexpend = NULL; + + int condnum = 0; + int reverse = 0; + int condval = 0; + int condcmp = 0; //0-none 1-and(&&) 2-or(||) + + int ret = 0; + + if (!hsc) return 0; + + if (!cond) return 0; + if (condlen < 0) condlen = strlen(cond); + if (condlen <= 0) return 0; + + pbgn = cond; + pend = cond + condlen; + + pbgn = skipOver(pbgn, condlen, " \t\r\n\f\v", 6); + if (pbgn >= pend) return 0; + + pexpend = rskipOver(pend-1, pend-pbgn, " \t\r\n\f\v", 6); + pend = pexpend + 1; + + for ( ; pbgn < pend; ) { + pbgn = skipOver(pbgn, pend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pend) return condval; + + if (pend - pbgn > 2 && pbgn[0] == '-' && + (pbgn[1] == 'f' || pbgn[1] == 'd' || pbgn[1] == 'e' || pbgn[1] == 'x')) + { + ret = script_if_file_parse(hsc, pbgn, pend-pbgn, &poct); + if (reverse) ret = ret > 0 ? 0 : 1; + + if (condcmp == 1) condval = condval && ret; + else if (condcmp == 2) condval = condval || ret; + else condval = ret; + + pbgn = poct; + condcmp = 0; + reverse = 0; + condnum++; + } + + else if (pend - pbgn > 3 && pbgn[0] == '!' && pbgn[1] == '-' && + (pbgn[2] == 'f' || pbgn[2] == 'd' || pbgn[2] == 'e' || pbgn[2] == 'x')) + { + ret = script_if_not_file_parse(hsc, pbgn, pend-pbgn, &poct); + if (reverse) ret = ret > 0 ? 0 : 1; + + if (condcmp == 1) condval = condval && ret; + else if (condcmp == 2) condval = condval || ret; + else condval = ret; + + pbgn = poct; + condcmp = 0; + reverse = 0; + condnum++; + + } else if (pbgn[0] == '(') { + poct = skipToPeer(pbgn, pend-pbgn, '(', ')'); + if (*poct != ')') return condval; + + pbgn = skipOver(pbgn+1, poct-pbgn-1, " \t\r\n\f\v", 6); + if (pbgn >= poct) { + pbgn = poct + 1; + continue; + } + + ret = script_if_condition_parse(hsc, pbgn, poct-pbgn, &pval); + if (ret >= 2) { /* the content in bracket will be considered as one variable-object */ + /* if ( ($request_path) != "/opt/hls.html" ) */ + /* ^ */ + /* | */ + ret = script_if_objcmp_parse(hsc, poct+1, pend-poct-1, &pval, pbgn, pval-pbgn, NULL, NULL, 0); + if (ret >= 2) { + pbgn = pval; + condcmp = 0; + reverse = 0; + condnum++; + continue; + } + } + + pbgn = poct + 1; + + if (ret == 0 || ret == 1) { + if (reverse) ret = ret > 0 ? 0 : 1; + + if (condcmp == 1) condval = condval && ret; + else if (condcmp == 2) condval = condval || ret; + else condval = ret; + + condcmp = 0; + reverse = 0; + condnum++; + } + + } else if (pbgn[0] == '!') { + reverse = 1; + pbgn++; + continue; + + } else { + ret = script_if_objcmp_parse(hsc, pbgn, pend-pbgn, &poct, NULL, 0, NULL, NULL, 0); + if (ret == 2) { //only one varobj, eg. if (($request_path) != "/opt/abc.txt") { + pval = skipOver(poct, pend-poct, " \t\r\n\f\v", 6); + if (pval >= pend) { + if (pterm) *pterm = poct; + if (condnum < 1) return 2; + } + + get_var_value(hsc, pbgn, poct-pbgn, buf, sizeof(buf)-1, 1); + pval = trim_var(buf, strlen(buf)); + + if (strlen(pval) <= 0 || + strcasecmp(pval, "0") == 0 || + strcasecmp(pval, "false") == 0 || + strcasecmp(pval, "no") == 0) + ret = 0; + else ret = 1; + + if (condnum > 0) { + } else { + } + } + + if (reverse) ret = ret > 0 ? 0 : 1; + + if (condcmp == 1) condval = condval && ret; + else if (condcmp == 2) condval = condval || ret; + else condval = ret; + + pbgn = poct; + condcmp = 0; + reverse = 0; + condnum++; + } + + pbgn = skipOver(pbgn, pend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pend) break; -onevar: - poct = trim_var(bufa, strlen(bufa)); - if (strlen(poct) <= 0) return reverse; + if (pend - pbgn >= 2) { + if (pbgn[0] == '&' && pbgn[1] == '&') { + condcmp = 1; // AND operation + pbgn += 2; + } else if (pbgn[0] == '|' && pbgn[1] == '|') { + condcmp = 2; // OR operation + pbgn += 2; + } else if (adf_tolower(pbgn[0]) == 'o' && adf_tolower(pbgn[1]) == 'r') { + condcmp = 2; // OR operation + pbgn += 2; + } + } + if (pend - pbgn >= 3) { + if (adf_tolower(pbgn[0]) == 'a' && adf_tolower(pbgn[1]) == 'n' && adf_tolower(pbgn[2]) == 'd') { + condcmp = 1; // AND operation + pbgn += 3; + } + } - if (strcasecmp(poct, "0") == 0 || - strcasecmp(poct, "false") == 0 || - strcasecmp(poct, "no") == 0) - return reverse; + if (condcmp == 0) break; + } - return !reverse; + return condval; } char * script_if_parse (void * vhsc, char * p, int slen) @@ -501,21 +918,21 @@ char * script_if_parse (void * vhsc, char * p, int slen) pbgn = skipTo(poct, pend-poct, ";", 1); return pbgn; } - + pexpend = skipTo(poct, pend-poct, ";", 1); pval = skipToPeer(poct, pexpend-poct, '(', ')'); if (*pval != ')') { return pexpend; } - + if (!ifbody_exec) { - condval = script_if_conditiion_parse(hsc, poct + 1, pval - poct - 1); + condval = script_if_condition_parse(hsc, poct + 1, pval - poct - 1, NULL); } - + /* skip the condition block, stop to the if body */ pbgn = skipOver(pval+1, pend-pval-1, " \t\r\n\f\v", 6); if (pbgn >= pend) return pbgn; - + if (*pbgn == '{') { /* if (cond) { ... } find { and assign to pbgn */ pval = skipToPeer(pbgn, pend-pbgn, '{', '}'); @@ -525,7 +942,7 @@ char * script_if_parse (void * vhsc, char * p, int slen) } if (*pval == '}') pval++; - + } else if (pend - pbgn >= 2 && str_ncmp(pbgn, "if", 2) == 0) { /* if (cond) if (cond2) {... } */ pval = script_if_parse(hsc, pbgn, pend-pbgn); @@ -1254,50 +1671,374 @@ char * script_del_res_header_parse (void * vhsc, char * p, int len) return pexpend; } -char * script_try_files_parse (void * vhsc, char * p, int len) -{ +char * script_add_res_body_parse (void * vhsc, char * p, int len) +{ HTTPScript * hsc = (HTTPScript *)vhsc; HTTPMsg * msg = NULL; char * pbgn = NULL; char * pend = NULL; char * poct = NULL; char * pexpend = NULL; - char name[2048]; - int namelen = 0; - char path[4092]; - uint8 lastitem = 0; - int status = 0; - HTTPHost * phost = NULL; - HTTPLoc * ploc = NULL; - + HeaderUnit * punit = NULL; + int64 val64 = 0; + int64 addlen = 0; + if (!hsc) return p; - + msg = (HTTPMsg *)hsc->msg; if (!msg) return p; - + if (!p) return NULL; if (len < 0) len = strlen(p); if (len <= 2) return p; - - /* try_files file1 file2 ... uri;; - or try_files file1 file2 ... =code; */ - - pbgn = p; + + /* addResBody "added body content"; + insert the content to the head of response body */ + + pbgn = p; pend = p + len; - + + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); + if (pbgn >= pend) return pbgn; + + pexpend = skipQuoteTo(pbgn, pend-pbgn, ";", 1); + if (pexpend - pbgn < 12) return pexpend; + + if (strncasecmp(pbgn, "addResBody", 10) != 0) return pexpend; + pbgn += 10; + + pbgn = skipOver(pbgn, pexpend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pexpend) return pexpend; + + /* extracting body value */ + poct = goto_symbol_end(pbgn, pexpend - pbgn); + + poct = rskipOver(poct-1, poct-pbgn, " \t\r\n\f\v", 6); + if (poct < pbgn) return pexpend; + + if ((*pbgn == '"' || *pbgn == '\'') && *poct == *pbgn) { + pbgn++; poct--; + } + + if (poct >= pbgn) { + addlen = poct - pbgn + 1; + addlen = chunk_prepend_strip_buffer(msg->res_body_chunk, pbgn, addlen, "\r\n\t\b\f\v'\"\\/", 10, 0); + if (addlen < 0) addlen = 0; + + if (msg->res_body_flag == BC_CONTENT_LENGTH) { + punit = http_header_get(msg, 1, "Content-Length", 14); + if (punit) { + val64 = strtoll(punit->value, NULL, 10); + val64 += addlen; + + http_header_del(msg, 1, "Content-Length", 14); + } else { + val64 = addlen; + } + http_header_append_int64(msg, 1, "Content-Length", 14, val64); + + } else if (msg->res_body_flag == BC_TE) { + if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { + http_header_append(msg, 1, "Transfer-Encoding", 17, "chunked", 7); + } + } + } + + return pexpend; +} + +char * script_append_res_body_parse (void * vhsc, char * p, int len) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + HTTPMsg * msg = NULL; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + char * pexpend = NULL; + HeaderUnit * punit = NULL; + int64 val64 = 0; + int64 addlen = 0; + + if (!hsc) return p; + + msg = (HTTPMsg *)hsc->msg; + if (!msg) return p; + + if (!p) return NULL; + if (len < 0) len = strlen(p); + if (len <= 2) return p; + + /* appendResBody "appended body content"; + insert the content to the tail of response body */ + + pbgn = p; + pend = p + len; + + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); + if (pbgn >= pend) return pbgn; + + pexpend = skipQuoteTo(pbgn, pend-pbgn, ";", 1); + if (pexpend - pbgn < 12) return pexpend; + + if (strncasecmp(pbgn, "appendResBody", 13) != 0) return pexpend; + pbgn += 13; + + pbgn = skipOver(pbgn, pexpend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pexpend) return pexpend; + + /* extracting body value */ + poct = goto_symbol_end(pbgn, pexpend - pbgn); + + poct = rskipOver(poct-1, poct-pbgn, " \t\r\n\f\v", 6); + if (poct < pbgn) return pexpend; + + if ((*pbgn == '"' || *pbgn == '\'') && *poct == *pbgn) { + pbgn++; poct--; + } + + if (poct >= pbgn) { + addlen = poct - pbgn + 1; + addlen = chunk_append_strip_buffer(msg->res_body_chunk, pbgn, addlen, "\r\n\t\b\f\v'\"\\/", 10); + if (addlen < 0) addlen = 0; + + if (msg->res_body_flag == BC_CONTENT_LENGTH) { + punit = http_header_get(msg, 1, "Content-Length", 14); + if (punit) { + val64 = strtoll(punit->value, NULL, 10); + val64 += addlen; + + http_header_del(msg, 1, "Content-Length", 14); + } else { + val64 = addlen; + } + http_header_append_int64(msg, 1, "Content-Length", 14, val64); + + } else if (msg->res_body_flag == BC_TE) { + if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { + http_header_append(msg, 1, "Transfer-Encoding", 17, "chunked", 7); + } + } + + if (poct) kfree(poct); + } + + return pexpend; +} + +char * script_add_file_to_res_body_parse (void * vhsc, char * p, int len) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + HTTPMsg * msg = NULL; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + char * pexpend = NULL; + char fpath[2048]; + char value[1024]; + HeaderUnit * punit = NULL; + int64 fsize = 0; + int64 val64 = 0; + + if (!hsc) return p; + + msg = (HTTPMsg *)hsc->msg; + if (!msg) return p; + + if (!p) return NULL; + if (len < 0) len = strlen(p); + if (len <= 2) return p; + + /* addFile2ResBody /abc/def.js; + addFile2ResBody $file_path */ + + pbgn = p; + pend = p + len; + + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); + if (pbgn >= pend) return pbgn; + + pexpend = skipQuoteTo(pbgn, pend-pbgn, ";", 1); + if (pexpend - pbgn < 12) return pexpend; + + if (strncasecmp(pbgn, "addFile2ResBody", 15) != 0) return pexpend; + pbgn += 15; + + pbgn = skipOver(pbgn, pexpend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pexpend) return pexpend; + + /* extracting file path to be appended to body */ + poct = goto_symbol_end(pbgn, pexpend - pbgn); + get_var_value(hsc, pbgn, poct-pbgn, value, sizeof(value)-1, 1); + + poct = str_trim(value); + if (!poct || strlen(poct) <= 0) + return pexpend; + + if (poct[0] == '/') { + sprintf(fpath, "%s", msg->GetRootPath(msg)); + sprintf(fpath + strlen(fpath), "%s", poct); + } else { + fpath[0] = '\0'; + msg->GetRealPath(msg, fpath, sizeof(fpath)-1); + sprintf(fpath + strlen(fpath), "%s", poct); + } + + if (msg->res_body_flag == BC_TE) val64 = 2 * 1024 * 1024; + else val64 = 0; + + fsize = chunk_prepend_file(msg->res_body_chunk, fpath, val64); + if (fsize > 0) { + if (msg->res_body_flag == BC_CONTENT_LENGTH) { + punit = http_header_get(msg, 1, "Content-Length", 14); + if (punit) { + val64 = strtoll(punit->value, NULL, 10); + val64 += fsize; + + http_header_del(msg, 1, "Content-Length", 14); + } else { + val64 = fsize; + } + http_header_append_int64(msg, 1, "Content-Length", 14, val64); + + } else if (msg->res_body_flag == BC_TE) { + if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { + http_header_append(msg, 1, "Transfer-Encoding", 17, "chunked", 7); + } + } + } + + return pexpend; +} + +char * script_append_file_to_res_body_parse (void * vhsc, char * p, int len) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + HTTPMsg * msg = NULL; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + char * pexpend = NULL; + char fpath[2048]; + char value[1024]; + HeaderUnit * punit = NULL; + int64 fsize = 0; + int64 val64 = 0; + + if (!hsc) return p; + + msg = (HTTPMsg *)hsc->msg; + if (!msg) return p; + + if (!p) return NULL; + if (len < 0) len = strlen(p); + if (len <= 2) return p; + + /* appendFile2ResBody /abc/def.js; + appendFile2ResBody $file_path */ + + pbgn = p; + pend = p + len; + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); if (pbgn >= pend) return pbgn; pexpend = skipQuoteTo(pbgn, pend-pbgn, ";", 1); if (pexpend - pbgn < 12) return pexpend; + if (strncasecmp(pbgn, "appendFile2ResBody", 18) != 0) return pexpend; + pbgn += 18; + + pbgn = skipOver(pbgn, pexpend-pbgn, " \t\r\n\f\v", 6); + if (pbgn >= pexpend) return pexpend; + + /* extracting file path to be appended to body */ + poct = goto_symbol_end(pbgn, pexpend - pbgn); + get_var_value(hsc, pbgn, poct-pbgn, value, sizeof(value)-1, 1); + + poct = str_trim(value); + if (!poct || strlen(poct) <= 0) + return pexpend; + + if (poct[0] == '/') { + sprintf(fpath, "%s", msg->GetRootPath(msg)); + sprintf(fpath + strlen(fpath), "%s", poct); + } else { + fpath[0] = '\0'; + msg->GetRealPath(msg, fpath, sizeof(fpath)-1); + sprintf(fpath + strlen(fpath), "%s", poct); + } + + if (msg->res_body_flag == BC_TE) val64 = 2 * 1024 * 1024; + else val64 = 0; + + fsize = chunk_append_file(msg->res_body_chunk, fpath, val64); + if (fsize > 0) { + if (msg->res_body_flag == BC_CONTENT_LENGTH) { + punit = http_header_get(msg, 1, "Content-Length", 14); + if (punit) { + val64 = strtoll(punit->value, NULL, 10); + val64 += fsize; + + http_header_del(msg, 1, "Content-Length", 14); + } else { + val64 = fsize; + } + http_header_append_int64(msg, 1, "Content-Length", 14, val64); + + } else if (msg->res_body_flag == BC_TE) { + if (http_header_get(msg, 1, "Transfer-Encoding", -1) == NULL) { + http_header_append(msg, 1, "Transfer-Encoding", 17, "chunked", 7); + } + } + } + + return pexpend; +} + +char * script_try_files_parse (void * vhsc, char * p, int len) +{ + HTTPScript * hsc = (HTTPScript *)vhsc; + HTTPMsg * msg = NULL; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + char * pexpend = NULL; + char name[2048]; + int namelen = 0; + char path[4092]; + uint8 lastitem = 0; + int status = 0; + HTTPHost * phost = NULL; + HTTPLoc * ploc = NULL; + + if (!hsc) return p; + + msg = (HTTPMsg *)hsc->msg; + if (!msg) return p; + + if (!p) return NULL; + if (len < 0) len = strlen(p); + if (len <= 2) return p; + + /* try_files file1 file2 ... uri;; + or try_files file1 file2 ... =code; */ + + pbgn = p; + pend = p + len; + + pbgn = skipOver(pbgn, len, " \t\r\n\f\v", 6); + if (pbgn >= pend) return pbgn; + + pexpend = skipQuoteTo(pbgn, pend-pbgn, ";", 1); + if (pexpend - pbgn < 12) return pexpend; + if (strncasecmp(pbgn, "try_files", 9) != 0) return pexpend; pbgn += 9; - + while (pbgn < pend) { pbgn = skipOver(pbgn, pexpend-pbgn, " \t\r\n\f\v", 6); if (pbgn >= pexpend) return pexpend; - + /* extracting file from list to check if existing or not */ poct = goto_symbol_end(pbgn, pexpend - pbgn); @@ -1348,17 +2089,18 @@ char * script_try_files_parse (void * vhsc, char * p, int len) } } } - + return pexpend; } int http_script_parse_exec (void * vhsc, char * sc, int sclen) { - HTTPScript * hsc = (HTTPScript *)vhsc; - char * pbgn = NULL; - char * pend = NULL; - char * poct = NULL; - int len = 0; + HTTPScript * hsc = (HTTPScript *)vhsc; + char * pbgn = NULL; + char * pend = NULL; + char * poct = NULL; + int len = 0; + ScriptParser * parser = NULL; if (!hsc) return -1; @@ -1411,77 +2153,18 @@ int http_script_parse_exec (void * vhsc, char * sc, int sclen) continue; } - for (poct = pbgn; is_var_char(*poct) && poct < pend; poct++); - - len = poct - pbgn; - if (len == 2 && str_ncmp(pbgn, "if", 2) == 0) { - /* if (conditioin) { ... } */ - poct = script_if_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - - pbgn = poct; - continue; - } - - else if (len == 3 && str_ncmp(pbgn, "set", 3) == 0) { - poct = script_set_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; + for (poct = pbgn, len = 0; poct < pend; poct++, len++) { + if (len == 0 && !is_var_char(*poct)) break; + if (len > 0 && !is_var_char(*poct) && !isdigit(*poct)) break; } - else if (len == 5 && str_ncmp(pbgn, "reply", 5) == 0) { - poct = script_reply_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } - - else if (len == 6 && str_ncmp(pbgn, "return", 6) == 0) { - poct = script_return_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } - - else if (len == 7 && str_ncmp(pbgn, "rewrite", 7) == 0) { - poct = script_rewrite_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } - - else if (len == 12 && str_ncmp(pbgn, "addReqHeader", 12) == 0) { - poct = script_add_req_header_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } - - else if (len == 12 && str_ncmp(pbgn, "addResHeader", 12) == 0) { - poct = script_add_res_header_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } + len = poct - pbgn; - else if (len == 12 && str_ncmp(pbgn, "delReqHeader", 12) == 0) { - poct = script_del_req_header_parse(hsc, pbgn, pend-pbgn); + parser = script_parser_get(pbgn, len); + if (parser) { + poct = (*parser)(hsc, pbgn, pend-pbgn); if (!poct) return -101; - pbgn = poct; - continue; - } - else if (len == 12 && str_ncmp(pbgn, "delResHeader", 12) == 0) { - poct = script_del_res_header_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; - pbgn = poct; - continue; - } - - else if (len == 9 && str_ncmp(pbgn, "try_files", 9) == 0) { - poct = script_try_files_parse(hsc, pbgn, pend-pbgn); - if (!poct) return -101; pbgn = poct; continue; } @@ -1631,3 +2314,128 @@ int http_script_exec (void * vmsg) return 1; } +int http_reply_script_exec (void * vmsg) +{ + HTTPMsg * msg = (HTTPMsg *)vmsg; + HTTPScript hsc; + HTTPListen * hl = NULL; + HTTPHost * host = NULL; + HTTPLoc * ploc = NULL; + int i, num; + ckstr_t * psc = NULL; + + if (!msg) return -1; + + memset(&hsc, 0, sizeof(hsc)); + + hl = (HTTPListen *)msg->hl; + if (hl) { + num = arr_num(hl->reply_script_list); + + for (i = 0; i < num; i++) { + psc = arr_value(hl->reply_script_list, i); + if (!psc || !psc->p || psc->len <= 0) + continue; + + http_script_init(&hsc, msg, psc->p, psc->len, 1, NULL, 0); + + http_script_parse_exec(&hsc, psc->p, psc->len); + + http_script_free(&hsc); + } + } + + host = (HTTPHost *)msg->phost; + if (host) { + num = arr_num(host->reply_script_list); + + for (i = 0; i < num; i++) { + psc = arr_value(host->reply_script_list, i); + if (!psc || !psc->p || psc->len <= 0) + continue; + + http_script_init(&hsc, msg, psc->p, psc->len, 2, NULL, 0); + + http_script_parse_exec(&hsc, psc->p, psc->len); + + http_script_free(&hsc); + } + } + + ploc = (HTTPLoc *)msg->ploc; + if (ploc) { + num = arr_num(ploc->reply_script_list); + + for (i = 0; i < num; i++) { + psc = arr_value(ploc->reply_script_list, i); + if (!psc || !psc->p || psc->len <= 0) + continue; + + http_script_init(&hsc, msg, psc->p, psc->len, 3, NULL, 0); + + http_script_parse_exec(&hsc, psc->p, psc->len); + + http_script_free(&hsc); + } + } + + return 1; +} + +void script_parser_init () +{ + int i, num; + ckstr_t key; + + static scmd_t scmd_tab [] = { + { "if", 2, script_if_parse }, + { "set", 3, script_set_parse }, + { "reply", 5, script_reply_parse }, + { "return", 6, script_return_parse }, + { "rewrite", 7, script_rewrite_parse }, + { "addReqHeader", 12, script_add_req_header_parse }, + { "addResHeader", 12, script_add_res_header_parse }, + { "delReqHeader", 12, script_del_req_header_parse }, + { "delResHeader", 12, script_del_res_header_parse }, + { "addResBody", 10, script_add_res_body_parse }, + { "appendResBody", 13, script_append_res_body_parse }, + { "addFile2ResBody", 15, script_add_file_to_res_body_parse }, + { "appendFile2ResBody", 18, script_append_file_to_res_body_parse }, + { "try_files", 9, script_try_files_parse } + }; + + if (script_parser_table) return; + + script_parser_table = ht_only_new(200, ckstr_cmp); + if (!script_parser_table) return; + + ht_set_hash_func(script_parser_table, ckstr_string_hash); + + num = sizeof(scmd_tab) / sizeof(scmd_tab[0]); + for (i = 0; i < num; i++) { + key.p = scmd_tab[i].cmd; + key.len = scmd_tab[i].len; + ht_set(script_parser_table, &key, &scmd_tab[i]); + } +} + +void script_parser_clean () +{ + if (!script_parser_table) return; + + ht_free(script_parser_table); + + script_parser_table = NULL; +} + +void * script_parser_get (char * cmd, int len) +{ + ckstr_t key = ckstr_init(cmd, len); + scmd_t * scmd; + + scmd = ht_get(script_parser_table, &key); + if (scmd) return scmd->parser; + + return NULL; +} + diff --git a/src/http_sndpxy.c b/src/http_sndpxy.c index fd637ba..24186d7 100644 --- a/src/http_sndpxy.c +++ b/src/http_sndpxy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_srv.c b/src/http_srv.c index abad8ec..b6a371b 100644 --- a/src/http_srv.c +++ b/src/http_srv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_srv_io.c b/src/http_srv_io.c index dc72d9a..31ef1c7 100644 --- a/src/http_srv_io.c +++ b/src/http_srv_io.c @@ -248,8 +248,7 @@ int http_srv_send (void * vcon) bodypos = msg->req_stream_sent - msg->req_header_length; if (bodypos <= 0) bodypos = 0; - (*msg->req_send_procnotify)(msg, msg->req_send_procnotify_para, - bodypos, filepos - msg->req_header_length - bodypos); + (*msg->req_send_procnotify)(msg, msg->req_send_procnotify_para, bodypos, num); } msg->req_stream_sent += num; @@ -439,9 +438,9 @@ int http_srv_recv (void * vcon) return 0; } - if (msg->reshandle && !msg->reshandle_called) { - (*msg->reshandle)(msg, msg->reshandle_para, msg->reshandle_cbval, msg->res_status); - msg->reshandle_called = 1; + if (msg->resnotify && !msg->resnotify_called) { + (*msg->resnotify)(msg, msg->resnotify_para, msg->resnotify_cbval, msg->res_status); + msg->resnotify_called = 1; } http_msg_close(msg); diff --git a/src/http_ssl.c b/src/http_ssl.c index 56ca037..ddcdf4c 100644 --- a/src/http_ssl.c +++ b/src/http_ssl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ @@ -247,7 +247,7 @@ int http_ssl_servername_select (SSL * ssl, int * ad, void * arg) if (!hl) return SSL_TLSEXT_ERR_NOACK; - host = http_listen_get_host(hl, servername); + host = http_listen_host_get(hl, servername); if (!host) return SSL_TLSEXT_ERR_NOACK; diff --git a/src/http_status.c b/src/http_status.c index dd84f9a..6051e6b 100644 --- a/src/http_status.c +++ b/src/http_status.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_uri.c b/src/http_uri.c index b908d29..5801492 100644 --- a/src/http_uri.c +++ b/src/http_uri.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */ diff --git a/src/http_variable.c b/src/http_variable.c index 87413f9..5cb73b5 100644 --- a/src/http_variable.c +++ b/src/http_variable.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Ke Hengzhong + * Copyright (c) 2003-2021 Ke Hengzhong * All rights reserved. See MIT LICENSE for redistribution. */