#include "api.h" #include #include #include #define IIS_TYPE 'IIS' #define MIN_BUFFER 256 #define MAX_BUFFER 65536 const char *mime_type(const char *ext); ///////////////////////////////////////////////////////////////////// class zsIIS { long bytes; char ctype[MIN_BUFFER]; public: zsIIS(LPEXTENSION_CONTROL_BLOCK pECB); ~zsIIS(); DWORD send(void* ptr, DWORD size); void mime(const char *ext); long size() { return bytes; } LPEXTENSION_CONTROL_BLOCK pECB; }; zsIIS::zsIIS(LPEXTENSION_CONTROL_BLOCK pECB) { this->pECB = pECB; mime("htm"); bytes = 0; } zsIIS::~zsIIS() { } void zsIIS::mime(const char *ext) { const char *p = mime_type(ext); if (p) strcpy(ctype, p); else strcpy(ctype, ext); } DWORD zsIIS::send(void* ptr, DWORD size) { if (bytes==0) { // send content header once char header[256]; sprintf(header, "Content-type: %s\r\n\r\n", ctype); HSE_SEND_HEADER_EX_INFO hdi; hdi.pszStatus = "200 OK"; hdi.pszHeader = header; hdi.cchStatus = strlen(hdi.pszStatus); hdi.cchHeader = strlen(hdi.pszHeader); hdi.fKeepConn = FALSE; if (!pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &hdi, NULL, NULL)) return HSE_STATUS_ERROR; } if (ptr && size>0) { if (!pECB->WriteClient(pECB->ConnID, ptr, &size, HSE_IO_SYNC)) return HSE_STATUS_ERROR; } bytes += size; return HSE_STATUS_SUCCESS; } std::string url_decode(const char *s, int len) { std::string ret; int i = 0; while (i < len) { if (s[i] == '%' && s[i+1] && s[i+2]) { char tmp[] = "0x0__"; tmp[3] = s[++i]; tmp[4] = s[++i]; ret += strtol(tmp, NULL, 16); } else { if (s[i] == '+') ret += ' '; else ret += s[i]; } i++; } return ret; } bool process_form(LPEXTENSION_CONTROL_BLOCK pECB, void *ctx) { void *arr = api_create_array(0, 32); api_set_object(ctx, "HTTP_PARS", arr); char *s1 = pECB->lpszQueryString; if (strcmp(pECB->lpszMethod, "POST") == 0) { if (pECB->cbTotalBytes > pECB->cbAvailable) { s1 = (char*)malloc(pECB->cbTotalBytes+1); if (!s1) return false; api_create_user(ctx, s1, 0, free, 0); s1[pECB->cbTotalBytes] = 0; strncpy(s1, (char*)pECB->lpbData, pECB->cbAvailable); char *cur = s1 + pECB->cbAvailable; DWORD read = pECB->cbAvailable; while (read < pECB->cbTotalBytes) { DWORD nb = pECB->cbTotalBytes - read; BOOL status = pECB->ReadClient(pECB->ConnID, cur, &nb); if (status == FALSE || nb == 0) return false; cur += nb; read += nb; } } else { s1 = (char*)pECB->lpbData; } } char *s2 = strchr(s1, '='); while (s1 && s2) { std::string name, value; name = url_decode(s1, s2-s1); if (name.empty()) return false; s1 = s2 + 1; s2 = strchr(s1, '&'); if (!s2) { value = url_decode(s1, strlen(s1)); } else { value = url_decode(s1, s2-s1); s1 = s2 + 1; s2 = strchr(s1, '='); } if (!value.empty()) { api_set_array_object(ctx, arr, name.c_str(), api_create_string(0, value.c_str())); } else { api_set_array_object(ctx, arr, name.c_str(), api_create_string(0, "")); } } return true; } BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO* pVer) { pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR); lstrcpyn(pVer->lpszExtensionDesc, "Z-Script ISAPI Extension", HSE_MAX_EXT_DLL_NAME_LEN-1); return TRUE; } DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK pECB) { zsIIS iis(pECB); /* if (strcmp(pECB->lpszMethod, "GET")==0 && strlen(pECB->lpszQueryString)==0) { // Send the source code when no query parameter is given. FILE *f = fopen(pECB->lpszPathTranslated, "r"); std::string s; if (f) { char buf[MAX_BUFFER]; while (!feof(f)) { if (!fgets(buf, MAX_BUFFER-1, f)) break; s += buf; } fclose(f); iis.mime("txt"); return iis.send((void*)s.c_str(), s.size()); } s = "Failed to open "; s += pECB->lpszPathInfo; return iis.send((void*)s.c_str(), s.size()); } */ // Get the physical path of script file. int len1 = strlen(pECB->lpszPathTranslated); int len2 = strlen(pECB->lpszPathInfo); int i, j; for (i = len1-1, j = len2-1; i > 0 && j > 0; i--, j--) { if (toupper(pECB->lpszPathTranslated[i]) != toupper(pECB->lpszPathInfo[j])) { if (pECB->lpszPathTranslated[i] != '\\' || pECB->lpszPathInfo[j] != '/') break; } } std::string path(pECB->lpszPathTranslated); path = path.substr(0,i+2); for (i = 0; i < path.size(); i++) { if (path.at(i) == '\\') path.at(i) = '/'; } char error[512]; // Parse script void *module = api_parse_file2(pECB->lpszPathInfo+j+2, error, path.c_str()); if (!module) { return iis.send(error, strlen(error)); } void *ctx = api_get_context(module); // Script may use HTTP_PATH to do path related IO api_set_object(ctx, "HTTP_PATH", api_create_string(0, path.c_str())); // Save all form parameters in HTTP_PARS if (!process_form(pECB, ctx)) { api_delete_module(module); strcpy(error, "Failed to get form data."); return iis.send(error, strlen(error)); } // Pass iis to the module for function call by script api_set_object(ctx, "HTTP_IIS", api_create_user(0, &iis, 0, 0, IIS_TYPE)); api_set_object(ctx, "HTTP_SOAP", api_create_user(0, &iis, 0, 0, IIS_TYPE)); if (api_exec_module(module, error) <= 0) { api_delete_module(module); if (!strcmp(error, "error: default exception")) return iis.send("Busy. Try again.", 16); else return iis.send(error, strlen(error)); } // Always reply with something api_delete_module(module); if (iis.size() <= 0) iis.send("Default OK response.", 20); return HSE_STATUS_SUCCESS; } void* iis_mime(void* ctx, int nargs, void **args) { if (nargs < 2) api_input_error(ctx); zsIIS *u = (zsIIS*)api_get_user(ctx, args[0], IIS_TYPE); u->mime(api_get_string(ctx, args[1])); return 0; } void* iis_send(void* ctx, int nargs, void **args) { if (nargs < 2) api_input_error(ctx); zsIIS *u = (zsIIS*)api_get_user(ctx, args[0], IIS_TYPE); if (nargs == 2) { const char *msg = api_get_string(ctx, args[1]); u->send((void*)msg, strlen(msg)); } else { // Send binary data u->send(api_get_ptr(ctx, args[1]), api_get_integer(ctx, args[2])); } return 0; } void* iis_vars(void* ctx, int nargs, void **args) { if (nargs < 2) api_input_error(ctx); zsIIS *u = (zsIIS*)api_get_user(ctx, args[0], IIS_TYPE); char buf[MAX_BUFFER]; DWORD nb = MAX_BUFFER-1; // Get server variable BOOL status = u->pECB->GetServerVariable(u->pECB->ConnID, (char*)api_get_string(ctx, args[1]), buf, &nb); if (status == TRUE) { buf[nb] = 0; return api_create_string(ctx, buf); } return 0; } void* iis_fsend(void *ctx, int nargs, void** args) { if (nargs < 2) api_input_error(ctx); zsIIS *u = (zsIIS*)api_get_user(ctx, args[0], IIS_TYPE); FILE *f = fopen(api_get_string(ctx, args[1]), "r"); if (!f) return 0; fseek(f, 0, SEEK_END); int size = ftell(f) - 2; if (size <= 0) { fclose(f); return api_create_integer(ctx, size); } rewind(f); void *ptr = malloc(size); if (!ptr) return 0; fread(ptr, 1, size, f); fclose(f); u->send(ptr, size); return api_create_integer(ctx, size); } void* iis_exec(void *ctx, int nargs, void** args) { return api_create_string(ctx, "exec is not allowed in web application."); } BOOL WINAPI DllMain(IN HINSTANCE hinstDll, IN DWORD dwReason, IN LPVOID lpvContext) { switch(dwReason) { case DLL_PROCESS_ATTACH: api_add_primitive("mime", IIS_TYPE, iis_mime); api_add_primitive("send", IIS_TYPE, iis_send); api_add_primitive("fsend", IIS_TYPE, iis_fsend); api_add_primitive("vars", IIS_TYPE, iis_vars); api_add_primitive("exec", 0, iis_exec); break; case DLL_PROCESS_DETACH : break; } return TRUE; } ///////////////////////////////////////////////////////////////////// struct mineType { const char *ext, *type; }; static mineType g_mine[] = { {"*", "application/octet-stream" }, {"htm", "text/html" }, {"html", "text/html" }, {"pdf", "application/pdf" }, {"jpeg", "image/jpeg" }, {"png", "image/png" }, {"mpg", "video/mpeg" }, {"mpeg", "video/mpeg" }, {"asf", "video/x-ms-asf" }, {"avi", "video/x-msvideo" }, {"bmp", "image/bmp" }, {"jpg", "image/jpeg" }, {"gif", "image/gif" }, {"ico", "image/x-icon" }, {"txt", "text/plain" }, {"css", "text/css" }, {"zip", "application/x-zip-compressed" }, {"tgz", "application/x-tar-gz" }, {"tar.gz", "application/x-tar-gz" }, {"tar", "application/x-tar" }, {"gz", "application/x-gunzip" }, {"arj", "application/x-arj-compressed" }, {"rar", "application/x-arj-compressed" }, {"wav", "audio/x-wav" }, {"mp3", "audio/x-mp3" }, {"mid", "audio/mid" }, {"m3u", "audio/x-mpegurl" }, {"ram", "audio/x-pn-realaudio" }, {"ra", "audio/x-pn-realaudio" }, {"svg", "image/svg+xml" }, {"doc", "application/msword", }, {"exe", "application/octet-stream" }, {"xls", "application/excel" }, {"ppt", "application/vnd.ms-powerpoint" }, {"rtf", "application/rtf" }, {"mathml", "application/mathml+xml" }, {"xml", "application/xml" }, {"xsl", "application/xml" }, {"dtd", "application/xml-dtd" }, {"xslt", "application/xslt+xml" }, {"xhtml", "application/xhtml+xml" }, {"xht", "application/xhtml+xml" }, {"mid", "audio/midi" }, {"midi", "audio/midi" }, {NULL, NULL } }; const char *mime_type(const char *ext) { mineType *p = g_mine; while (p->ext) { if (strcmp(p->ext, ext) == 0) break; p++; } return p->type; }