Annotation of parser3/src/main/pa_request.C, revision 1.180
1.54 paf 1: /** @file
1.55 paf 2: Parser: request class main part. @see compile.C and execute.C.
3:
1.9 paf 4: Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
1.176 paf 5: Author: Alexander Petrosyan <paf@design.ru> (http://paf.design.ru)
1.55 paf 6:
1.180 ! paf 7: $Id: pa_request.C,v 1.179 2001/11/08 11:52:34 paf Exp $
1.1 paf 8: */
9:
1.70 paf 10: #include "pa_config_includes.h"
1.166 parser 11:
12: extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c
13:
1.69 paf 14: #include "pa_sapi.h"
1.53 paf 15: #include "pa_common.h"
1.1 paf 16: #include "pa_request.h"
1.3 paf 17: #include "pa_wwrapper.h"
18: #include "pa_vclass.h"
1.31 paf 19: #include "pa_globals.h"
1.30 paf 20: #include "pa_vint.h"
1.112 paf 21: #include "pa_vmethod_frame.h"
1.32 paf 22: #include "pa_types.h"
1.78 paf 23: #include "pa_vtable.h"
1.90 paf 24: #include "pa_vfile.h"
1.147 parser 25: #include "pa_dictionary.h"
1.164 parser 26: #include "pa_charset_manager.h"
1.178 paf 27: #include "pa_charset_connection.h"
1.159 parser 28:
1.180 ! paf 29: // defines
! 30:
! 31: #define ORIGIN_FILE_LINE_FORMAT "%.300s(%d)"
! 32:
1.82 paf 33: /// content type of exception response, when no @MAIN:exception handler defined
34: const char *UNHANDLED_EXCEPTION_CONTENT_TYPE="text/plain";
35:
36: /// content type of response when no $MAIN:defaults.content-type defined
37: const char *DEFAULT_CONTENT_TYPE="text/html";
1.144 parser 38: const char *ORIGINS_CONTENT_TYPE="text/plain";
1.82 paf 39:
1.123 paf 40: Methoded *MOP_create(Pool&);
41:
1.160 parser 42: static void load_charset(const Hash::Key& akey, Hash::Val *avalue,
1.158 parser 43: void *info) {
1.164 parser 44: Value& value=*static_cast<Value *>(avalue);
1.158 parser 45: Hash& CTYPE=*static_cast<Hash *>(info);
46:
1.178 paf 47: Charset_connection& connection=
48: charset_manager->get_connection(akey, value.as_string());
1.158 parser 49:
1.159 parser 50: // charset->pcre_tables
1.164 parser 51: CTYPE.put(akey, connection.pcre_tables());
1.157 parser 52: }
53:
54: //
55: Request::Request(Pool& apool,
56: Info& ainfo,
1.179 paf 57: String::Untaint_lang adefault_lang,
58: bool status_allowed) : Pooled(apool),
1.157 parser 59: stack(apool),
60: OP(*MOP_create(apool)),
61: env(apool),
1.175 paf 62: status(apool),
1.157 parser 63: form(apool),
64: math(apool),
65: request(apool, *this),
66: response(apool),
67: cookie(apool),
68: fclasses(apool),
1.158 parser 69: CTYPE(apool),
1.157 parser 70: fdefault_lang(adefault_lang), flang(adefault_lang),
71: info(ainfo),
72: post_data(0), post_size(0),
73: used_files(apool),
74: default_content_type(0),
75: mime_types(0),
76: main_class(0),
77: connection(0),
78: classes_conf(apool),
1.171 parser 79: anti_endless_execute_recoursion(0),
80: trace(apool)
1.157 parser 81: {
1.178 paf 82: // maybe expire old caches
83: cache_managers->maybe_expire();
84:
1.157 parser 85: /// directly used
86: // operators
87: OP.register_directly_used(*this);
88: // classes:
89: // table, file, random, mail, image, ...
90: methoded_array->register_directly_used(*this);
91:
92: /// methodless
93: // env class
94: classes().put(*NEW String(pool(), ENV_CLASS_NAME), &env);
1.175 paf 95: // status class
1.179 paf 96: if(status_allowed)
97: classes().put(*NEW String(pool(), STATUS_CLASS_NAME), &status);
1.157 parser 98: // request class
99: classes().put(*NEW String(pool(), REQUEST_CLASS_NAME), &request);
100: // cookie class
101: classes().put(*NEW String(pool(), COOKIE_CLASS_NAME), &cookie);
102:
103: /// methoded
104: // response class
105: classes().put(response.get_class()->name(), &response);
106:
107: /// bases used
108: // form class
109: classes().put(form.get_class()->base()->name(), &form);
110: // math class
111: classes().put(math.get_class()->base()->name(), &math);
1.117 paf 112: }
1.150 parser 113:
1.64 paf 114: /**
115: load MAIN class, execute @main.
116: MAIN class consists of all the auto.p files we'd manage to find
117: plus
118: the file user requested us to process
119: all located classes become children of one another,
120: composing class we name 'MAIN'
1.180 ! paf 121:
! 122: @test log stack trace
! 123:
1.64 paf 124: */
1.153 parser 125: void Request::core(
126: const char *root_config_filespec, bool root_config_fail_on_read_problem,
127: const char *site_config_filespec, bool site_config_fail_on_read_problem,
1.62 paf 128: bool header_only) {
1.169 parser 129: try {
1.29 paf 130: char *auto_filespec=(char *)malloc(MAX_STRING);
131:
1.153 parser 132: // loading root config
133: if(root_config_filespec) {
1.77 paf 134: String& filespec=*NEW String(pool());
1.153 parser 135: filespec.APPEND_CLEAN(root_config_filespec, 0, "root_config", 0);
1.29 paf 136: main_class=use_file(
1.148 parser 137: filespec,
1.153 parser 138: true/*ignore class_path*/, root_config_fail_on_read_problem,
1.37 paf 139: main_class_name, main_class);
1.29 paf 140: }
141:
1.164 parser 142: if(main_class) {
143: /* $MAIN:CHARSETS[
144: $.charsetname1[/full/path/to/charset/file.cfg]
145: ...
146: ]
147: */
148: if(Value *vcharsets=main_class->get_element(*charsets_name)) {
1.172 parser 149: if(Hash *charsets=vcharsets->get_hash(0))
1.164 parser 150: charsets->for_each(load_charset, &CTYPE);
151: else
1.169 parser 152: throw Exception(0, 0,
1.164 parser 153: &vcharsets->name(),
154: "must be hash");
155: }
156: }
157:
1.124 paf 158: // configure root options
1.72 paf 159: // until someone with less privileges have overriden them
1.129 paf 160: OP.configure_admin(*this);
1.124 paf 161: methoded_array->configure_admin(*this);
1.72 paf 162:
1.153 parser 163: // loading site config
164: if(site_config_filespec) {
1.77 paf 165: String& filespec=*NEW String(pool());
1.153 parser 166: filespec.APPEND_CLEAN(site_config_filespec, 0, "site_config", 0);
1.37 paf 167: main_class=use_file(
1.148 parser 168: filespec,
1.153 parser 169: true/*ignore class_path*/, site_config_fail_on_read_problem,
1.37 paf 170: main_class_name, main_class);
1.29 paf 171: }
1.8 paf 172:
1.72 paf 173: // loading auto.p files from document_root/..
174: // to the one beside requested file.
175: // all assigned bases from upper dir
176: {
1.115 paf 177: const char *after=info.path_translated;
178: size_t drlen=strlen(info.document_root);
179: if(memcmp(after, info.document_root, drlen)==0) {
180: after+=drlen;
181: if(after[-1]=='/')
182: --after;
183: }
184:
1.152 parser 185: int step=0;
1.115 paf 186: while(const char *before=strchr(after, '/')) {
1.152 parser 187: String& sfile_spec=*NEW String(pool());
1.115 paf 188: if(after!=info.path_translated) {
1.152 parser 189: sfile_spec.APPEND_CLEAN(
190: info.path_translated, before-info.path_translated,
191: "path-translated-scanned", step++);
192: sfile_spec << "/" AUTO_FILE_NAME;
193:
194: main_class=use_file(sfile_spec,
195: true/*ignore class_path*/, false/*ignore read problem*/,
196: main_class_name, main_class);
1.115 paf 197: }
198: after=before+1;
1.72 paf 199: }
200: }
1.34 paf 201:
1.125 paf 202: // compile requested file
1.77 paf 203: String& spath_translated=*NEW String(pool());
1.136 parser 204: spath_translated.APPEND_TAINTED(info.path_translated, 0, "user-request", 0);
1.148 parser 205: main_class=use_file(spath_translated,
206: true/*ignore class_path*/, true/*don't ignore read problem*/,
1.72 paf 207: main_class_name, main_class);
1.7 paf 208:
1.124 paf 209: // configure not-root=user options
1.129 paf 210: OP.configure_user(*this);
1.124 paf 211: methoded_array->configure_user(*this);
212:
1.85 paf 213: // $MAIN:DEFAULTS
1.78 paf 214: Value *defaults=main_class->get_element(*defaults_name);
1.75 paf 215: // value must be allocated on request's pool for that pool used on
216: // meaning constructing @see attributed_meaning_to_string
1.80 paf 217: default_content_type=defaults?defaults->get_element(*content_type_name):0;
1.155 parser 218: // record default charset
1.154 parser 219: if(default_content_type)
1.172 parser 220: if(Hash *hash=default_content_type->get_hash(0))
1.154 parser 221: if(Value *vcharset=(Value *)hash->get(*charset_name))
222: pool().set_charset(vcharset->as_string());
223:
1.117 paf 224: if(Value *element=main_class->get_element(*user_html_name))
1.87 paf 225: if(Table *table=element->get_table())
1.147 parser 226: pool().set_tag(NEW Dictionary(*table));
1.85 paf 227:
228: // $MAIN:MIME-TYPES
229: if(Value *element=main_class->get_element(*mime_types_name))
230: if(Table *table=element->get_table())
231: mime_types=table;
1.102 paf 232:
1.124 paf 233: // filling form fields
1.153 parser 234: form.fill_fields_and_tables(*this);
1.102 paf 235:
1.124 paf 236: // filling cookies
237: cookie.fill_fields(*this);
1.25 paf 238:
239: // execute @main[]
1.143 parser 240: const String *body_string=execute_virtual_method(
241: *main_class, *main_method_name);
1.41 paf 242: if(!body_string)
1.169 parser 243: throw Exception(0,0,
1.145 parser 244: 0,
245: "'"MAIN_METHOD_NAME"' method not found");
1.79 paf 246:
1.91 paf 247: VString body_vstring_before_post_process(*body_string);
248: VString *body_vstring_after_post_process=&body_vstring_before_post_process;
249:
1.119 paf 250: // @postprocess
1.91 paf 251: if(Value *value=main_class->get_element(*post_process_method_name))
252: if(Junction *junction=value->get_junction())
253: if(const Method *method=junction->method) {
254: // preparing to pass parameters to
1.119 paf 255: // @postprocess[data]
1.146 parser 256: VMethodFrame frame(pool(), value->name(), *junction);
1.91 paf 257: frame.set_self(*main_class);
258:
259: frame.store_param(method->name,
260: &body_vstring_before_post_process);
261: body_vstring_after_post_process=
262: NEW VString(*execute_method(frame, *method));
263: }
1.90 paf 264:
1.144 parser 265: bool origins_mode=main_class->get_element(*origins_mode_name)!=0;
266:
267: const VFile *body_file=body_vstring_after_post_process->as_vfile(
268: String::UL_UNSPECIFIED, origins_mode);
1.41 paf 269:
1.45 paf 270: // extract response body
271: Value *body_value=static_cast<Value *>(
272: response.fields().get(*body_name));
1.119 paf 273: if(body_value) // there is some $response.body
1.90 paf 274: body_file=body_value->as_vfile();
1.144 parser 275: else if(origins_mode)
276: response.fields().put(*content_type_name,
277: NEW VString(*NEW String(pool(), ORIGINS_CONTENT_TYPE)));
1.45 paf 278:
279: // OK. write out the result
1.90 paf 280: output_result(*body_file, header_only);
1.171 parser 281: } catch(const Exception& e) { // request handling problem
1.76 paf 282: // we're returning not result, but error explanation
1.169 parser 283: try {
1.76 paf 284: // log the beast
285: const String *problem_source=e.problem_source();
1.114 paf 286: if(problem_source && problem_source->size())
1.76 paf 287: SAPI::log(pool(),
288: #ifndef NO_STRING_ORIGIN
1.180 ! paf 289: ORIGIN_FILE_LINE_FORMAT": "
1.76 paf 290: #endif
291: "'%s' %s [%s %s]",
292: #ifndef NO_STRING_ORIGIN
293: problem_source->origin().file?problem_source->origin().file:"global",
294: problem_source->origin().line,
295: #endif
1.173 paf 296: problem_source->cstr(),
1.76 paf 297: e.comment(),
1.173 paf 298: e.type()?e.type()->cstr():"-",
299: e.code()?e.code()->cstr():"-"
1.76 paf 300: );
301: else
302: SAPI::log(pool(),
303: "%s [%s %s]",
304: e.comment(),
1.173 paf 305: e.type()?e.type()->cstr():"-",
306: e.code()?e.code()->cstr():"-"
1.180 ! paf 307: );
1.171 parser 308:
1.43 paf 309: // reset language to default
310: flang=fdefault_lang;
1.135 parser 311: if(flang==String::UL_USER_HTML)
1.137 parser 312: flang=String::UL_HTML; // no _ & Co conversions in @exception[params]
1.43 paf 313:
314: // reset response
315: response.fields().clear();
316:
317: // this is what we'd return in $response:body
1.41 paf 318: const String *body_string=0;
1.43 paf 319:
1.30 paf 320: if(main_class) { // we've managed to end up with some main_class
321: // maybe we'd be lucky enough as to report an error
322: // in a gracefull way...
323: if(Value *value=main_class->get_element(*exception_method_name))
324: if(Junction *junction=value->get_junction())
325: if(const Method *method=junction->method) {
1.169 parser 326: // preparing to pass parameters to
1.171 parser 327: // @exception[origin;source;comment;type;code;stack]
1.146 parser 328: VMethodFrame frame(pool(), value->name(), *junction);
1.38 paf 329: frame.set_self(*main_class);
1.30 paf 330:
331: const String *problem_source=e.problem_source();
332: // origin
1.38 paf 333: Value *origin_value=0;
1.30 paf 334: #ifndef NO_STRING_ORIGIN
1.114 paf 335: if(problem_source && problem_source->size()) {
1.38 paf 336: const Origin& origin=problem_source->origin();
337: if(origin.file) {
338: char *buf=(char *)malloc(MAX_STRING);
1.180 ! paf 339: size_t buf_size=snprintf(buf, MAX_STRING, ORIGIN_FILE_LINE_FORMAT,
1.38 paf 340: origin.file, 1+origin.line);
1.171 parser 341: origin_value=NEW VString(*NEW String(pool(),
342: buf, buf_size, true));
1.38 paf 343: }
1.30 paf 344: }
345: #endif
1.91 paf 346: frame.store_param(method->name,
1.138 parser 347: origin_value?origin_value:NEW VVoid(pool()));
1.28 paf 348:
1.30 paf 349: // source
1.38 paf 350: Value *source_value=0;
1.114 paf 351: if(problem_source && problem_source->size()) {
1.47 paf 352: String& problem_source_copy=*NEW String(pool());
353: problem_source_copy.append(*problem_source,
354: flang, true);
1.43 paf 355: source_value=NEW VString(problem_source_copy);
356: }
1.91 paf 357: frame.store_param(method->name,
1.138 parser 358: source_value?source_value:NEW VVoid(pool()));
1.30 paf 359:
360: // comment
1.44 paf 361: String *comment_value=NEW String(pool(),
1.106 paf 362: e.comment(), 0, true);
1.91 paf 363: frame.store_param(method->name,
1.30 paf 364: NEW VString(*comment_value));
365:
366: // type
367: Value *type_value;
1.43 paf 368: if(e.type()) {
1.47 paf 369: String& type_copy=*NEW String(pool());
370: type_value=NEW VString(type_copy.append(*e.type(),
371: flang, true));
1.43 paf 372: } else
1.138 parser 373: type_value=NEW VVoid(pool());
1.91 paf 374: frame.store_param(method->name, type_value);
1.30 paf 375:
376: // code
377: Value *code_value;
1.43 paf 378: if(e.code()) {
1.47 paf 379: String& code_copy=*NEW String(pool());
380: code_value=NEW VString(code_copy.append(*e.code(),
381: flang, true));
1.43 paf 382: } else
1.138 parser 383: code_value=NEW VVoid(pool());
1.91 paf 384: frame.store_param(method->name, code_value);
1.30 paf 385:
1.171 parser 386: // $stack[^table::set{name origin}]
387: Array& stack_trace_columns=*NEW Array(pool());
388: stack_trace_columns+=NEW String(pool(), "name");
389: stack_trace_columns+=NEW String(pool(), "origin");
390: Table& stack_trace=*NEW Table(pool(), 0, &stack_trace_columns);
391: Array_iter tracei(trace);
392: while(tracei.has_next()) {
393: Array& row=*NEW Array(pool());
394:
395: const String *name=(const String *)tracei.next();
396: row+=name; // name column
397: #ifndef NO_STRING_ORIGIN
398: const Origin& origin=name->origin();
399: if(origin.file) {
400: char *buf=(char *)malloc(MAX_STRING);
1.180 ! paf 401: size_t buf_size=snprintf(buf, MAX_STRING, ORIGIN_FILE_LINE_FORMAT,
1.171 parser 402: origin.file, 1+origin.line);
403: row+=NEW String(pool(), buf, buf_size, true); // origin column
404: }
405: #endif
406: stack_trace+=&row;
407: }
408: frame.store_param(method->name,
409: NEW VTable(pool(), &stack_trace));
410:
1.43 paf 411: // future $response:body=
1.171 parser 412: // execute ^exception[origin;source;comment;type;code;stack]
1.43 paf 413: body_string=execute_method(frame, *method);
1.30 paf 414: }
415: }
416:
1.41 paf 417: if(!body_string) { // couldn't report an error beautifully?
418: // doing that ugly
419:
420: // make up result: $origin $source $comment $type $code
421: char *buf=(char *)malloc(MAX_STRING);
1.30 paf 422: size_t printed=0;
423: const String *problem_source=e.problem_source();
424: if(problem_source) {
1.16 paf 425: #ifndef NO_STRING_ORIGIN
1.30 paf 426: const Origin& origin=problem_source->origin();
427: if(origin.file)
1.180 ! paf 428: printed+=snprintf(buf+printed, MAX_STRING-printed,
! 429: ORIGIN_FILE_LINE_FORMAT": ",
! 430: origin.file, 1+origin.line
! 431: );
1.28 paf 432: #endif
1.41 paf 433: printed+=snprintf(buf+printed, MAX_STRING-printed, "'%s' ",
1.173 paf 434: problem_source->cstr());
1.30 paf 435: }
1.41 paf 436: printed+=snprintf(buf+printed, MAX_STRING-printed, "%s",
1.30 paf 437: e.comment());
438: const String *type=e.type();
439: if(type) {
1.41 paf 440: printed+=snprintf(buf+printed, MAX_STRING-printed, " type: %s",
1.173 paf 441: type->cstr());
1.30 paf 442: const String *code=e.code();
443: if(code)
1.41 paf 444: printed+=snprintf(buf+printed, MAX_STRING-printed, ", code: %s",
1.173 paf 445: code->cstr());
1.30 paf 446: }
1.43 paf 447:
448: // future $response:content-type
1.49 paf 449: response.fields().put(*content_type_name,
1.82 paf 450: NEW VString(*NEW String(pool(), UNHANDLED_EXCEPTION_CONTENT_TYPE)));
1.43 paf 451: // future $response:body
1.44 paf 452: body_string=NEW String(pool(), buf);
1.30 paf 453: }
1.41 paf 454:
1.144 parser 455: VString body_vstring(*body_string);
1.90 paf 456: const VFile *body_file=body_vstring.as_vfile();
457:
1.45 paf 458: // ERROR. write it out
1.90 paf 459: output_result(*body_file, header_only);
1.170 parser 460: } catch(const Exception& ) {
1.169 parser 461: /*re*/throw;
1.3 paf 462: }
1.1 paf 463: }
464: }
465:
1.148 parser 466: VStateless_class *Request::use_file(const String& file_name,
467: bool ignore_class_path, bool fail_on_read_problem,
1.26 paf 468: const String *name,
469: VStateless_class *base_class) {
1.73 paf 470: // cyclic dependence check
1.148 parser 471: if(used_files.get(file_name))
1.73 paf 472: return base_class;
1.148 parser 473: used_files.put(file_name, (Hash::Val *)true);
1.73 paf 474:
1.148 parser 475: const String *file_spec;
1.153 parser 476: if(ignore_class_path) // ignore_class_path?
1.148 parser 477: file_spec=&file_name;
1.153 parser 478: else if(file_name.first_char()=='/') //absolute path, no need to scan MAIN:CLASS_PATH?
479: file_spec=&absolute(file_name);
480: else {
481: file_spec=0;
482: if(main_class)
483: if(Value *element=main_class->get_element(*class_path_name)) {
484: if(element->is_string()) {
485: file_spec=file_readable(element->as_string(), file_name); // found at class_path?
486: } else if(Table *table=element->get_table()) {
487: int size=table->size();
488: for(int i=size; i--; ) {
489: const String& path=*static_cast<Array *>(table->get(i))->get_string(0);
490: if(file_spec=file_readable(path, file_name))
491: break; // found along class_path
1.148 parser 492: }
1.153 parser 493: } else
1.169 parser 494: throw Exception(0, 0,
1.153 parser 495: &element->name(),
496: "must be string or table");
497: if(!file_spec)
1.169 parser 498: throw Exception(0, 0,
1.153 parser 499: &file_name,
500: "not found along " MAIN_CLASS_NAME ":" CLASS_PATH_NAME);
501: }
502: if(!file_spec)
1.169 parser 503: throw Exception(0, 0,
1.153 parser 504: &file_name,
505: "usage failed - no " MAIN_CLASS_NAME ":" CLASS_PATH_NAME " were specified");
1.148 parser 506: }
1.73 paf 507:
1.148 parser 508: char *source=file_read_text(pool(), *file_spec, fail_on_read_problem);
1.3 paf 509: if(!source)
1.12 paf 510: return base_class;
1.3 paf 511:
1.148 parser 512: return use_buf(source, file_spec->cstr(), 0/*new class*/, name, base_class);
1.16 paf 513: }
514:
1.67 paf 515: VStateless_class *Request::use_buf(const char *source, const char *file,
1.26 paf 516: VStateless_class *aclass, const String *name,
517: VStateless_class *base_class) {
1.5 paf 518: // compile loaded class
1.26 paf 519: VStateless_class& cclass=COMPILE(source, aclass, name, base_class, file);
1.1 paf 520:
1.4 paf 521: // locate and execute possible @auto[] static method
1.143 parser 522: execute_nonvirtual_method(cclass, *auto_method_name, false /*no result needed*/);
1.16 paf 523: return &cclass;
1.19 paf 524: }
525:
1.77 paf 526: const String& Request::relative(const char *apath, const String& relative_name) {
527: int lpath_buf_size=strlen(apath)+1;
528: char *lpath=(char *)malloc(lpath_buf_size);
529: memcpy(lpath, apath, lpath_buf_size);
1.120 paf 530: if(!rsplit(lpath, '/'))
531: strcpy(lpath, ".");
1.77 paf 532: String& result=*NEW String(pool(), lpath);
1.104 paf 533: result << "/" << relative_name;
1.19 paf 534: return result;
535: }
536:
1.77 paf 537: const String& Request::absolute(const String& relative_name) {
538: char *relative_name_cstr=relative_name.cstr();
539: if(relative_name_cstr[0]=='/') {
540: String& result=*NEW String(pool(), info.document_root);
1.104 paf 541: result << relative_name;
1.19 paf 542: return result;
543: } else
1.77 paf 544: return relative(info.path_translated, relative_name);
1.1 paf 545: }
1.45 paf 546:
1.101 paf 547: static void add_header_attribute(const Hash::Key& aattribute, Hash::Val *ameaning,
548: void *info) {
1.178 paf 549: Request& r=*static_cast<Request *>(info);
550: if(aattribute==*body_name)
1.101 paf 551: return;
552:
553: Value& lmeaning=*static_cast<Value *>(ameaning);
554: Pool& pool=lmeaning.pool();
555:
556: SAPI::add_header_attribute(pool,
1.173 paf 557: aattribute.cstr(),
1.101 paf 558: attributed_meaning_to_string(lmeaning, String::UL_HTTP_HEADER).cstr());
559: }
1.90 paf 560: void Request::output_result(const VFile& body_file, bool header_only) {
1.51 paf 561: // header: cookies
562: cookie.output_result();
563:
1.90 paf 564: // set content-type
565: if(String *body_file_content_type=static_cast<String *>(
566: body_file.fields().get(*vfile_mime_type_name))) {
567: // body file content type
568: response.fields().put(*content_type_name, body_file_content_type);
569: } else {
570: // default content type
571: response.fields().put_dont_replace(*content_type_name,
572: default_content_type?default_content_type
573: :NEW VString(*NEW String(pool(), DEFAULT_CONTENT_TYPE)));
1.92 paf 574: }
575:
576: // content-disposition
1.111 paf 577: if(VString *vfile_name=static_cast<VString *>(body_file.fields().get(*name_name)))
578: if(vfile_name->string()!=NONAME_DAT) {
579: VHash& vhash=*NEW VHash(pool());
1.174 paf 580: vhash.hash(0).put(*content_disposition_filename_name, vfile_name);
1.111 paf 581: response.fields().put(*content_disposition_name, &vhash);
582: }
1.49 paf 583:
1.62 paf 584: // prepare header: $response:fields without :body
1.178 paf 585: response.fields().for_each(add_header_attribute, this);
1.50 paf 586:
1.62 paf 587: // prepare...
1.90 paf 588: const void *body=body_file.value_ptr();
589: size_t content_length=body_file.value_size();
1.50 paf 590:
1.62 paf 591: // prepare header: content-length
1.65 paf 592: if(content_length) { // useful for redirecting [header "location: http://..."]
593: char content_length_cstr[MAX_NUMBER];
1.108 paf 594: snprintf(content_length_cstr, MAX_NUMBER, "%u", content_length);
1.69 paf 595: SAPI::add_header_attribute(pool(), "content-length", content_length_cstr);
1.65 paf 596: }
1.62 paf 597:
598: // send header
1.69 paf 599: SAPI::send_header(pool());
1.71 paf 600:
1.62 paf 601: // send body
602: if(!header_only)
1.69 paf 603: SAPI::send_body(pool(), body, content_length);
1.50 paf 604: }
1.104 paf 605:
606: const String& Request::mime_type_of(const char *user_file_name_cstr) {
607: if(mime_types)
608: if(const char *cext=strrchr(user_file_name_cstr, '.')) {
609: String sext(pool(), ++cext);
610: if(mime_types->locate(0, sext))
611: if(const String *result=mime_types->item(1))
612: return *result;
613: else
1.169 parser 614: throw Exception(0, 0,
1.104 paf 615: mime_types->origin_string(),
616: "MIME-TYPE table column elements must not be empty");
617: }
618: return *NEW String(pool(), "application/octet-stream");
1.158 parser 619: }
620:
1.165 parser 621: const unsigned char *Request::pcre_tables() {
1.166 parser 622: if(unsigned char *result=(unsigned char *)CTYPE.get(pool().get_charset()))
623: return result;
624:
625: // this is not for pcre itself,
626: // it can do default, it's for string.lower&co
627: return pcre_default_tables;
1.133 parser 628: }
E-mail: