Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.5
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:
19: struct Service_func_context {
20: LPEXTENSION_CONTROL_BLOCK lpECB;
21: String *header;
22: DWORD http_response_code;
23: };
24:
1.1 paf 25: static const char *get_env(Pool& pool, const char *name) {
1.3 paf 26: Service_func_context& ctx=*static_cast<Service_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;
35: }
36:
37: variable_buf=(char *)pool.malloc(variable_len+1);
38:
1.3 paf 39: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
1.1 paf 40: variable_buf, &variable_len)) {
41: variable_buf[variable_len]=0;
42: return variable_buf;
43: }
44:
45: return 0;
46: }
47:
48: static uint read_post(Pool& pool, char *buf, uint max_bytes) {
1.3 paf 49: Service_func_context& ctx=*static_cast<Service_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:
78: static void add_header_attribute(Pool& pool, const char *key, const char *value) {
1.3 paf 79: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
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.1 paf 95: static void send_header(Pool& pool) {
1.3 paf 96: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
1.1 paf 97:
1.3 paf 98: ctx.header->APPEND_CONST("Cache-Control: no-cache\n");
99: ctx.header->APPEND_CONST("\n");
1.1 paf 100: HSE_SEND_HEADER_EX_INFO header_info;
101:
102: char status_buf[MAX_STATUS_LENGTH];
1.3 paf 103: switch(ctx.http_response_code) {
1.1 paf 104: case 200:
105: header_info.pszStatus="200 OK";
106: break;
107: case 302:
108: header_info.pszStatus="302 Moved Temporarily";
109: break;
1.3 paf 110: /*case 401:
1.1 paf 111: header_info.pszStatus="401 Authorization Required";
1.3 paf 112: break;*/
1.1 paf 113: default:
1.3 paf 114: snprintf(status_buf, MAX_STATUS_LENGTH,
115: "%d Undescribed", ctx.http_response_code);
1.1 paf 116: header_info.pszStatus=status_buf;
117: break;
118: }
119: header_info.cchStatus=strlen(header_info.pszStatus);
1.3 paf 120: header_info.pszHeader=ctx.header->cstr();
121: header_info.cchHeader=ctx.header->size();
1.5 ! paf 122: header_info.fKeepConn=true;
1.1 paf 123:
1.3 paf 124: ctx.lpECB->dwHttpStatusCode=ctx.http_response_code;
1.1 paf 125:
1.3 paf 126: ctx.lpECB->ServerSupportFunction(ctx.lpECB->ConnID,
127: HSE_REQ_SEND_RESPONSE_HEADER_EX, &header_info, NULL, NULL);
1.1 paf 128: }
129:
130: static void send_body(Pool& pool, const char *buf, size_t size) {
1.3 paf 131: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
1.1 paf 132:
133: DWORD num_bytes=size;
1.3 paf 134: ctx.lpECB->WriteClient(ctx.lpECB->ConnID,
135: const_cast<char *>(buf), &num_bytes, HSE_IO_SYNC);
1.1 paf 136: }
137: //@}
138:
139: /// Service funcs
140: Service_funcs service_funcs={
141: get_env,
142: read_post,
143: add_header_attribute,
144: send_header,
145: send_body
146: };
147:
148: //
149:
150: static void parser_init() {
151: static bool globals_inited=false;
152: if(globals_inited)
153: return;
154: globals_inited=true;
155:
156: static Pool pool; // global pool
157: PTRY {
158: // init global variables
159: globals_init(pool);
160:
161: //...
162: } PCATCH(e) { // global problem
163: const char *body=e.comment();
164: // TODO: somehow report that error
165: }
166: PEND_CATCH
167: }
168:
169: /// ISAPI //
170: BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) {
171: pVer->dwExtensionVersion = HSE_VERSION;
172: strncpy(pVer->lpszExtensionDesc, "Parser " PARSER_VERSION, HSE_MAX_EXT_DLL_NAME_LEN);
173: return TRUE;
174: }
175:
176: /// ISAPI // main workhorse
177: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
178: Pool pool;
179: // TODO r->no_cache=1;
1.2 paf 180:
1.1 paf 181: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
182: PTRY { // global try
183: // must be first in PTRY{}PCATCH
1.2 paf 184:
1.3 paf 185: Service_func_context ctx={
186: lpECB,
187: new(pool) String(pool),
188: 200
189: };
190: pool.set_context(&ctx);
191:
1.2 paf 192: const char *filespec_to_process=lpECB->lpszPathTranslated;
193:
194: // Request info
195: Request::Info request_info;
196:
197: const char *document_root=0; // todo: get from somewhere?
198: if(!document_root) {
199: static char fake_document_root[MAX_STRING];
200: strncpy(fake_document_root, filespec_to_process, MAX_STRING);
201: rsplit(fake_document_root, '/'); rsplit(fake_document_root, '\\');// strip filename
202: document_root=fake_document_root;
203: }
204: request_info.document_root=document_root;
205: request_info.path_translated=filespec_to_process;
206: request_info.method=lpECB->lpszMethod;
207: request_info.query_string=lpECB->lpszQueryString;
208: char reconstructed_uri[MAX_STRING];
209: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
210: strncpy(reconstructed_uri, lpECB->lpszPathInfo,
211: MAX_STRING-1/*'?'*/-strlen(lpECB->lpszQueryString));
212: strcat(reconstructed_uri, "?");
213: strcat(reconstructed_uri, lpECB->lpszPathInfo);
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;
220: // cookie
1.3 paf 221: request_info.cookie=0;
1.2 paf 222: char cookie_buf[MAX_STRING];
223: {
224: DWORD cookie_len = MAX_STRING-1;
225:
226: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", cookie_buf, &cookie_len)) {
227: cookie_buf[cookie_len]=0;
228: request_info.cookie=cookie_buf;
229: } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
230: char *tmp_cookie_buf=(char *)pool.malloc(cookie_len+1);
1.1 paf 231:
1.2 paf 232: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_cookie_buf, &cookie_len)) {
233: tmp_cookie_buf[cookie_len]=0;
234: request_info.cookie=tmp_cookie_buf;
1.1 paf 235: }
236: }
237: }
1.2 paf 238:
239: // prepare to process request
240: Request request(pool,
241: request_info,
242: String::UL_HTML_TYPO
243: );
244:
245: // some root-controlled location
246: char *root_auto_path;
247: // c:\windows
248: root_auto_path=(char *)pool.malloc(MAX_STRING);
249: GetWindowsDirectory(root_auto_path, MAX_STRING);
1.4 paf 250:
1.2 paf 251: // process the request
252: request.core(
253: root_auto_path, false/*may be abcent*/, // /path/to/admin/auto.p
254: 0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
255: header_only);
256:
257: // successful finish
1.1 paf 258: } PCATCH(e) { // global problem
259: const char *body=e.comment();
260: int content_length=strlen(body);
261:
262: // prepare header
263: (*service_funcs.add_header_attribute)(pool, "content-type", "text/plain");
264: char content_length_cstr[MAX_NUMBER];
265: snprintf(content_length_cstr, MAX_NUMBER, "%d", content_length);
266: (*service_funcs.add_header_attribute)(pool, "content-length",
267: content_length_cstr);
268:
269: // send header
270: (*service_funcs.send_header)(pool);
271:
272: // send body
273: if(!header_only)
274: (*service_funcs.send_body)(pool, body, content_length);
275:
276: // unsuccessful finish
277: _endthread();
278: }
279: PEND_CATCH
280:
281: return HSE_STATUS_SUCCESS;
282: }
283:
284:
285: BOOL APIENTRY DllMain(HANDLE hModule,
286: DWORD ul_reason_for_call,
287: LPVOID lpReserved
288: ) {
289: switch (ul_reason_for_call) {
290: case DLL_PROCESS_ATTACH:
291: parser_init();
292: break;
293: case DLL_THREAD_ATTACH:
294: break;
295: case DLL_THREAD_DETACH:
296: break;
297: case DLL_PROCESS_DETACH:
298: break;
299: }
300: return TRUE;
301: }
E-mail: