Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.8
1.1 paf 1: #ifndef _MSC_VER
2: # error compile ISAPI module with MSVC
3: #endif
4:
5: #include <windows.h>
6: #include <process.h>
7:
8: #include <httpext.h>
9:
10: #include "pa_globals.h"
11: #include "pa_request.h"
12: #include "pa_version.h"
13:
14: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION")
15:
16: //@{
17: /// service func decl
1.3 paf 18:
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.8 ! paf 25: static const char *sapi_get_env(Pool& pool, const char *name) {
! 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.8 ! paf 48: static uint sapi_read_post(Pool& pool, char *buf, uint max_bytes) {
! 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.8 ! paf 78: static void sapi_add_header_attribute(Pool& pool, const char *key, const char *value) {
! 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.8 ! paf 95: static void sapi_send_header(Pool& pool) {
! 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.8 ! paf 131: static void sapi_send_body(Pool& pool, const char *buf, size_t size) {
! 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:
1.8 ! paf 140: /// SAPI
! 141: SAPI sapi={
! 142: sapi_get_env,
! 143: sapi_read_post,
! 144: sapi_add_header_attribute,
! 145: sapi_send_header,
! 146: sapi_send_body
1.1 paf 147: };
148:
149: //
150:
151: static void parser_init() {
152: static bool globals_inited=false;
153: if(globals_inited)
154: return;
155: globals_inited=true;
156:
157: static Pool pool; // global pool
158: PTRY {
159: // init global variables
160: globals_init(pool);
161:
162: //...
163: } PCATCH(e) { // global problem
164: const char *body=e.comment();
165: // TODO: somehow report that error
166: }
167: PEND_CATCH
168: }
169:
170: /// ISAPI //
171: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) {
172: pVer->dwExtensionVersion = HSE_VERSION;
173: strncpy(pVer->lpszExtensionDesc, "Parser " PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN);
174: return TRUE;
175: }
176:
1.6 paf 177: /**
178: ISAPI // main workhorse
179:
180: @todo
181: think of a better way than @c APPL_PHYSICAL_PATH
182: of obtaining the @c DOCUMENT_ROOT
183: because this only gets "the place where last IIS Application was set"
184: and if someone would redefine Application settings below the /
185: all ^table:load[/test] would open not /test but /below/test
186: */
1.1 paf 187: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
188: Pool pool;
1.2 paf 189:
1.1 paf 190: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
191: PTRY { // global try
1.8 ! paf 192: sapi_func_context ctx={
1.3 paf 193: lpECB,
194: new(pool) String(pool),
195: 200
196: };
197: pool.set_context(&ctx);
198:
1.2 paf 199: // Request info
200: Request::Info request_info;
201:
1.8 ! paf 202: if(!(request_info.document_root=sapi_get_env(pool, "APPL_PHYSICAL_PATH")))
1.6 paf 203: PTHROW(0, 0,
204: 0,
1.7 paf 205: "can not get server variable APPL_PHYSICAL_PATH (error #%lu)",
1.6 paf 206: GetLastError()); // never
207:
208: request_info.path_translated=lpECB->lpszPathTranslated;
1.2 paf 209: request_info.method=lpECB->lpszMethod;
210: request_info.query_string=lpECB->lpszQueryString;
211: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
1.7 paf 212: char *reconstructed_uri=(char *)malloc(
213: strlen(lpECB->lpszPathInfo)+1/*'?'*/+
214: strlen(lpECB->lpszQueryString)+1/*0*/);
215: strcpy(reconstructed_uri, lpECB->lpszPathInfo);
1.2 paf 216: strcat(reconstructed_uri, "?");
1.7 paf 217: strcat(reconstructed_uri, lpECB->lpszQueryString);
1.2 paf 218: request_info.uri=reconstructed_uri;
219: } else
220: request_info.uri=lpECB->lpszPathInfo;
221:
222: request_info.content_type=lpECB->lpszContentType;
223: request_info.content_length=lpECB->cbTotalBytes;
1.8 ! paf 224: request_info.cookie=sapi_get_env(pool, "HTTP_COOKIE");
1.2 paf 225:
226: // prepare to process request
227: Request request(pool,
228: request_info,
229: String::UL_HTML_TYPO
230: );
231:
232: // some root-controlled location
1.7 paf 233: // c:\windows
234: // must be dynamic: rethrowing from request.core
235: // may return 'source' which can be inside of 'root auto.p@exeception'
236: char *root_auto_path=(char *)pool.malloc(MAX_STRING);
1.2 paf 237: GetWindowsDirectory(root_auto_path, MAX_STRING);
1.4 paf 238:
1.2 paf 239: // process the request
240: request.core(
241: root_auto_path, false/*may be abcent*/, // /path/to/admin/auto.p
242: 0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
243: header_only);
244:
245: // successful finish
1.1 paf 246: } PCATCH(e) { // global problem
247: const char *body=e.comment();
248: int content_length=strlen(body);
249:
250: // prepare header
1.8 ! paf 251: sapi_add_header_attribute(pool, "content-type", "text/plain");
1.1 paf 252: char content_length_cstr[MAX_NUMBER];
1.6 paf 253: snprintf(content_length_cstr, MAX_NUMBER, "%lu", content_length);
1.8 ! paf 254: sapi_add_header_attribute(pool, "content-length", content_length_cstr);
1.1 paf 255:
256: // send header
1.8 ! paf 257: sapi_send_header(pool);
1.1 paf 258:
259: // send body
260: if(!header_only)
1.8 ! paf 261: sapi_send_body(pool, body, content_length);
1.1 paf 262:
263: // unsuccessful finish
264: _endthread();
265: }
266: PEND_CATCH
267:
1.6 paf 268: return HSE_STATUS_SUCCESS_AND_KEEP_CONN;
1.1 paf 269: }
270:
271:
272: BOOL APIENTRY DllMain(HANDLE hModule,
273: DWORD ul_reason_for_call,
274: LPVOID lpReserved
275: ) {
276: switch (ul_reason_for_call) {
277: case DLL_PROCESS_ATTACH:
278: parser_init();
279: break;
280: case DLL_THREAD_ATTACH:
281: break;
282: case DLL_THREAD_DETACH:
283: break;
284: case DLL_PROCESS_DETACH:
285: break;
286: }
287: return TRUE;
288: }
E-mail: