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

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

Changed cgiutils::process_post_section() to use the current timestamp for the temporary uploaded filename instead of the MD5 hash of the uploaded file. This is only used by the depositor, which already uses timestamps, and timestamps will be more efficient that MD5ing, particularly for big files.

  • 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 "md5.h"
28#include "fileutil.h"
29#include "gsdlunicode.h"
30#include "fileutil.h"
31#include "unitool.h" // in mg, for output_utf8_char
32#include <cstdlib>
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.