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

Last change on this file since 12771 was 12579, checked in by kjdon, 18 years ago

set the filesize in the fileupload data

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