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