|
|
| version 1.123, 2020/12/15 13:37:35 | version 1.142, 2026/10/18 21:05:35 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: IIS extension. | Parser: IIS extension. |
| Copyright (c) 2000-2017 Art. Lebedev Studio (http://www.artlebedev.com) | Copyright (c) 2000-2026 Art. Lebedev Studio (https://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru> |
| */ | */ |
| volatile const char * IDENT_PARSER3ISAPI_C="$Id$"; | volatile const char * IDENT_PARSER3ISAPI_C="$Id$"; |
| Line 56 const int IIS51var_count=sizeof(IIS51var | Line 56 const int IIS51var_count=sizeof(IIS51var |
| // globals | // globals |
| char argv0[MAX_STRING]=""; | char argv0[MAX_STRING]=""; |
| const char* parser3_mode="isapi"; // $status:mode | |
| const char *parser3_log_filespec(){ return ""; } // $status:log-filename | |
| // SAPI | // SAPI |
| Line 80 void SAPI::log(SAPI_Info& SAPI_info, con | Line 82 void SAPI::log(SAPI_Info& SAPI_info, con |
| const char* prefix="PARSER_ERROR:"; | const char* prefix="PARSER_ERROR:"; |
| strcpy(buf, prefix); | strcpy(buf, prefix); |
| char *start=buf+strlen(prefix); | char *start=buf+strlen(prefix); |
| DWORD size=vsnprintf(start, MAX_LOG_STRING-strlen(prefix), fmt, args); | DWORD size=pa_vsnprintf(start, MAX_LOG_STRING-strlen(prefix), fmt, args); |
| size=remove_crlf(start, start+size); | size=remove_crlf(start, start+size); |
| SAPI_info.lpECB->ServerSupportFunction(SAPI_info.lpECB->ConnID, HSE_APPEND_LOG_PARAMETER, buf, &size, 0); | SAPI_info.lpECB->ServerSupportFunction(SAPI_info.lpECB->ConnID, HSE_APPEND_LOG_PARAMETER, buf, &size, 0); |
| Line 99 void SAPI::die(const char* fmt, ...) { | Line 101 void SAPI::die(const char* fmt, ...) { |
| // va_end(args); | // va_end(args); |
| } | } |
| void SAPI::send_error(SAPI_Info& SAPI_info, const char *exception_cstr, const char *status){ | |
| // capitalized headers passed for preventing malloc during capitalization | |
| add_header_attribute(SAPI_info, HTTP_STATUS_CAPITALIZED, status); | |
| add_header_attribute(SAPI_info, HTTP_CONTENT_TYPE_CAPITALIZED, "text/plain"); | |
| send_headers(SAPI_info); | |
| send_body(SAPI_info, exception_cstr, strlen(exception_cstr)); | |
| } | |
| char* SAPI::Env::get(SAPI_Info& SAPI_info, const char* name) { | char* SAPI::Env::get(SAPI_Info& SAPI_info, const char* name) { |
| char *variable_buf=new(PointerFreeGC) char[MAX_STRING]; | char *variable_buf=new(PointerFreeGC) char[MAX_STRING]; |
| DWORD variable_len = MAX_STRING-1; | DWORD variable_len = MAX_STRING-1; |
| Line 206 void SAPI::add_header_attribute(SAPI_Inf | Line 216 void SAPI::add_header_attribute(SAPI_Inf |
| } | } |
| /// @todo intelligent cache-control | /// @todo intelligent cache-control |
| void SAPI::send_header(SAPI_Info& SAPI_info) { | void SAPI::send_headers(SAPI_Info& SAPI_info) { |
| HSE_SEND_HEADER_EX_INFO header_info; | HSE_SEND_HEADER_EX_INFO header_info; |
| char status_buf[MAX_STATUS_LENGTH]; | char status_buf[MAX_STATUS_LENGTH]; |
| Line 221 void SAPI::send_header(SAPI_Info& SAPI_i | Line 231 void SAPI::send_header(SAPI_Info& SAPI_i |
| header_info.pszStatus="401 Authorization Required"; | header_info.pszStatus="401 Authorization Required"; |
| break; | break; |
| default: | default: |
| snprintf(status_buf, MAX_STATUS_LENGTH, | pa_snprintf(status_buf, MAX_STATUS_LENGTH, |
| "%d Undescribed", SAPI_info.http_response_code); | "%d Undescribed", SAPI_info.http_response_code); |
| header_info.pszStatus=status_buf; | header_info.pszStatus=status_buf; |
| break; | break; |
| Line 238 void SAPI::send_header(SAPI_Info& SAPI_i | Line 248 void SAPI::send_header(SAPI_Info& SAPI_i |
| HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); | HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); |
| } | } |
| void SAPI::clear_headers(SAPI_Info& SAPI_info) { | |
| SAPI_info.header=new String; | |
| } | |
| size_t SAPI::send_body(SAPI_Info& SAPI_info, const void *buf, size_t size) { | size_t SAPI::send_body(SAPI_Info& SAPI_info, const void *buf, size_t size) { |
| DWORD num_bytes=size; | DWORD num_bytes=size; |
| if(!SAPI_info.lpECB->WriteClient(SAPI_info.lpECB->ConnID, | if(!SAPI_info.lpECB->WriteClient(SAPI_info.lpECB->ConnID, |
| Line 272 static void parser_done() { | Line 286 static void parser_done() { |
| /// ISAPI // | /// ISAPI // |
| BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) { | BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) { |
| pVer->dwExtensionVersion = HSE_VERSION; | pVer->dwExtensionVersion = HSE_VERSION; |
| strncpy(pVer->lpszExtensionDesc, "Parser " PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN-1); | pa_strncpy(pVer->lpszExtensionDesc, "Parser " PARSER_VERSION_WITH_FEATURES, HSE_MAX_EXT_DLL_NAME_LEN); |
| pVer->lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN-1]=0; | |
| return parser_init(); | return parser_init(); |
| } | } |
| // dwFlags & HSE_TERM_MUST_UNLOAD means we can't return false | // dwFlags & HSE_TERM_MUST_UNLOAD means we can't return false |
| Line 297 BOOL WINAPI TerminateExtension( | Line 310 BOOL WINAPI TerminateExtension( |
| @test | @test |
| PARSER_VERSION from outside | PARSER_VERSION from outside |
| */ | */ |
| void real_parser_handler(SAPI_Info& SAPI_info, bool header_only) { | void real_parser_handler(SAPI_Info& SAPI_info) { |
| // collect garbage from prev request | // collect garbage from prev request |
| PA_GC_GCOLLECT; | pa_gc_collect(); |
| SAPI_info.header=new String; | SAPI_info.header=new String; |
| LPEXTENSION_CONTROL_BLOCK lpECB=SAPI_info.lpECB; | LPEXTENSION_CONTROL_BLOCK lpECB=SAPI_info.lpECB; |
| Line 307 void real_parser_handler(SAPI_Info& SAPI | Line 320 void real_parser_handler(SAPI_Info& SAPI |
| // Request info | // Request info |
| Request_info request_info; memset(&request_info, 0, sizeof(request_info)); | Request_info request_info; memset(&request_info, 0, sizeof(request_info)); |
| size_t path_translated_buf_size=strlen(lpECB->lpszPathTranslated)+1; | char *filespec_to_process=backslashes_to_slashes(lpECB->lpszPathTranslated); |
| char *filespec_to_process=pa_strdup(lpECB->lpszPathTranslated, path_translated_buf_size); | |
| #ifdef WIN32 | |
| back_slashes_to_slashes(filespec_to_process); | |
| #endif | |
| if(const char* path_info=SAPI::Env::get(SAPI_info, "PATH_INFO")) { | if(const char* path_info=SAPI::Env::get(SAPI_info, "PATH_INFO")) { |
| // IIS | // IIS |
| size_t len=strlen(filespec_to_process)-strlen(path_info); | size_t filespec_len=strlen(filespec_to_process); |
| char *buf=new(PointerFreeGC) char[len+1]; | size_t path_info_len=strlen(path_info); |
| strncpy(buf, filespec_to_process, len); buf[len]=0; | request_info.set_document_root(filespec_len>path_info_len ? pa_strdup(filespec_to_process, filespec_len-path_info_len) : ""); |
| request_info.document_root=buf; | |
| } else | } else |
| throw Exception(PARSER_RUNTIME, 0, "ISAPI: no PATH_INFO defined (in reinventing DOCUMENT_ROOT)"); | throw Exception(PARSER_RUNTIME, 0, "ISAPI: no PATH_INFO defined (in reinventing DOCUMENT_ROOT)"); |
| Line 336 void real_parser_handler(SAPI_Info& SAPI | Line 344 void real_parser_handler(SAPI_Info& SAPI |
| // beside by binary | // beside by binary |
| static char beside_binary_path[MAX_STRING]; | static char beside_binary_path[MAX_STRING]; |
| strncpy(beside_binary_path, argv0, MAX_STRING-1); beside_binary_path[MAX_STRING-1]=0; // filespec of my binary | pa_strncpy(beside_binary_path, argv0, MAX_STRING); // filespec of my binary |
| if(!(rsplit(beside_binary_path, '/') || rsplit(beside_binary_path, '\\'))) { // strip filename | if(!rsplit(beside_binary_path, "/\\")) { // strip filename |
| // no path, just filename | // no path, just filename |
| beside_binary_path[0]='.'; beside_binary_path[1]=0; | beside_binary_path[0]='.'; beside_binary_path[1]=0; |
| } | } |
| char config_filespec[MAX_STRING]; | char config_filespec[MAX_STRING]; |
| snprintf(config_filespec, MAX_STRING, "%s/%s", beside_binary_path, AUTO_FILE_NAME); | pa_snprintf(config_filespec, MAX_STRING, "%s/%s", beside_binary_path, AUTO_FILE_NAME); |
| // process the request | // process the request |
| request.core(entry_exists(config_filespec) ? config_filespec : NULL, header_only); | request.core(entry_exists(config_filespec) ? config_filespec : NULL); |
| } | } |
| #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION | #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION |
| static const Exception call_real_parser_handler__do_PEH_return_it(SAPI_Info& SAPI_info, bool header_only) { | static const Exception call_real_parser_handler__do_PEH_return_it(SAPI_Info& SAPI_info) { |
| try { | try { |
| real_parser_handler(SAPI_info, header_only); | real_parser_handler(SAPI_info); |
| } catch(const Exception& e) { | } catch(const Exception& e) { |
| return e; | return e; |
| } | } |
| Line 359 static const Exception call_real_parser_ | Line 367 static const Exception call_real_parser_ |
| return Exception(); | return Exception(); |
| } | } |
| static void call_real_parser_handler__supress_system_exception(SAPI_Info& SAPI_info, bool header_only) { | static void call_real_parser_handler__supress_system_exception(SAPI_Info& SAPI_info) { |
| Exception parser_exception; | Exception parser_exception; |
| LPEXCEPTION_POINTERS system_exception=0; | LPEXCEPTION_POINTERS system_exception=0; |
| __try { | __try { |
| parser_exception=call_real_parser_handler__do_PEH_return_it(SAPI_info, header_only); | parser_exception=call_real_parser_handler__do_PEH_return_it(SAPI_info); |
| } __except ( (system_exception=GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { | } __except ( (system_exception=GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { |
| if(system_exception) | if(system_exception) |
| if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord) | if(_EXCEPTION_RECORD *er=system_exception->ExceptionRecord) |
| throw Exception("system", 0, "0x%08X at 0x%08X", er->ExceptionCode, er->ExceptionAddress); | throw Exception("system", 0, "0x%08X at %p", er->ExceptionCode, er->ExceptionAddress); |
| else | else |
| throw Exception("system", 0, "<no exception record>"); | throw Exception("system", 0, "<no exception record>"); |
| else | else |
| Line 388 DWORD WINAPI HttpExtensionProc(LPEXTENSI | Line 396 DWORD WINAPI HttpExtensionProc(LPEXTENSI |
| 200 // default http_response_code [lpECB->dwHttpStatusCode seems to be always 0, even on 404 redirect to /404.html] | 200 // default http_response_code [lpECB->dwHttpStatusCode seems to be always 0, even on 404 redirect to /404.html] |
| }; | }; |
| bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0; | |
| try { // global try | try { // global try |
| #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION | #ifdef PA_SUPPRESS_SYSTEM_EXCEPTION |
| call_real_parser_handler__supress_system_exception( | call_real_parser_handler__supress_system_exception( |
| #else | #else |
| real_parser_handler( | real_parser_handler( |
| #endif | #endif |
| SAPI_info, header_only); | SAPI_info); |
| // successful finish | // successful finish |
| } catch(const Exception& e) { // exception in unhandled exception | } catch(const Exception& e) { // just in case |
| // log it | // log it |
| SAPI::log(SAPI_info, "%s", e.comment()); | SAPI::log(SAPI_info, "%s", e.comment()); |
| HSE_SEND_HEADER_EX_INFO header_info; | HSE_SEND_HEADER_EX_INFO header_info; |
| header_info.pszStatus="200 OK"; | header_info.pszStatus="500 Internal Server Error"; |
| header_info.cchStatus=strlen(header_info.pszStatus); | header_info.cchStatus=strlen(header_info.pszStatus); |
| header_info.pszHeader=HTTP_CONTENT_TYPE_CAPITALIZED ": text/plain\r\n\r\n"; | header_info.pszHeader=HTTP_CONTENT_TYPE_CAPITALIZED ": text/plain\r\n\r\n"; |
| header_info.cchHeader=strlen(header_info.pszHeader); | header_info.cchHeader=strlen(header_info.pszHeader); |
| header_info.fKeepConn=true; | header_info.fKeepConn=true; |
| // send header | // send header |
| lpECB->dwHttpStatusCode=200; | lpECB->dwHttpStatusCode=500; |
| lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); | lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL); |
| // send body | // send body |
| if(!header_only) | if(strcasecmp(lpECB->lpszMethod, "HEAD")!=0) |
| SAPI::send_body(SAPI_info, e.comment(), strlen(e.comment())); | SAPI::send_body(SAPI_info, e.comment(), strlen(e.comment())); |
| // unsuccessful finish | // unsuccessful finish |
| Line 434 BOOL WINAPI DllMain( | Line 441 BOOL WINAPI DllMain( |
| ); | ); |
| return TRUE; | return TRUE; |
| } | |
| } |