source: main/trunk/greenstone2/runtime-src/src/recpt/cgiutils.cpp@ 22796

Last change on this file since 22796 was 22796, checked in by mdewsnip, 14 years ago

Need to add <time.h> so my last change compiles on Windows.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/**********************************************************************
2 *
3 * cgiutils.cpp -- general cgi utilities
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "cgiutils.h"
27#include "fileutil.h"
28#include "gsdlunicode.h"
29#include "fileutil.h"
30#include "unitool.h" // in mg, for output_utf8_char
31#include <cstdlib>
32#include <time.h>
33
34#if defined(GSDL_USE_OBJECTSPACE)
35# include <ospace\std\iostream>
36# include <ospace\std\fstream>
37#elif defined(GSDL_USE_IOS_H)
38# include <iostream.h>
39# include <fstream.h>
40#else
41# include <iostream>
42# include <fstream>
43#endif
44
45
46static unsigned short hexdigit (unsigned short c) {
47 if (c >= '0' && c <= '9') return (c-'0');
48 if (c >= 'a' && c <= 'f') return (c-'a'+10);
49 if (c >= 'A' && c <= 'F') return (c-'A'+10);
50 return c;
51}
52
53
54static void c2hex (unsigned short c, text_t &t) {
55 t.clear();
56
57 if (c >= 256) {
58 t = "20"; // ' '
59 return;
60 }
61
62 unsigned short o1, o2;
63
64 o1 = (c/16) % 16;
65 o2 = c % 16;
66 if (o1 >= 10) o1 += 'a' - 10;
67 else o1 += '0';
68 if (o2 >= 10) o2 += 'a' - 10;
69 else o2 += '0';
70
71 t.push_back(o1);
72 t.push_back(o2);
73}
74
75static text_t::iterator getline (text_t::iterator first,
76 text_t::iterator last,
77 bool include_crlf) {
78 while (first != last) {
79 if (((first+1) != last) && (*first == 13) && (*(first+1) == 10)) {
80 // found <CRLF>
81 if (include_crlf) first += 2;
82 break;
83 }
84
85 first++;
86 }
87
88 return first;
89}
90
91static void process_post_section (text_t &argname, text_t &argdata, text_t &filename, text_t &filedata,
92 text_t &filetype, bool &isfile, text_t &argstr,
93 fileupload_tmap &fileuploads, const text_t &gsdlhome) {
94
95 if (!argname.empty()) {
96
97 if (!isfile) {
98 // argdata includes a trailing <CRLF> that we must remove
99 if ((argdata.size() > 1) && (*(argdata.end()-2) == 13) && (*(argdata.end()-1) == 10)) {
100 argdata.erase(argdata.end()-2, argdata.end());
101 }
102 if (!argstr.empty()) argstr += "&";
103 argstr += argname + "=" + argdata;
104
105 } else if (!filename.empty()) {
106 // filedata includes a trailing <CRLF> that we must remove
107 if ((filedata.size() > 1) && (*(filedata.end()-2) == 13) && (*(filedata.end()-1) == 10)) {
108 filedata.erase(filedata.end()-2, filedata.end());
109 }
110
111 // create tmp_name for storing the file on disk, using the current timestamp
112 text_t tmp_name(time(NULL));
113 tmp_name = filename_cat(gsdlhome, "tmp", tmp_name);
114
115 char *tmp_name_c = tmp_name.getcstr();
116
117 // write the file data to disk
118 outconvertclass out;
119 ofstream filestream(tmp_name_c, ios::out | ios::binary);
120 filestream << out << filedata;
121 filestream.close();
122 delete tmp_name_c;
123
124 // populate the fields of a fileupload_t and put it in the
125 // fileuploads map
126 fileupload_t fu;
127 // note that filename currently may or may not include the path since
128 // some browsers (e.g. IE) include the path while others
129 // (e.g. mozilla) do not. we should probably remove the path from
130 // this field here to get a consistent value across all browsers.
131 text_t::iterator slash = findlastchar(filename.begin(), filename.end(), '\\');
132 if (slash != filename.end()) {
133 filename = substr(slash+1, filename.end());
134 }
135 fu.name = filename;
136 fu.type = filetype;
137 // size has yet to be implemented
138 fu.size = filedata.size();
139
140 fu.tmp_name = tmp_name;
141 fileuploads[argname] = fu;
142 }
143 }
144 isfile = false;
145 argname.clear();
146 argdata.clear();
147 filename.clear();
148 filedata.clear();
149 filetype.clear();
150}
151
152// parse data obtained through a CGI POST request
153text_t parse_post_data (text_t &content_type, text_t &raw_post_data,
154 fileupload_tmap &fileuploads, const text_t &gsdlhome) {
155
156 text_t argstr;
157
158 text_t::iterator content_type_begin = content_type.begin();
159 text_t::iterator content_type_end = content_type.end();
160 if (findword(content_type_begin, content_type_end, "multipart/form-data") == content_type_end) {
161 // a simple post request
162
163 return raw_post_data;
164
165 } else {
166 // multipart/form data - may contain one or more uploaded files
167
168 /*
169 content_type should look something like the following
170 multipart/form-data; boundary=---------------------------7d411e1a50330
171
172 while raw_post_data will be as follows
173 -----------------------------7d43e73450330CRLF
174 Content-Disposition: form-data; name="e"<CRLF>
175 <CRLF>
176 d-0testss--1-0-00---4----0--0-110--1en-Zz-1---10-about-0--00031-001utfZz-8-0<CRLF>
177 -----------------------------7d43e73450330<CRLF>
178 Content-Disposition: form-data; name="afile"; filename="C:\somedoc.doc"<CRLF>
179 Content-Type: application/msword<CRLF>
180 <CRLF>
181 <Content of file><CRLF>
182
183 */
184
185 // first get the boundary from content-type
186 text_t::iterator boundary_begin = findword(content_type_begin, content_type_end, "boundary=");
187 if (boundary_begin+9 < content_type_end)
188 {
189 // skip over "boundary=" part of string
190 boundary_begin += 9;
191 }
192 else {
193 // error
194 cerr << "Error: malformed boundary? '" << content_type << "'" << endl;
195 return "";
196 }
197 text_t boundary = substr(boundary_begin, getline(boundary_begin, content_type_end, false));
198 int boundary_len = boundary.size();
199
200
201 text_t argname, argdata, filename, filedata, filetype;
202 bool isfile = false;
203 text_t::iterator data_here = raw_post_data.begin();
204 text_t::iterator data_end = raw_post_data.end();
205 while (data_here != data_end) {
206
207 // get the next available line (including the trailing <CRLF>
208 text_t line = substr(data_here, getline(data_here, data_end, true));
209
210 data_here += line.size();
211 text_t::iterator line_begin = line.begin();
212 text_t::iterator line_end = line.end();
213 if (findword(line_begin, line_end, boundary) != line_end) {
214 // we've found a boundary
215 process_post_section(argname, argdata, filename, filedata, filetype,
216 isfile, argstr, fileuploads, gsdlhome);
217
218 } else if (findword(line_begin, line_end, "Content-Disposition: form-data") != line_end) {
219 // we've found the the beginning of a new section
220 argname.clear();
221 argdata.clear();
222
223 // get the name of this piece of form data
224 text_t::iterator it = findword(line_begin, line_end, "name=\"");
225 if (it == line_end) break; // error - this shouldn't happen
226 it = findchar(it, line_end, '"');
227 if ((it != line_end) && (it+1 != line_end)) {
228 argname = substr(it+1, findchar(it+1, line_end, '"'));
229 }
230
231 // if this piece of form data contains filename="" it's a file
232 // upload and needs to be treated special
233 it = (findword(line_begin, line_end, "filename=\""));
234 if (it != line_end) {
235 // we've found a file upload
236 isfile = true;
237 it = findchar(it, line_end, '"');
238 if ((it != line_end) && (it+1 != line_end)) {
239 filename = substr(it+1, findchar(it+1, line_end, '"'));
240 }
241
242 // the next line is the content-type of this section
243 line = substr(data_here, getline(data_here, data_end, true));
244 data_here += line.size();
245 line_begin = line.begin();
246 line_end = line.end();
247 it = (findword(line_begin, line_end, "Content-Type: "));
248 if (it != line_end) {
249 filetype = substr(it+14, getline(it, line_end, false));
250 }
251 }
252
253 // eat up the next line as it's just a <CRLF> on it's own
254 data_here += 2;
255
256 } else {
257 if (isfile) filedata += line;
258 else argdata += line;
259 }
260
261 }
262
263 // process last section
264 process_post_section(argname, argdata, filename, filedata, filetype,
265 isfile, argstr, fileuploads, gsdlhome);
266
267 return argstr;
268 }
269}
270
271// convert %xx and + to their appropriate equivalents
272// IE 6.0 and later use "%u" followed by 4 hex digits... MS IIS extension!
273// NOTE: this method is crap. It assumes the input encoding is utf-8. If it
274// actually was, then this returns utf-8, and needs to_uni on the
275// result to get it back to unicode. If the encoding wasn't utf-8, then the
276// output may be crap. Seems to work for 8 bit encodings.
277// Really, this should be given the encoding, and should always return unicode.
278void decode_cgi_arg (text_t &argstr) {
279 text_t::iterator in = argstr.begin();
280 text_t::iterator out = in;
281 text_t::iterator end = argstr.end();
282
283 while (in != end) {
284 if (*in == '+') *out = ' ';
285
286 else if (*in == '%') {
287 unsigned short c = '%';
288 ++in;
289 if (in != end) { // this is an encoding...
290 if (*in == 'u') { // convert %uHHHH to unicode then current encoding
291 // this assumes a short int is at least 16 bits...
292 ++in;
293 if (in != end)
294 c=hexdigit(*in++) << 12;
295 if (in != end)
296 c+=hexdigit(*in++) << 8;
297 if (in != end)
298 c+=hexdigit(*in++) << 4;
299 if (in != end)
300 c+=hexdigit(*in);
301 /* BAD!! The following assumes the interface is using utf-8. But
302 at this point we don't know what encoding we are using, unless
303 we can parse it out of the string we are currently decoding... */
304 text_t uni=" ";
305 uni[0]=c;
306 text_t utf8=to_utf8(uni);
307 int last_byte=utf8.size()-1;
308 for (int i=0;i<last_byte;++i)
309 *out++ = utf8[i];
310 c=utf8[last_byte];
311 } else { // convert %HH to hex value
312 c = hexdigit (*in);
313 ++in;
314 if (in != end && c < 16) { // sanity check on the previous character
315 c = c*16 + hexdigit (*in);
316 }
317 }
318 }
319 *out = c;
320 } else *out = *in;
321
322 if (in != end) ++in;
323 ++out;
324 }
325
326 // remove the excess characters
327 argstr.erase (out, end);
328
329}
330
331
332// split up the cgi arguments
333void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr,
334 cgiargsclass &args) {
335 args.clear();
336
337 text_t::const_iterator here = argstr.begin();
338 text_t::const_iterator end = argstr.end();
339 text_t key, value;
340
341 // extract out the key=value pairs
342 while (here != end) {
343 // get the next key and value pair
344 here = getdelimitstr (here, end, '=', key);
345 here = getdelimitstr (here, end, '&', value);
346
347 // convert %xx and + to their appropriate equivalents
348 decode_cgi_arg (value);
349 value.setencoding(1); // other encoding
350 // store this key=value pair
351 if (!key.empty()) {
352
353 // if arg occurs multiple times (as is the case with multiple
354 // checkboxes using the same name) we'll create a comma separated
355 // list of all the values (this uses a hack that encodes naturally
356 // occurring commas as %2C - values will therefore need to be decoded
357 // again before use) - it should use an array instead
358 const cgiarginfo *info = argsinfo.getarginfo (key);
359 if (info==NULL) {
360 // If info is NULL, we can't tell if the arg is multiple value or not
361 // Because we need to have dynamically named arguments multivalued, we
362 // will always assume multiplevalue = true
363 // If the arg is not multi valued, then you need to decode the commas.
364 if (args.getarg(key)==NULL) {
365 args.setarg (key, encode_commas(value), cgiarg_t::cgi_arg);
366 }
367 else {
368 text_t newvalue = args[key];
369
370 newvalue += "," + encode_commas(value);
371 newvalue.setencoding(1); // other encoding
372 args.setarg (key, newvalue, cgiarg_t::cgi_arg);
373 }
374 }
375 else {
376 if (info->multiplevalue) {
377
378 text_t newvalue = args[key];
379 if (args.lookupcgiarg(key).source == cgiarg_t::cgi_arg) newvalue += ",";
380 newvalue += encode_commas(value);
381 newvalue.setencoding(1); // other encoding
382 args.setarg (key, newvalue, cgiarg_t::cgi_arg);
383
384 } else {
385 args.setarg (key, value, cgiarg_t::cgi_arg);
386 }
387 }
388 }
389 }
390}
391
392text_t encode_commas (const text_t &intext) {
393
394 text_t outtext;
395
396 text_t::const_iterator here = intext.begin ();
397 text_t::const_iterator end = intext.end ();
398
399 while (here != end) {
400 if (*here == ',') outtext += "%2C";
401 else outtext.push_back (*here);
402 ++here;
403 }
404 return outtext;
405}
406
407text_t decode_commas (const text_t &intext) {
408
409 text_t outtext;
410
411 text_t::const_iterator here = intext.begin ();
412 text_t::const_iterator end = intext.end ();
413
414 while (here != end) {
415 if ((here+2<end) && *here == '%' && *(here+1) == '2' &&
416 (*(here+2) == 'C' || *(here+2) == 'c')) {
417 here += 2;
418 outtext.push_back(',');
419
420 }else outtext.push_back (*here);
421 ++here;
422 }
423 return outtext;
424}
425
426// set utf8 to true if input is in utf-8, otherwise expects input in unicode
427text_t minus_safe (const text_t &intext, bool utf8) {
428
429 text_t outtext;
430
431 text_t::const_iterator here = intext.begin ();
432 text_t::const_iterator end = intext.end ();
433
434 while (here != end) {
435 if (*here == '-') outtext += "Zz-";
436 else outtext.push_back (*here);
437 ++here;
438 }
439 if (utf8) {
440 outtext = cgi_safe_utf8 (outtext);
441 } else {
442 outtext = cgi_safe_unicode (outtext);
443 }
444 return outtext;
445}
446
447// takes utf-8 input
448text_t cgi_safe_utf8 (const text_t &intext) {
449 text_t outtext;
450
451 text_t::const_iterator here = intext.begin ();
452 text_t::const_iterator end = intext.end ();
453 unsigned short c;
454 text_t ttmp;
455
456 while (here != end) {
457 c = *here;
458 if (((c >= 'a') && (c <= 'z')) ||
459 ((c >= 'A') && (c <= 'Z')) ||
460 ((c >= '0') && (c <= '9')) ||
461 (c == '%') || (c == '-')) {
462 // alphanumeric character
463 outtext.push_back(c);
464 } else if (c == ' ') {
465 // space
466 outtext.push_back('+');
467 } else if (c > 255) { // not utf-8 character
468 cerr << "WARNING: expected utf-8 char, but got unicode!!\n";
469 } else {
470 // everything else
471 outtext.push_back('%');
472 c2hex(c, ttmp);
473 outtext += ttmp;
474 }
475
476 ++here;
477 }
478
479 return outtext;
480}
481// takes unicode input
482text_t cgi_safe_unicode (const text_t &intext) {
483 text_t outtext;
484
485 text_t::const_iterator here = intext.begin ();
486 text_t::const_iterator end = intext.end ();
487 unsigned short c;
488 text_t ttmp;
489
490 while (here != end) {
491 c = *here;
492 if (((c >= 'a') && (c <= 'z')) ||
493 ((c >= 'A') && (c <= 'Z')) ||
494 ((c >= '0') && (c <= '9')) ||
495 (c == '%') || (c == '-')) {
496 // alphanumeric character
497 outtext.push_back(c);
498 } else if (c == ' ') {
499 // space
500 outtext.push_back('+');
501 } else if (c > 127) { // unicode character
502 unsigned char buf[3]; // up to 3 bytes
503 buf[0]='\0';buf[1]='\0';buf[2]='\0';
504 output_utf8_char(c,buf, buf+2);
505 outtext.push_back('%');
506 c2hex(buf[0], ttmp);
507 outtext += ttmp;
508 outtext.push_back('%');
509 c2hex(buf[1], ttmp);
510 outtext += ttmp;
511 if (buf[2]) {
512 outtext.push_back('%');
513 c2hex(buf[2], ttmp);
514 outtext += ttmp;
515 }
516 } else {
517 // everything else
518 outtext.push_back('%');
519 c2hex(c, ttmp);
520 outtext += ttmp;
521 }
522
523 ++here;
524 }
525
526 return outtext;
527}
528
529
530
531
532static text_t::const_iterator get_next_save_arg (text_t::const_iterator first,
533 text_t::const_iterator last,
534 text_t &argname) {
535 first = getdelimitstr (first, last, '-', argname);
536 return first;
537}
538
539
540// check_save_conf_str checks the configuration string for
541// the saved args and makes sure it does not conflict with
542// the information about the arguments. If an error is encountered
543// it will return false and the program should not produce any
544// output.
545bool check_save_conf_str (const text_t &saveconf,
546 const cgiargsinfoclass &argsinfo,
547 ostream &logout) {
548 outconvertclass text_t2ascii;
549
550 text_tset argsset;
551 text_t::const_iterator saveconfhere = saveconf.begin ();
552 text_t::const_iterator saveconfend = saveconf.end ();
553 text_t argname;
554 const cgiarginfo *info;
555
556 // first check to make sure all saved arguments can be saved
557
558 while (saveconfhere != saveconfend) {
559 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
560
561 if (!argname.empty()) {
562 // save the argument name for later
563 argsset.insert (argname);
564
565 // check the argument
566 info = argsinfo.getarginfo (argname);
567 if (info == NULL) {
568 logout << text_t2ascii << "Error: the cgi argument \"" << argname
569 << "\" is used in the configuration string for the\n"
570 << "saved arguments but does not exist as a valid argument.\n\n";
571 return false;
572 }
573 if (info->savedarginfo == cgiarginfo::mustnot) {
574 logout << text_t2ascii << "Error: the cgi argument \"" << argname
575 << "\" is used in the configuration string for the\n"
576 << "saved arguments but has been specified as an argument whose\n"
577 << "state must not be saved.\n\n";
578 return false;
579 }
580 }
581 }
582
583
584 // next check that all saved arguments that should be saved
585 // are saved
586 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
587 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
588
589 while (argsinfohere != argsinfoend) {
590 if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
591 (argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
592 logout << text_t2ascii << "Error: the cgi argument \""
593 << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
594 << "be save but was not listed in the saved arguments.\n\n";
595 return false;
596 }
597
598 ++argsinfohere;
599 }
600
601 return true; // made it, no clashes
602}
603
604
605// create_save_conf_str will create a configuration string
606// based on the information in argsinfo. This method of configuration
607// is not recomended as small changes can produce large changes in
608// the resulting configuration string (for instance a totally different
609// ordering). Only arguments which "must" be saved are included in
610// the resulting string.
611text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
612 ostream &/*logout*/) {
613 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
614 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
615 text_t saveconf;
616 bool first = true;
617
618 while (argsinfohere != argsinfoend) {
619 // save this argument if it must be saved
620 if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
621 if (!first) saveconf.push_back ('-');
622 else first = false;
623 saveconf += (*argsinfohere).second.shortname;
624 }
625
626 ++argsinfohere;
627 }
628
629 return saveconf;
630}
631
632
633// expand_save_args will expand the saved arguments based
634// on saveconf placing the results in args if they are not
635// already defined. If it encounters an error it will return false
636// and output more information to logout.
637bool expand_save_args (const cgiargsinfoclass &argsinfo,
638 const text_t &saveconf,
639 cgiargsclass &args,
640 ostream &logout) {
641 outconvertclass text_t2ascii;
642
643 text_t *arg_e = args.getarg("e");
644 if (arg_e == NULL) return true; // no compressed arguments
645 if (arg_e->empty()) return true; // no compressed arguments
646
647 text_t argname, argvalue;
648 const cgiarginfo *argnameinfo;
649
650 text_t::const_iterator saveconfhere = saveconf.begin();
651 text_t::const_iterator saveconfend = saveconf.end();
652
653 text_t::iterator arg_ebegin = arg_e->begin();
654 text_t::iterator arg_eend = arg_e->end();
655 text_t::iterator arg_ehere = arg_ebegin;
656 while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
657 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
658
659 if (!argname.empty()) {
660 // found another entry
661 argnameinfo = argsinfo.getarginfo (argname);
662
663 if (argnameinfo == NULL) {
664 // no information about the argument could be found
665 // we can't keep going because we don't know whether
666 // this argument is a single or multiple character value
667 logout << text_t2ascii << "Error: the cgi argument \"" << argname
668 << "\" was specified as being a compressed argument\n"
669 << "but no information about it could be found within the "
670 << "cgiargsinfoclass.\n";
671 return false;
672
673 } else {
674
675 // found the argument information
676 if (argnameinfo->multiplechar) {
677 text_t::const_iterator sav = arg_ehere;
678 arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
679 if (distance(arg_ebegin, arg_ehere) > 2) {
680 // replace any '-' chars escaped with 'Zz'
681 bool first = true;
682 while ((*(arg_ehere-3) == 'Z') && (*(arg_ehere-2) == 'z')) {
683 if (first) argvalue.clear();
684
685 // Hey, here's a wild idea. Why don't we check that there is
686 // another hyphen in the cgiarge before we get a pointer to it and
687 // add one. That way we are far less likely to wander off into
688 // random memory merrily parsing arguments that are then lovingly
689 // spewed all over the HTML page returned at the usage logs.
690 text_t::iterator minus_itr = findchar (arg_ehere, arg_eend, '-');
691 if (minus_itr == arg_eend)
692 {
693 logout << text_t2ascii << "Error: the cgi argument \"" << argname << "\" was specified as being a compressed argument but we have run out of cgiarge to decompress!\n";
694 return false;
695 }
696 arg_ehere = minus_itr + 1;
697
698 while (sav != (arg_ehere-1)) {
699 if (!((*sav == 'Z') && (*(sav+1) == 'z') && (*(sav+2) == '-')) &&
700 !((*(sav-1) == 'Z') && (*sav == 'z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
701 ++sav;
702 }
703 first = false;
704 }
705 }
706 argvalue.setencoding(1); // other encoding
707 if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
708 } else {
709 args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
710 ++arg_ehere;
711 }
712 }
713 }
714 }
715
716 return true;
717}
718
719
720// adds the default values for those arguments which have not
721// been specified
722void add_default_args (const cgiargsinfoclass &argsinfo,
723 cgiargsclass &args,
724 ostream &/*logout*/) {
725 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
726 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
727
728 while (argsinfohere != argsinfoend) {
729 if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
730 args.setdefaultarg ((*argsinfohere).second.shortname,
731 (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
732 }
733 ++argsinfohere;
734 }
735}
736
737void add_fileupload_args (const cgiargsinfoclass &argsinfo,
738 cgiargsclass &args,
739 fileupload_tmap &fileuploads,
740 ostream &logout) {
741
742 const cgiarginfo *info = argsinfo.getarginfo("a");
743 fileupload_tmap::const_iterator this_file = fileuploads.begin();
744 fileupload_tmap::const_iterator end_file = fileuploads.end();
745 while (this_file != end_file) {
746 const cgiarginfo *info = argsinfo.getarginfo((*this_file).first);
747 if (info != NULL) {
748
749 if ((*info).fileupload && (file_exists((*this_file).second.tmp_name))) {
750
751 args.setargfile((*this_file).first, (*this_file).second);
752 }
753 }
754 this_file++;
755 }
756}
757
758// compress_save_args will compress the arguments and return
759// them in compressed_args. If an error was encountered
760// compressed_args will be set to to "", an error will be
761// written to logout, and the function will return false.
762bool compress_save_args (const cgiargsinfoclass &argsinfo,
763 const text_t &saveconf,
764 cgiargsclass &args,
765 text_t &compressed_args,
766 outconvertclass &outconvert,
767 ostream &logout) {
768 outconvertclass text_t2ascii;
769
770 compressed_args.clear();
771
772 text_t argname, argvalue;
773 const cgiarginfo *argnameinfo;
774
775 text_t::const_iterator saveconfhere = saveconf.begin();
776 text_t::const_iterator saveconfend = saveconf.end();
777
778 while (saveconfhere != saveconfend) {
779 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
780
781 if (!argname.empty()) {
782 // found another entry
783 argnameinfo = argsinfo.getarginfo (argname);
784
785 if (argnameinfo == NULL) {
786 // no information about the argument could be found
787 // we can't keep going because we don't know whether
788 // this argument is a single or multiple character value
789 logout << text_t2ascii << "Error: the cgi argument \"" << argname
790 << "\" was specified as being a compressed argument\n"
791 << "but no information about it could be found within the "
792 << "cgiargsinfoclass.\n";
793 compressed_args.clear();
794 return false;
795
796 } else {
797 // found the argument information
798 if (argnameinfo->multiplechar) {
799 // multiple character argument -- sort out any '-' chars
800 if (args["w"]=="utf-16be") // browsers don't like \0 in urls...
801 compressed_args += minus_safe (args[argname], false);
802 else
803 compressed_args += minus_safe (outconvert.convert(args[argname]), true);
804
805 if (saveconfhere != saveconfend) compressed_args.push_back ('-');
806
807 } else {
808 // single character argument
809 if (args[argname].size() == 0) {
810 logout << text_t2ascii << "Error: the cgi argument \"" << argname
811 << "\" was specified as being a compressed argument which\n"
812 << "should have a one character value but it was empty.\n\n";
813 compressed_args.clear ();
814 return false;
815
816 } else if (args[argname].size() > 1) {
817 logout << text_t2ascii << "Error: the cgi argument \"" << argname
818 << "\" was specified as being a compressed argument which\n"
819 << "should have a one character value but it had multiple characters.\n\n";
820 compressed_args.clear ();
821 return false;
822 }
823
824 // everything is ok
825 compressed_args += args[argname];
826 }
827 }
828 }
829 }
830
831 return true;
832}
833
834
835// args_tounicode converts any arguments which are not in unicode
836// to unicode using inconvert
837void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
838 cgiargsclass::iterator here = args.begin();
839 cgiargsclass::iterator end = args.end();
840
841 while (here != end) {
842 if ((*here).second.value.getencoding() > 0) {
843 // Call reset() before converting each argument, to prevent problems when converting the last
844 // argument left the converter in a bad state
845 inconvert.reset();
846 (*here).second.value = inconvert.convert((*here).second.value);
847 }
848
849 ++here;
850 }
851}
852
853// fcgienv will be loaded with environment name-value pairs
854// if using fastcgi (had to do this as getenv doesn't work
855// with our implementation of fastcgi). if fcgienv is empty
856// we'll simply use getenv
857text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv) {
858 if (fcgienv.empty()) {
859 char *n = name.getcstr();
860 char *v = getenv(n);
861 delete []n;
862 if (v != NULL) return v;
863 return g_EmptyText;
864
865 } else return fcgienv[name];
866}
Note: See TracBrowser for help on using the repository browser.