Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.1

1.1     ! paf         1: #ifndef _MSC_VER
        !             2: #      error compile ISAPI module with MSVC
        !             3: #endif
        !             4: 
        !             5: #include <windows.h>
        !             6: #include <process.h>
        !             7: 
        !             8: #include <httpext.h>
        !             9: #include <httpfilt.h>
        !            10: #include <httpext.h>
        !            11: 
        !            12: #include "pa_globals.h"
        !            13: #include "pa_request.h"
        !            14: #include "pa_version.h"
        !            15: 
        !            16: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION")
        !            17: #define ISAPI_SERVER_VAR_BUF_SIZE 0x400
        !            18: 
        !            19: //@{
        !            20: /// service func decl
        !            21: static const char *get_env(Pool& pool, const char *name) {
        !            22:        LPEXTENSION_CONTROL_BLOCK lpECB=static_cast<LPEXTENSION_CONTROL_BLOCK>(pool.context());
        !            23: 
        !            24:        char *variable_buf=(char *)pool.malloc(MAX_STRING);
        !            25:        DWORD variable_len = MAX_STRING-1;
        !            26: 
        !            27:        if(lpECB->GetServerVariable(lpECB->ConnID, const_cast<char *>(name), 
        !            28:                variable_buf, &variable_len)) {
        !            29:                variable_buf[variable_len]=0;
        !            30:                return variable_buf;
        !            31:        }
        !            32: 
        !            33:        variable_buf=(char *)pool.malloc(variable_len+1);
        !            34:        
        !            35:        if(lpECB->GetServerVariable(lpECB->ConnID, const_cast<char *>(name), 
        !            36:                variable_buf, &variable_len)) {
        !            37:                variable_buf[variable_len]=0;
        !            38:                return variable_buf;
        !            39:        }
        !            40: 
        !            41:        return 0;
        !            42: }
        !            43: 
        !            44: static uint read_post(Pool& pool, char *buf, uint max_bytes) {
        !            45:        LPEXTENSION_CONTROL_BLOCK lpECB=static_cast<LPEXTENSION_CONTROL_BLOCK>(pool.context());
        !            46: 
        !            47:        // todo: timeout
        !            48:        DWORD read_from_buf=0;
        !            49:        DWORD read_from_input=0;
        !            50:        DWORD total_read=0;
        !            51: 
        !            52:        read_from_buf=min(lpECB->cbAvailable, max_bytes);
        !            53:        memcpy(buf, lpECB->lpbData, read_from_buf);
        !            54:        total_read+=read_from_buf;
        !            55: 
        !            56:        if(read_from_buf<max_bytes &&
        !            57:                read_from_buf<lpECB->cbTotalBytes) {
        !            58:                DWORD cbRead=0, cbSize;
        !            59: 
        !            60:                read_from_input=min(max_bytes-read_from_buf, lpECB->cbTotalBytes-read_from_buf);
        !            61:                while(cbRead < read_from_input) {
        !            62:                        cbSize=read_from_input - cbRead;
        !            63:                        if(!lpECB->ReadClient(lpECB->ConnID, buf+read_from_buf+cbRead, &cbSize) || 
        !            64:                                cbSize==0) 
        !            65:                                break;
        !            66:                        cbRead+=cbSize;
        !            67:                }
        !            68:                total_read+=cbRead;
        !            69:        }
        !            70:        return total_read;
        !            71: }
        !            72: 
        !            73: static void add_header_attribute(Pool& pool, const char *key, const char *value) {
        !            74:        LPEXTENSION_CONTROL_BLOCK lpECB=static_cast<LPEXTENSION_CONTROL_BLOCK>(pool.context());
        !            75:        String *header=static_cast<String *>(pool.tag());
        !            76:        if(!header) 
        !            77:                pool.set_tag(header=new(pool) String(pool));
        !            78: 
        !            79:        header->APPEND_CONST(key);
        !            80:        header->APPEND_CONST(": ");
        !            81:        header->APPEND_CONST(value);
        !            82:        header->APPEND_CONST("\r\n");
        !            83: }
        !            84: 
        !            85: static void send_header(Pool& pool) {
        !            86:        LPEXTENSION_CONTROL_BLOCK lpECB=static_cast<LPEXTENSION_CONTROL_BLOCK>(pool.context());
        !            87:        String *header=static_cast<String *>(pool.tag());
        !            88:        if(!header) // never
        !            89:                return;
        !            90: 
        !            91:        header->APPEND_CONST("\r\n");
        !            92:        HSE_SEND_HEADER_EX_INFO header_info;
        !            93: 
        !            94:        int http_response_code=200; // todo: dig from headers
        !            95: 
        !            96:        char status_buf[MAX_STATUS_LENGTH];
        !            97:        switch(http_response_code) {
        !            98:                case 200:
        !            99:                        header_info.pszStatus="200 OK";
        !           100:                        break;
        !           101:                case 302:
        !           102:                        header_info.pszStatus="302 Moved Temporarily";
        !           103:                        break;
        !           104:                case 401:
        !           105:                        header_info.pszStatus="401 Authorization Required";
        !           106:                        break;
        !           107:                default:
        !           108:                        snprintf(status_buf, MAX_STATUS_LENGTH, "%d Undescribed", http_response_code);
        !           109:                        header_info.pszStatus=status_buf;
        !           110:                        break;
        !           111:        }
        !           112:        header_info.cchStatus=strlen(header_info.pszStatus);
        !           113:        header_info.pszHeader=header->cstr();
        !           114:        header_info.cchHeader=header->size();
        !           115: 
        !           116:        lpECB->dwHttpStatusCode=http_response_code;
        !           117: 
        !           118:        lpECB->ServerSupportFunction(lpECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, 
        !           119:                &header_info, NULL, NULL);
        !           120: }
        !           121: 
        !           122: static void send_body(Pool& pool, const char *buf, size_t size) {
        !           123:        LPEXTENSION_CONTROL_BLOCK lpECB=static_cast<LPEXTENSION_CONTROL_BLOCK>(pool.context());
        !           124: 
        !           125:        DWORD num_bytes=size;
        !           126:        lpECB->WriteClient(lpECB->ConnID, const_cast<char *>(buf), &num_bytes, HSE_IO_SYNC);
        !           127: }
        !           128: //@}
        !           129: 
        !           130: /// Service funcs 
        !           131: Service_funcs service_funcs={
        !           132:        get_env,
        !           133:        read_post,
        !           134:        add_header_attribute,
        !           135:        send_header,
        !           136:        send_body
        !           137: };
        !           138: 
        !           139: // 
        !           140: 
        !           141: static void parser_init() {
        !           142:        static bool globals_inited=false;
        !           143:        if(globals_inited)
        !           144:                return;
        !           145:        globals_inited=true;
        !           146: 
        !           147:        static Pool pool; // global pool
        !           148:        PTRY {
        !           149:                // init global variables
        !           150:                globals_init(pool);
        !           151:                
        !           152:                //...
        !           153:        } PCATCH(e) { // global problem 
        !           154:                const char *body=e.comment();
        !           155:                // TODO: somehow report that error
        !           156:        }
        !           157:        PEND_CATCH
        !           158: }
        !           159: 
        !           160: /// ISAPI //
        !           161: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) {
        !           162:        pVer->dwExtensionVersion = HSE_VERSION;
        !           163:        strncpy(pVer->lpszExtensionDesc, "Parser " PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN);
        !           164:        return TRUE;
        !           165: }
        !           166: 
        !           167: static BOOL exception_handler(LPEXCEPTION_POINTERS *e,LPEXCEPTION_POINTERS ep) {
        !           168:        *e=ep;
        !           169:        return TRUE;
        !           170: }
        !           171: 
        !           172: /// ISAPI // main workhorse
        !           173: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
        !           174:        Pool pool;
        !           175:        pool.set_context(lpECB);
        !           176: 
        !           177:        // TODO r->no_cache=1;
        !           178: 
        !           179:        bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
        !           180:        PTRY { // global try
        !           181:                // must be first in PTRY{}PCATCH
        !           182:                LPEXCEPTION_POINTERS e;
        !           183:                __try {
        !           184:                        
        !           185:                        const char *filespec_to_process=lpECB->lpszPathTranslated;
        !           186:                        
        !           187:                        // Request info
        !           188:                        Request::Info request_info;
        !           189:                        
        !           190:                        const char *document_root=0; // todo: get from somewhere?
        !           191:                        if(!document_root) {
        !           192:                                static char fake_document_root[MAX_STRING];
        !           193:                                strncpy(fake_document_root, filespec_to_process, MAX_STRING);
        !           194:                                rsplit(fake_document_root, '/');  rsplit(fake_document_root, '\\');// strip filename
        !           195:                                document_root=fake_document_root;
        !           196:                        }
        !           197:                        request_info.document_root=document_root;
        !           198:                        request_info.path_translated=filespec_to_process;
        !           199:                        request_info.method=lpECB->lpszMethod;
        !           200:                        request_info.query_string=lpECB->lpszQueryString;
        !           201:                        request_info.uri=lpECB->lpszPathInfo;//todo: check for ?zzz included?
        !           202:                        request_info.content_type=lpECB->lpszContentType;
        !           203:                        request_info.content_length=lpECB->cbTotalBytes;
        !           204:                        {// cookie
        !           205:                                char variable_buf[ISAPI_SERVER_VAR_BUF_SIZE];
        !           206:                                DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE-1;
        !           207:                                
        !           208:                                if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", variable_buf, &variable_len)) {
        !           209:                                        variable_buf[variable_len]=0;
        !           210:                                        request_info.cookie=variable_buf;
        !           211:                                } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
        !           212:                                        char *tmp_variable_buf=(char *)pool.malloc(variable_len+1);
        !           213:                                        
        !           214:                                        if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_variable_buf, &variable_len)) {
        !           215:                                                tmp_variable_buf[variable_len] = 0;
        !           216:                                                request_info.cookie=tmp_variable_buf;
        !           217:                                        } else {
        !           218:                                                request_info.cookie=0;
        !           219:                                        }
        !           220:                                }
        !           221:                        }
        !           222:                        
        !           223:                        // prepare to process request
        !           224:                        Request request(pool,
        !           225:                                request_info,
        !           226:                                String::UL_HTML_TYPO
        !           227:                                );
        !           228:                        
        !           229: 
        !           230:                        // some root-controlled location
        !           231:                        char *root_auto_path;
        !           232:                        // c:\windows
        !           233:                        root_auto_path=(char *)pool.malloc(MAX_STRING);
        !           234:                        GetWindowsDirectory(root_auto_path, MAX_STRING);
        !           235:                        strcat(root_auto_path, "/");
        !           236:                        
        !           237:                        // process the request
        !           238:                        request.core(
        !           239:                                root_auto_path, true, // /path/to/admin/auto.p
        !           240:                                0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
        !           241:                                header_only);
        !           242:                        
        !           243:                        // successful finish
        !           244:                        
        !           245:                        // must be last in PTRY{}PCATCH
        !           246:                } __except(exception_handler(&e, GetExceptionInformation())) {
        !           247:                        // converting C++ exception into Parser exception
        !           248: 
        !           249:                        if(_exception_code()==EXCEPTION_STACK_OVERFLOW) 
        !           250:                                PTHROW(0, 0,
        !           251:                                        0,
        !           252:                                        "Stack overflow");
        !           253:                        else if(_exception_code()==EXCEPTION_ACCESS_VIOLATION)
        !           254:                                PTHROW(0, 0,
        !           255:                                        0,
        !           256:                                        "Access violation at %p", 
        !           257:                                                e->ExceptionRecord->ExceptionAddress);
        !           258:                        else
        !           259:                                PTHROW(0, 0,
        !           260:                                        0,
        !           261:                                        "Exception %#X at %p", 
        !           262:                                                e->ExceptionRecord->ExceptionCode,
        !           263:                                                e->ExceptionRecord->ExceptionAddress);
        !           264:                }
        !           265:                // no further code here
        !           266:        } PCATCH(e) { // global problem 
        !           267:                const char *body=e.comment();
        !           268:                int content_length=strlen(body);
        !           269: 
        !           270:                // prepare header
        !           271:                (*service_funcs.add_header_attribute)(pool, "content-type", "text/plain");
        !           272:                char content_length_cstr[MAX_NUMBER];
        !           273:                snprintf(content_length_cstr, MAX_NUMBER, "%d", content_length);
        !           274:                (*service_funcs.add_header_attribute)(pool, "content-length", 
        !           275:                        content_length_cstr);
        !           276: 
        !           277:                // send header
        !           278:                (*service_funcs.send_header)(pool);
        !           279: 
        !           280:                // send body
        !           281:                if(!header_only)
        !           282:                        (*service_funcs.send_body)(pool, body, content_length);
        !           283: 
        !           284:                // unsuccessful finish
        !           285:                _endthread();
        !           286:        }
        !           287:        PEND_CATCH
        !           288:        
        !           289:        return HSE_STATUS_SUCCESS;
        !           290: }
        !           291: 
        !           292: 
        !           293: BOOL APIENTRY DllMain(HANDLE hModule, 
        !           294:                                          DWORD  ul_reason_for_call, 
        !           295:                                          LPVOID lpReserved
        !           296:                                          ) {
        !           297:     switch (ul_reason_for_call) {
        !           298:                case DLL_PROCESS_ATTACH:
        !           299:                        parser_init();
        !           300:                        break;
        !           301:                case DLL_THREAD_ATTACH:
        !           302:                        break;
        !           303:                case DLL_THREAD_DETACH:
        !           304:                        break;
        !           305:                case DLL_PROCESS_DETACH:
        !           306:                        break;
        !           307:     }
        !           308:     return TRUE;
        !           309: }

E-mail: