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