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

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

Added Stefan's fileupload code to replace use of cgicc by depositor. parsing post data, generating fileupload structures and saving the file

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 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 = 0;
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 text_tset multivalue;
322
323
324 // extract out the key=value pairs
325 while (here != end) {
326 // get the next key and value pair
327 here = getdelimitstr (here, end, '=', key);
328 here = getdelimitstr (here, end, '&', value);
329
330 // convert %xx and + to their appropriate equivalents
331 decode_cgi_arg (value);
332
333 value.setencoding(1); // other encoding
334 // store this key=value pair
335 if (!key.empty()) {
336
337 // if arg occurs multiple times (as is the case with multiple
338 // checkboxes using the same name) we'll create a comma separated
339 // list of all the values (this uses a hack that encodes naturally
340 // occurring commas as %2C - values will therefore need to be decoded
341 // again before use) - it should use an array instead
342 const cgiarginfo *info = argsinfo.getarginfo (key);
343
344 if (info==NULL) {
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.