Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.44
1.29 paf 1: /** @file
2: Parser: IIS extension.
3:
4: Copyright (c) 2000,2001 ArtLebedev Group (http://www.artlebedev.com)
1.44 ! parser 5: Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
1.29 paf 6:
1.44 ! parser 7: $Id: $
1.29 paf 8: */
9:
1.1 paf 10: #ifndef _MSC_VER
1.10 paf 11: # error compile ISAPI module with MSVC [no urge for now to make it autoconf-ed (PAF)]
1.1 paf 12: #endif
1.43 parser 13:
14: #include "pa_config_includes.h"
1.1 paf 15:
16: #include <windows.h>
17: #include <process.h>
18:
19: #include <httpext.h>
20:
1.9 paf 21: #include "pa_sapi.h"
1.1 paf 22: #include "pa_globals.h"
23: #include "pa_request.h"
24: #include "pa_version.h"
1.13 paf 25: #include "pool_storage.h"
1.24 paf 26: #include "pa_socks.h"
1.1 paf 27:
28: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION")
1.44 ! parser 29:
! 30: // consts
! 31:
! 32: extern const char *main_RCSIds[];
! 33: extern const char *smtp_RCSIds[];
! 34: extern const char *gd_RCSIds[];
! 35: extern const char *classes_RCSIds[];
! 36: extern const char *types_RCSIds[];
! 37: extern const char *parser3isapi_RCSIds[];
! 38: const char **RCSIds[]={
! 39: main_RCSIds,
! 40: smtp_RCSIds,
! 41: gd_RCSIds,
! 42: classes_RCSIds,
! 43: types_RCSIds,
! 44: parser3isapi_RCSIds,
! 45: 0
! 46: };
1.1 paf 47:
1.18 paf 48: // SAPI
49:
1.38 parser 50: #ifndef DOXYGEN
51: /*
1.18 paf 52: ISAPI SAPI functions receive this context information.
1.38 parser 53: see Pool::set_context
1.18 paf 54: */
1.15 paf 55: struct SAPI_func_context {
1.3 paf 56: LPEXTENSION_CONTROL_BLOCK lpECB;
57: String *header;
58: DWORD http_response_code;
59: };
1.38 parser 60: #endif
1.3 paf 61:
1.26 paf 62: // goes to 'cs-uri-query' log file field. webmaster: switch it ON[default OFF].
63: void SAPI::log(Pool& pool, const char *fmt, ...) {
64: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
65:
66: va_list args;
67: va_start(args,fmt);
68: char buf[MAX_STRING];
69: const char *prefix="PARSER_ERROR:";
70: strcpy(buf, prefix);
71: DWORD size=vsnprintf(buf+strlen(prefix), MAX_STRING-strlen(prefix), fmt, args);
72:
73: ctx.lpECB->ServerSupportFunction(ctx.lpECB->ConnID,
74: HSE_APPEND_LOG_PARAMETER, buf, &size, 0);
75: }
76:
1.9 paf 77: const char *SAPI::get_env(Pool& pool, const char *name) {
1.15 paf 78: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
1.1 paf 79:
80: char *variable_buf=(char *)pool.malloc(MAX_STRING);
81: DWORD variable_len = MAX_STRING-1;
82:
1.3 paf 83: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
1.1 paf 84: variable_buf, &variable_len)) {
85: variable_buf[variable_len]=0;
86: return variable_buf;
1.7 paf 87: } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
88: variable_buf=(char *)pool.malloc(variable_len+1);
89:
90: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
91: variable_buf, &variable_len)) {
92: variable_buf[variable_len]=0;
93: return variable_buf;
94: }
1.1 paf 95: }
1.7 paf 96:
1.1 paf 97: return 0;
98: }
99:
1.26 paf 100: size_t SAPI::read_post(Pool& pool, char *buf, size_t max_bytes) {
1.15 paf 101: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
1.1 paf 102:
103: DWORD read_from_buf=0;
104: DWORD read_from_input=0;
105: DWORD total_read=0;
106:
1.3 paf 107: read_from_buf=min(ctx.lpECB->cbAvailable, max_bytes);
108: memcpy(buf, ctx.lpECB->lpbData, read_from_buf);
1.1 paf 109: total_read+=read_from_buf;
110:
111: if(read_from_buf<max_bytes &&
1.3 paf 112: read_from_buf<ctx.lpECB->cbTotalBytes) {
1.1 paf 113: DWORD cbRead=0, cbSize;
114:
1.3 paf 115: read_from_input=min(max_bytes-read_from_buf,
116: ctx.lpECB->cbTotalBytes-read_from_buf);
1.1 paf 117: while(cbRead < read_from_input) {
118: cbSize=read_from_input - cbRead;
1.3 paf 119: if(!ctx.lpECB->ReadClient(ctx.lpECB->ConnID,
120: buf+read_from_buf+cbRead, &cbSize) ||
1.1 paf 121: cbSize==0)
122: break;
123: cbRead+=cbSize;
124: }
125: total_read+=cbRead;
126: }
127: return total_read;
128: }
129:
1.9 paf 130: void SAPI::add_header_attribute(Pool& pool, const char *key, const char *value) {
1.15 paf 131: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
1.3 paf 132:
133: if(strcasecmp(key, "location")==0)
134: ctx.http_response_code=302;
135:
136: if(strcasecmp(key, "status")==0)
137: ctx.http_response_code=atoi(value);
138: else {
139: ctx.header->APPEND_CONST(key);
140: ctx.header->APPEND_CONST(": ");
141: ctx.header->APPEND_CONST(value);
1.30 paf 142: ctx.header->APPEND_CONST("\r\n");
1.3 paf 143: }
1.1 paf 144: }
145:
1.23 paf 146: /// @todo intelligent cache-control
1.9 paf 147: void SAPI::send_header(Pool& pool) {
1.15 paf 148: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
1.1 paf 149:
1.6 paf 150: ctx.header->APPEND_CONST(
1.30 paf 151: "expires: Fri, 23 Mar 2001 09:32:23 GMT\r\n"
152: "\r\n");
1.1 paf 153: HSE_SEND_HEADER_EX_INFO header_info;
154:
155: char status_buf[MAX_STATUS_LENGTH];
1.3 paf 156: switch(ctx.http_response_code) {
1.1 paf 157: case 200:
158: header_info.pszStatus="200 OK";
159: break;
160: case 302:
161: header_info.pszStatus="302 Moved Temporarily";
162: break;
1.8 paf 163: case 401:// useless untill parser auth mech
1.1 paf 164: header_info.pszStatus="401 Authorization Required";
1.8 paf 165: break;
1.1 paf 166: default:
1.3 paf 167: snprintf(status_buf, MAX_STATUS_LENGTH,
168: "%d Undescribed", ctx.http_response_code);
1.1 paf 169: header_info.pszStatus=status_buf;
170: break;
171: }
172: header_info.cchStatus=strlen(header_info.pszStatus);
1.3 paf 173: header_info.pszHeader=ctx.header->cstr();
174: header_info.cchHeader=ctx.header->size();
1.5 paf 175: header_info.fKeepConn=true;
1.1 paf 176:
1.3 paf 177: ctx.lpECB->dwHttpStatusCode=ctx.http_response_code;
1.1 paf 178:
1.3 paf 179: ctx.lpECB->ServerSupportFunction(ctx.lpECB->ConnID,
180: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
1.1 paf 181: }
182:
1.23 paf 183: void SAPI::send_body(Pool& pool, const void *buf, size_t size) {
1.15 paf 184: SAPI_func_context& ctx=*static_cast<SAPI_func_context *>(pool.context());
1.1 paf 185:
186: DWORD num_bytes=size;
1.3 paf 187: ctx.lpECB->WriteClient(ctx.lpECB->ConnID,
1.23 paf 188: const_cast<void *>(buf), &num_bytes, HSE_IO_SYNC);
1.1 paf 189: }
1.16 paf 190:
1.1 paf 191: //
192:
1.15 paf 193: static bool parser_init() {
1.1 paf 194: static bool globals_inited=false;
195: if(globals_inited)
1.15 paf 196: return true;
1.1 paf 197: globals_inited=true;
198:
1.13 paf 199: static Pool pool(0); // global pool
1.1 paf 200: PTRY {
1.27 paf 201: // init socks
202: init_socks(pool);
203:
1.32 paf 204: // init global classes
205: init_methoded_array(pool);
1.1 paf 206: // init global variables
1.9 paf 207: pa_globals_init(pool);
1.1 paf 208:
1.15 paf 209: // successful finish
210: return true;
1.1 paf 211: } PCATCH(e) { // global problem
1.15 paf 212: //const char *body=e.comment();
213:
214: // unsuccessful finish
215: return false;
1.1 paf 216: }
217: PEND_CATCH
218: }
219:
220: /// ISAPI //
221: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) {
222: pVer->dwExtensionVersion = HSE_VERSION;
1.36 parser 223: strncpy(pVer->lpszExtensionDesc, "Parser "PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN-1);
224: pVer->lpszExtensionDesc[HSE_MAX_EXT_DLL_NAME_LEN-1]=0;
1.15 paf 225: return parser_init();
1.1 paf 226: }
227:
1.6 paf 228: /**
229: ISAPI // main workhorse
230:
1.23 paf 231: @todo
1.10 paf 232: IIS: remove trailing default-document[index.html] from $request.uri.
233: to do that we need to consult metabase,
1.12 paf 234: wich is tested&works but seems slow runtime
235: and not could-be-quickly-implemented if prepared.
1.37 parser 236: @test
237: PARSER_VERSION from outside
1.6 paf 238: */
1.1 paf 239: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
1.13 paf 240: Pool_storage pool_storage;
1.15 paf 241: Pool pool(&pool_storage); // no allocations until assigned context [for reporting]
242: SAPI_func_context ctx={
243: lpECB,
1.18 paf 244: 0, // filling later: so that if there would be error pool would have ctx
1.39 parser 245: 200 // default http_response_code
1.15 paf 246: };
1.41 parser 247: _asm nop; // int 3;
1.15 paf 248: pool.set_context(&ctx);// no allocations before this line!
1.2 paf 249:
1.1 paf 250: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
251: PTRY { // global try
1.12 paf 252: ctx.header=new(pool) String(pool);
1.3 paf 253:
1.2 paf 254: // Request info
255: Request::Info request_info;
1.14 paf 256:
257: size_t path_translated_buf_size=strlen(lpECB->lpszPathTranslated)+1;
258: char *filespec_to_process=(char *)malloc(path_translated_buf_size);
259: memcpy(filespec_to_process, lpECB->lpszPathTranslated, path_translated_buf_size);
260: #ifdef WIN32
261: back_slashes_to_slashes(filespec_to_process);
262: #endif
263:
1.11 paf 264: if(const char *path_info=SAPI::get_env(pool, "PATH_INFO")) {
265: // IIS
266: size_t len=strlen(filespec_to_process)-strlen(path_info);
267: char *buf=(char *)pool.malloc(len+1);
1.36 parser 268: strncpy(buf, filespec_to_process, len); buf[len]=0;
1.11 paf 269: request_info.document_root=buf;
270: } else
1.6 paf 271: PTHROW(0, 0,
272: 0,
1.11 paf 273: "ISAPI: no PATH_INFO defined (in reinventing DOCUMENT_ROOT)");
1.6 paf 274:
1.11 paf 275: request_info.path_translated=filespec_to_process;
1.2 paf 276: request_info.method=lpECB->lpszMethod;
277: request_info.query_string=lpECB->lpszQueryString;
278: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
1.7 paf 279: char *reconstructed_uri=(char *)malloc(
280: strlen(lpECB->lpszPathInfo)+1/*'?'*/+
281: strlen(lpECB->lpszQueryString)+1/*0*/);
282: strcpy(reconstructed_uri, lpECB->lpszPathInfo);
1.2 paf 283: strcat(reconstructed_uri, "?");
1.7 paf 284: strcat(reconstructed_uri, lpECB->lpszQueryString);
1.2 paf 285: request_info.uri=reconstructed_uri;
286: } else
287: request_info.uri=lpECB->lpszPathInfo;
288:
289: request_info.content_type=lpECB->lpszContentType;
290: request_info.content_length=lpECB->cbTotalBytes;
1.9 paf 291: request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");
1.20 paf 292: request_info.user_agent=SAPI::get_env(pool, "HTTP_USER_AGENT");
293:
1.2 paf 294:
295: // prepare to process request
296: Request request(pool,
297: request_info,
1.33 paf 298: String::UL_USER_HTML
1.2 paf 299: );
1.15 paf 300:
1.2 paf 301: // some root-controlled location
1.7 paf 302: // c:\windows
1.42 parser 303: char root_config_path[MAX_STRING];
304: GetWindowsDirectory(root_config_path, MAX_STRING);
1.7 paf 305: // must be dynamic: rethrowing from request.core
306: // may return 'source' which can be inside of 'root auto.p@exeception'
1.42 parser 307: char *root_config_filespec=(char *)pool.malloc(MAX_STRING);
308: snprintf(root_config_filespec, MAX_STRING,
309: "%s/%s",
310: root_config_path, CONFIG_FILE_NAME);
1.4 paf 311:
1.2 paf 312: // process the request
313: request.core(
1.42 parser 314: root_config_filespec, false/*may be abcent*/, // /path/to/admin/auto.p
1.2 paf 315: 0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
316: header_only);
317: // successful finish
1.12 paf 318: } PCATCH(e) { // global problem
319: // don't allocate anything on pool here:
320: // possible pool' exception not catch-ed now
1.31 paf 321: // and there could be out-of-memory exception
1.1 paf 322: const char *body=e.comment();
1.16 paf 323: // log it
324: SAPI::log(pool, "exception in request exception handler: %s", body);
325:
326: //
1.1 paf 327: int content_length=strlen(body);
328:
1.12 paf 329: // prepare header // not using SAPI func wich allocates on pool
330: char header_buf[MAX_STRING];
331: int header_len=snprintf(header_buf, MAX_STRING,
1.30 paf 332: "content-type: text/plain\r\n"
333: "content-length: %lu\r\n"
334: "expires: Fri, 23 Mar 2001 09:32:23 GMT\r\n"
335: "\r\n",
1.12 paf 336: content_length);
337:
338: HSE_SEND_HEADER_EX_INFO header_info;
339: header_info.pszStatus="200 OK";
340: header_info.cchStatus=strlen(header_info.pszStatus);
341: header_info.pszHeader=header_buf;
342: header_info.cchHeader=header_len;
343: header_info.fKeepConn=true;
344:
1.1 paf 345: // send header
1.12 paf 346: lpECB->dwHttpStatusCode=200;
347: lpECB->ServerSupportFunction(lpECB->ConnID,
348: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
1.1 paf 349:
350: // send body
351: if(!header_only)
1.9 paf 352: SAPI::send_body(pool, body, content_length);
1.1 paf 353:
354: // unsuccessful finish
355: }
356: PEND_CATCH
357:
1.6 paf 358: return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
1.1 paf 359: }
E-mail: