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