Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.10
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.8 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
172: think of a better way than @c APPL_PHYSICAL_PATH
173: of obtaining the @c DOCUMENT_ROOT
174: because this only gets "the place where last IIS Application was set"
175: and if someone would redefine Application settings below the /
176: all ^table:load[/test] would open not /test but /below/test
1.10 ! paf 177:
! 178: @todo
! 179: IIS: remove trailing default-document[index.html] from $request.uri.
! 180: to do that we need to consult metabase,
! 181: wich is tested but seems slow.
1.6 paf 182: */
1.1 paf 183: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
184: Pool pool;
1.2 paf 185:
1.1 paf 186: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
187: PTRY { // global try
1.8 paf 188: sapi_func_context ctx={
1.3 paf 189: lpECB,
190: new(pool) String(pool),
191: 200
192: };
193: pool.set_context(&ctx);
194:
1.2 paf 195: // Request info
196: Request::Info request_info;
197:
1.9 paf 198: if(!(request_info.document_root=SAPI::get_env(pool, "APPL_PHYSICAL_PATH")))
1.6 paf 199: PTHROW(0, 0,
200: 0,
1.7 paf 201: "can not get server variable APPL_PHYSICAL_PATH (error #%lu)",
1.6 paf 202: GetLastError()); // never
203:
204: request_info.path_translated=lpECB->lpszPathTranslated;
1.2 paf 205: request_info.method=lpECB->lpszMethod;
206: request_info.query_string=lpECB->lpszQueryString;
207: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
1.7 paf 208: char *reconstructed_uri=(char *)malloc(
209: strlen(lpECB->lpszPathInfo)+1/*'?'*/+
210: strlen(lpECB->lpszQueryString)+1/*0*/);
211: strcpy(reconstructed_uri, lpECB->lpszPathInfo);
1.2 paf 212: strcat(reconstructed_uri, "?");
1.7 paf 213: strcat(reconstructed_uri, lpECB->lpszQueryString);
1.2 paf 214: request_info.uri=reconstructed_uri;
215: } else
216: request_info.uri=lpECB->lpszPathInfo;
217:
218: request_info.content_type=lpECB->lpszContentType;
219: request_info.content_length=lpECB->cbTotalBytes;
1.9 paf 220: request_info.cookie=SAPI::get_env(pool, "HTTP_COOKIE");
1.2 paf 221:
222: // prepare to process request
223: Request request(pool,
224: request_info,
225: String::UL_HTML_TYPO
226: );
227:
228: // some root-controlled location
1.7 paf 229: // c:\windows
230: // must be dynamic: rethrowing from request.core
231: // may return 'source' which can be inside of 'root auto.p@exeception'
232: char *root_auto_path=(char *)pool.malloc(MAX_STRING);
1.2 paf 233: GetWindowsDirectory(root_auto_path, MAX_STRING);
1.4 paf 234:
1.2 paf 235: // process the request
236: request.core(
237: root_auto_path, false/*may be abcent*/, // /path/to/admin/auto.p
238: 0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
239: header_only);
240:
241: // successful finish
1.1 paf 242: } PCATCH(e) { // global problem
243: const char *body=e.comment();
244: int content_length=strlen(body);
245:
246: // prepare header
1.9 paf 247: SAPI::add_header_attribute(pool, "content-type", "text/plain");
1.1 paf 248: char content_length_cstr[MAX_NUMBER];
1.6 paf 249: snprintf(content_length_cstr, MAX_NUMBER, "%lu", content_length);
1.9 paf 250: SAPI::add_header_attribute(pool, "content-length", content_length_cstr);
1.1 paf 251:
252: // send header
1.9 paf 253: SAPI::send_header(pool);
1.1 paf 254:
255: // send body
256: if(!header_only)
1.9 paf 257: SAPI::send_body(pool, body, content_length);
1.1 paf 258:
259: // unsuccessful finish
260: _endthread();
261: }
262: PEND_CATCH
263:
1.6 paf 264: return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
1.1 paf 265: }
266:
267:
268: BOOL APIENTRY DllMain(HANDLE hModule,
269: DWORD ul_reason_for_call,
270: LPVOID lpReserved
271: ) {
272: switch (ul_reason_for_call) {
273: case DLL_PROCESS_ATTACH:
274: parser_init();
275: break;
276: case DLL_THREAD_ATTACH:
277: break;
278: case DLL_THREAD_DETACH:
279: break;
280: case DLL_PROCESS_DETACH:
281: break;
282: }
283: return TRUE;
284: }
E-mail: