source: gsdl/trunk/src/recpt/cgiutils.cpp@ 15597

Last change on this file since 15597 was 13461, checked in by kjdon, 17 years ago

added some comments for decode_cgi_arg method

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