Annotation of parser3/src/targets/isapi/parser3isapi.C, revision 1.3
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: #include <httpfilt.h>
10: #include <httpext.h>
11:
12: #include "pa_globals.h"
13: #include "pa_request.h"
14: #include "pa_version.h"
15:
16: #define MAX_STATUS_LENGTH sizeof("xxxx LONGEST STATUS DESCRIPTION")
17:
18: //@{
19: /// service func decl
1.3 ! paf 20:
! 21: struct Service_func_context {
! 22: LPEXTENSION_CONTROL_BLOCK lpECB;
! 23: String *header;
! 24: DWORD http_response_code;
! 25: };
! 26:
1.1 paf 27: static const char *get_env(Pool& pool, const char *name) {
1.3 ! paf 28: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
1.1 paf 29:
30: char *variable_buf=(char *)pool.malloc(MAX_STRING);
31: DWORD variable_len = MAX_STRING-1;
32:
1.3 ! paf 33: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
1.1 paf 34: variable_buf, &variable_len)) {
35: variable_buf[variable_len]=0;
36: return variable_buf;
37: }
38:
39: variable_buf=(char *)pool.malloc(variable_len+1);
40:
1.3 ! paf 41: if(ctx.lpECB->GetServerVariable(ctx.lpECB->ConnID, const_cast<char *>(name),
1.1 paf 42: variable_buf, &variable_len)) {
43: variable_buf[variable_len]=0;
44: return variable_buf;
45: }
46:
47: return 0;
48: }
49:
50: static uint read_post(Pool& pool, char *buf, uint max_bytes) {
1.3 ! paf 51: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
1.1 paf 52:
53: DWORD read_from_buf=0;
54: DWORD read_from_input=0;
55: DWORD total_read=0;
56:
1.3 ! paf 57: read_from_buf=min(ctx.lpECB->cbAvailable, max_bytes);
! 58: memcpy(buf, ctx.lpECB->lpbData, read_from_buf);
1.1 paf 59: total_read+=read_from_buf;
60:
61: if(read_from_buf<max_bytes &&
1.3 ! paf 62: read_from_buf<ctx.lpECB->cbTotalBytes) {
1.1 paf 63: DWORD cbRead=0, cbSize;
64:
1.3 ! paf 65: read_from_input=min(max_bytes-read_from_buf,
! 66: ctx.lpECB->cbTotalBytes-read_from_buf);
1.1 paf 67: while(cbRead < read_from_input) {
68: cbSize=read_from_input - cbRead;
1.3 ! paf 69: if(!ctx.lpECB->ReadClient(ctx.lpECB->ConnID,
! 70: buf+read_from_buf+cbRead, &cbSize) ||
1.1 paf 71: cbSize==0)
72: break;
73: cbRead+=cbSize;
74: }
75: total_read+=cbRead;
76: }
77: return total_read;
78: }
79:
80: static void add_header_attribute(Pool& pool, const char *key, const char *value) {
1.3 ! paf 81: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
! 82:
! 83: if(strcasecmp(key, "location")==0)
! 84: ctx.http_response_code=302;
! 85:
! 86: if(strcasecmp(key, "status")==0)
! 87: ctx.http_response_code=atoi(value);
! 88: else {
! 89: ctx.header->APPEND_CONST(key);
! 90: ctx.header->APPEND_CONST(": ");
! 91: ctx.header->APPEND_CONST(value);
! 92: ctx.header->APPEND_CONST("\n");
! 93: }
1.1 paf 94: }
95:
1.3 ! paf 96: /// @todo intelligent cache-control
1.1 paf 97: static void send_header(Pool& pool) {
1.3 ! paf 98: Service_func_context& ctx=*static_cast<Service_func_context *>(pool.context());
1.1 paf 99:
1.3 ! paf 100: ctx.header->APPEND_CONST("Cache-Control: no-cache\n");
! 101: ctx.header->APPEND_CONST("\n");
1.1 paf 102: HSE_SEND_HEADER_EX_INFO header_info;
103:
104: char status_buf[MAX_STATUS_LENGTH];
1.3 ! paf 105: switch(ctx.http_response_code) {
1.1 paf 106: case 200:
107: header_info.pszStatus="200 OK";
108: break;
109: case 302:
110: header_info.pszStatus="302 Moved Temporarily";
111: break;
1.3 ! paf 112: /*case 401:
1.1 paf 113: header_info.pszStatus="401 Authorization Required";
1.3 ! paf 114: break;*/
1.1 paf 115: default:
1.3 ! paf 116: snprintf(status_buf, MAX_STATUS_LENGTH,
! 117: "%d Undescribed", ctx.http_response_code);
1.1 paf 118: header_info.pszStatus=status_buf;
119: break;
120: }
121: header_info.cchStatus=strlen(header_info.pszStatus);
1.3 ! paf 122: header_info.pszHeader=ctx.header->cstr();
! 123: header_info.cchHeader=ctx.header->size();
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:
131: static void send_body(Pool& pool, const char *buf, size_t size) {
1.3 ! paf 132: Service_func_context& ctx=*static_cast<Service_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: /// Service funcs
141: Service_funcs service_funcs={
142: get_env,
143: read_post,
144: add_header_attribute,
145: send_header,
146: send_body
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:
177: /// ISAPI // main workhorse
178: DWORD WINAPI HttpExtensionProc(LPEXTENSION_CONTROL_BLOCK lpECB) {
179: Pool pool;
180: // TODO r->no_cache=1;
1.2 paf 181:
1.1 paf 182: bool header_only=strcasecmp(lpECB->lpszMethod, "HEAD")==0;
183: PTRY { // global try
184: // must be first in PTRY{}PCATCH
1.2 paf 185:
1.3 ! paf 186: Service_func_context ctx={
! 187: lpECB,
! 188: new(pool) String(pool),
! 189: 200
! 190: };
! 191: pool.set_context(&ctx);
! 192:
1.2 paf 193: const char *filespec_to_process=lpECB->lpszPathTranslated;
194:
195: // Request info
196: Request::Info request_info;
197:
198: const char *document_root=0; // todo: get from somewhere?
199: if(!document_root) {
200: static char fake_document_root[MAX_STRING];
201: strncpy(fake_document_root, filespec_to_process, MAX_STRING);
202: rsplit(fake_document_root, '/'); rsplit(fake_document_root, '\\');// strip filename
203: document_root=fake_document_root;
204: }
205: request_info.document_root=document_root;
206: request_info.path_translated=filespec_to_process;
207: request_info.method=lpECB->lpszMethod;
208: request_info.query_string=lpECB->lpszQueryString;
209: char reconstructed_uri[MAX_STRING];
210: if(lpECB->lpszQueryString && *lpECB->lpszQueryString) {
211: strncpy(reconstructed_uri, lpECB->lpszPathInfo,
212: MAX_STRING-1/*'?'*/-strlen(lpECB->lpszQueryString));
213: strcat(reconstructed_uri, "?");
214: strcat(reconstructed_uri, lpECB->lpszPathInfo);
215: request_info.uri=reconstructed_uri;
216: } else
217: request_info.uri=lpECB->lpszPathInfo;
218:
219: request_info.content_type=lpECB->lpszContentType;
220: request_info.content_length=lpECB->cbTotalBytes;
221: // cookie
1.3 ! paf 222: request_info.cookie=0;
1.2 paf 223: char cookie_buf[MAX_STRING];
224: {
225: DWORD cookie_len = MAX_STRING-1;
226:
227: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", cookie_buf, &cookie_len)) {
228: cookie_buf[cookie_len]=0;
229: request_info.cookie=cookie_buf;
230: } else if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
231: char *tmp_cookie_buf=(char *)pool.malloc(cookie_len+1);
1.1 paf 232:
1.2 paf 233: if (lpECB->GetServerVariable(lpECB->ConnID, "HTTP_COOKIE", tmp_cookie_buf, &cookie_len)) {
234: tmp_cookie_buf[cookie_len]=0;
235: request_info.cookie=tmp_cookie_buf;
1.1 paf 236: }
237: }
238: }
1.2 paf 239:
240: // prepare to process request
241: Request request(pool,
242: request_info,
243: String::UL_HTML_TYPO
244: );
245:
246: // some root-controlled location
247: char *root_auto_path;
248: // c:\windows
249: root_auto_path=(char *)pool.malloc(MAX_STRING);
250: GetWindowsDirectory(root_auto_path, MAX_STRING);
251: /*
252: char *fuck_it="fff";
253: DWORD num_bytes=strlen(fuck_it);;
254: lpECB->WriteClient(lpECB->ConnID, fuck_it, &num_bytes, HSE_IO_SYNC);
255: return HSE_STATUS_SUCCESS;
256: */
257: // process the request
258: request.core(
259: root_auto_path, false/*may be abcent*/, // /path/to/admin/auto.p
260: 0/*parser_site_auto_path*/, false, // /path/to/site/auto.p
261: header_only);
262:
263: // successful finish
1.1 paf 264: } PCATCH(e) { // global problem
265: const char *body=e.comment();
266: int content_length=strlen(body);
267:
268: // prepare header
269: (*service_funcs.add_header_attribute)(pool, "content-type", "text/plain");
270: char content_length_cstr[MAX_NUMBER];
271: snprintf(content_length_cstr, MAX_NUMBER, "%d", content_length);
272: (*service_funcs.add_header_attribute)(pool, "content-length",
273: content_length_cstr);
274:
275: // send header
276: (*service_funcs.send_header)(pool);
277:
278: // send body
279: if(!header_only)
280: (*service_funcs.send_body)(pool, body, content_length);
281:
282: // unsuccessful finish
283: _endthread();
284: }
285: PEND_CATCH
286:
287: return HSE_STATUS_SUCCESS;
288: }
289:
290:
291: BOOL APIENTRY DllMain(HANDLE hModule,
292: DWORD ul_reason_for_call,
293: LPVOID lpReserved
294: ) {
295: switch (ul_reason_for_call) {
296: case DLL_PROCESS_ATTACH:
297: parser_init();
298: break;
299: case DLL_THREAD_ATTACH:
300: break;
301: case DLL_THREAD_DETACH:
302: break;
303: case DLL_PROCESS_DETACH:
304: break;
305: }
306: return TRUE;
307: }
E-mail: