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