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

Last change on this file since 12794 was 12794, checked in by davidb, 18 years ago

Changes to make depositor action work under Windows. Main change is to
make sure 'standard input' is in binary mode before MIME multi-part posts
are parsed.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 24.1 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? '" << boundary_begin << "'" << 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!
272void decode_cgi_arg (text_t &argstr) {
273 text_t::iterator in = argstr.begin();
274 text_t::iterator out = in;
275 text_t::iterator end = argstr.end();
276
277 while (in != end) {
278 if (*in == '+') *out = ' ';
279
280 else if (*in == '%') {
281 unsigned short c = '%';
282 ++in;
283 if (in != end) { // this is an encoding...
284 if (*in == 'u') { // convert %uHHHH to unicode then current encoding
285 // this assumes a short int is at least 16 bits...
286 ++in;
287 if (in != end)
288 c=hexdigit(*in++) << 12;
289 if (in != end)
290 c+=hexdigit(*in++) << 8;
291 if (in != end)
292 c+=hexdigit(*in++) << 4;
293 if (in != end)
294 c+=hexdigit(*in);
295 /* BAD!! The following assumes the interface is using utf-8. But
296 at this point we don't know what encoding we are using, unless
297 we can parse it out of the string we are currently decoding... */
298 text_t uni=" ";
299 uni[0]=c;
300 text_t utf8=to_utf8(uni);
301 int last_byte=utf8.size()-1;
302 for (int i=0;i<last_byte;++i)
303 *out++ = utf8[i];
304 c=utf8[last_byte];
305 } else { // convert %HH to hex value
306 c = hexdigit (*in);
307 ++in;
308 if (in != end && c < 16) { // sanity check on the previous character
309 c = c*16 + hexdigit (*in);
310 }
311 }
312 }
313 *out = c;
314 } else *out = *in;
315
316 if (in != end) ++in;
317 ++out;
318 }
319
320 // remove the excess characters
321 argstr.erase (out, end);
322}
323
324
325// split up the cgi arguments
326void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr,
327 cgiargsclass &args) {
328 args.clear();
329
330 text_t::const_iterator here = argstr.begin();
331 text_t::const_iterator end = argstr.end();
332 text_t key, value;
333
334 // extract out the key=value pairs
335 while (here != end) {
336 // get the next key and value pair
337 here = getdelimitstr (here, end, '=', key);
338 here = getdelimitstr (here, end, '&', value);
339
340 // convert %xx and + to their appropriate equivalents
341 decode_cgi_arg (value);
342
343 value.setencoding(1); // other encoding
344 // store this key=value pair
345 if (!key.empty()) {
346
347 // if arg occurs multiple times (as is the case with multiple
348 // checkboxes using the same name) we'll create a comma separated
349 // list of all the values (this uses a hack that encodes naturally
350 // occurring commas as %2C - values will therefore need to be decoded
351 // again before use) - it should use an array instead
352 const cgiarginfo *info = argsinfo.getarginfo (key);
353 if (info==NULL) {
354 // If info is NULL, we can't tell if the arg is multiple value or not
355 // Because we need to have dynamically named arguments multivalued, we
356 // will always assume multiplevalue = true
357 // If the arg is not multi valued, then you need to decode the commas.
358 if (args.getarg(key)==NULL) {
359 args.setarg (key, encode_commas(value), cgiarg_t::cgi_arg);
360 }
361 else {
362 text_t newvalue = args[key];
363
364 newvalue += "," + encode_commas(value);
365 args.setarg (key, newvalue, cgiarg_t::cgi_arg);
366 }
367 }
368 else {
369 if (info->multiplevalue) {
370
371 text_t newvalue = args[key];
372 if (args.lookupcgiarg(key).source == cgiarg_t::cgi_arg) newvalue += ",";
373 newvalue += encode_commas(value);
374 args.setarg (key, newvalue, cgiarg_t::cgi_arg);
375
376 } else {
377 args.setarg (key, value, cgiarg_t::cgi_arg);
378 }
379 }
380 }
381 }
382}
383
384text_t encode_commas (const text_t &intext) {
385
386 text_t outtext;
387
388 text_t::const_iterator here = intext.begin ();
389 text_t::const_iterator end = intext.end ();
390
391 while (here != end) {
392 if (*here == ',') outtext += "%2C";
393 else outtext.push_back (*here);
394 ++here;
395 }
396 return outtext;
397}
398
399text_t decode_commas (const text_t &intext) {
400
401 text_t outtext;
402
403 text_t::const_iterator here = intext.begin ();
404 text_t::const_iterator end = intext.end ();
405
406 while (here != end) {
407 if ((here+2<end) && *here == '%' && *(here+1) == '2' &&
408 (*(here+2) == 'C' || *(here+2) == 'c')) {
409 here += 2;
410 outtext.push_back(',');
411
412 }else outtext.push_back (*here);
413 ++here;
414 }
415 return outtext;
416}
417
418text_t minus_safe (const text_t &intext) {
419
420 text_t outtext;
421
422 text_t::const_iterator here = intext.begin ();
423 text_t::const_iterator end = intext.end ();
424
425 while (here != end) {
426 if (*here == '-') outtext += "Zz-";
427 else outtext.push_back (*here);
428 ++here;
429 }
430 outtext = cgi_safe (outtext);
431 return outtext;
432}
433
434text_t cgi_safe (const text_t &intext) {
435 text_t outtext;
436
437 text_t::const_iterator here = intext.begin ();
438 text_t::const_iterator end = intext.end ();
439 unsigned short c;
440 text_t ttmp;
441
442 while (here != end) {
443 c = *here;
444 if (((c >= 'a') && (c <= 'z')) ||
445 ((c >= 'A') && (c <= 'Z')) ||
446 ((c >= '0') && (c <= '9')) ||
447 (c == '+') || (c == '%') || (c == '-')) {
448 // alphanumeric character
449 outtext.push_back(c);
450 } else if (c == ' ') {
451 // space
452 outtext.push_back('+');
453 } else if (c > 255) { // unicode character
454 unsigned char buf[3]; // up to 3 bytes
455 buf[0]='\0';buf[1]='\0';buf[2]='\0';
456 output_utf8_char(c,buf, buf+2);
457 outtext.push_back('%');
458 c2hex(buf[0], ttmp);
459 outtext += ttmp;
460 outtext.push_back('%');
461 c2hex(buf[1], ttmp);
462 outtext += ttmp;
463 if (buf[2]) {
464 outtext.push_back('%');
465 c2hex(buf[2], ttmp);
466 outtext += ttmp;
467 }
468 } else {
469 // everything else
470 outtext.push_back('%');
471 c2hex(c, ttmp);
472 outtext += ttmp;
473 }
474
475 ++here;
476 }
477
478 return outtext;
479}
480
481
482
483
484static text_t::const_iterator get_next_save_arg (text_t::const_iterator first,
485 text_t::const_iterator last,
486 text_t &argname) {
487 first = getdelimitstr (first, last, '-', argname);
488 return first;
489}
490
491
492// check_save_conf_str checks the configuration string for
493// the saved args and makes sure it does not conflict with
494// the information about the arguments. If an error is encountered
495// it will return false and the program should not produce any
496// output.
497bool check_save_conf_str (const text_t &saveconf,
498 const cgiargsinfoclass &argsinfo,
499 ostream &logout) {
500 outconvertclass text_t2ascii;
501
502 text_tset argsset;
503 text_t::const_iterator saveconfhere = saveconf.begin ();
504 text_t::const_iterator saveconfend = saveconf.end ();
505 text_t argname;
506 const cgiarginfo *info;
507
508 // first check to make sure all saved arguments can be saved
509
510 while (saveconfhere != saveconfend) {
511 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
512
513 if (!argname.empty()) {
514 // save the argument name for later
515 argsset.insert (argname);
516
517 // check the argument
518 info = argsinfo.getarginfo (argname);
519 if (info == NULL) {
520 logout << text_t2ascii << "Error: the cgi argument \"" << argname
521 << "\" is used in the configuration string for the\n"
522 << "saved arguments but does not exist as a valid argument.\n\n";
523 return false;
524 }
525 if (info->savedarginfo == cgiarginfo::mustnot) {
526 logout << text_t2ascii << "Error: the cgi argument \"" << argname
527 << "\" is used in the configuration string for the\n"
528 << "saved arguments but has been specified as an argument whose\n"
529 << "state must not be saved.\n\n";
530 return false;
531 }
532 }
533 }
534
535
536 // next check that all saved arguments that should be saved
537 // are saved
538 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
539 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
540
541 while (argsinfohere != argsinfoend) {
542 if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
543 (argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
544 logout << text_t2ascii << "Error: the cgi argument \""
545 << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
546 << "be save but was not listed in the saved arguments.\n\n";
547 return false;
548 }
549
550 ++argsinfohere;
551 }
552
553 return true; // made it, no clashes
554}
555
556
557// create_save_conf_str will create a configuration string
558// based on the information in argsinfo. This method of configuration
559// is not recomended as small changes can produce large changes in
560// the resulting configuration string (for instance a totally different
561// ordering). Only arguments which "must" be saved are included in
562// the resulting string.
563text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
564 ostream &/*logout*/) {
565 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
566 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
567 text_t saveconf;
568 bool first = true;
569
570 while (argsinfohere != argsinfoend) {
571 // save this argument if it must be saved
572 if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
573 if (!first) saveconf.push_back ('-');
574 else first = false;
575 saveconf += (*argsinfohere).second.shortname;
576 }
577
578 ++argsinfohere;
579 }
580
581 return saveconf;
582}
583
584
585// expand_save_args will expand the saved arguments based
586// on saveconf placing the results in args if they are not
587// already defined. If it encounters an error it will return false
588// and output more information to logout.
589bool expand_save_args (const cgiargsinfoclass &argsinfo,
590 const text_t &saveconf,
591 cgiargsclass &args,
592 ostream &logout) {
593 outconvertclass text_t2ascii;
594
595 text_t *arg_e = args.getarg("e");
596 if (arg_e == NULL) return true; // no compressed arguments
597 if (arg_e->empty()) return true; // no compressed arguments
598
599 text_t argname, argvalue;
600 const cgiarginfo *argnameinfo;
601
602 text_t::const_iterator saveconfhere = saveconf.begin();
603 text_t::const_iterator saveconfend = saveconf.end();
604
605 text_t::iterator arg_ebegin = arg_e->begin();
606 text_t::iterator arg_eend = arg_e->end();
607 text_t::iterator arg_ehere = arg_ebegin;
608 while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
609 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
610
611 if (!argname.empty()) {
612 // found another entry
613 argnameinfo = argsinfo.getarginfo (argname);
614
615 if (argnameinfo == NULL) {
616 // no information about the argument could be found
617 // we can't keep going because we don't know whether
618 // this argument is a single or multiple character value
619 logout << text_t2ascii << "Error: the cgi argument \"" << argname
620 << "\" was specified as being a compressed argument\n"
621 << "but no information about it could be found within the "
622 << "cgiargsinfoclass.\n";
623 return false;
624
625 } else {
626
627 // found the argument information
628 if (argnameinfo->multiplechar) {
629 text_t::const_iterator sav = arg_ehere;
630 arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
631 if (distance(arg_ebegin, arg_ehere) > 2) {
632 // replace any '-' chars escaped with 'Zz'
633 bool first = true;
634 while ((*(arg_ehere-3) == 'Z') && (*(arg_ehere-2) == 'z')) {
635 if (first) argvalue.clear();
636 arg_ehere = (findchar (arg_ehere, arg_eend, '-')) + 1;
637 while (sav != (arg_ehere-1)) {
638 if (!((*sav == 'Z') && (*(sav+1) == 'z') && (*(sav+2) == '-')) &&
639 !((*(sav-1) == 'Z') && (*sav == 'z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
640 ++sav;
641 }
642 first = false;
643 }
644 }
645 argvalue.setencoding(1); // other encoding
646 if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
647 } else {
648 args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
649 ++arg_ehere;
650 }
651 }
652 }
653 }
654
655 return true;
656}
657
658
659// adds the default values for those arguments which have not
660// been specified
661void add_default_args (const cgiargsinfoclass &argsinfo,
662 cgiargsclass &args,
663 ostream &/*logout*/) {
664 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
665 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
666
667 while (argsinfohere != argsinfoend) {
668 if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
669 args.setdefaultarg ((*argsinfohere).second.shortname,
670 (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
671 }
672 ++argsinfohere;
673 }
674}
675
676void add_fileupload_args (const cgiargsinfoclass &argsinfo,
677 cgiargsclass &args,
678 fileupload_tmap &fileuploads,
679 ostream &logout) {
680
681 const cgiarginfo *info = argsinfo.getarginfo("a");
682 fileupload_tmap::const_iterator this_file = fileuploads.begin();
683 fileupload_tmap::const_iterator end_file = fileuploads.end();
684 while (this_file != end_file) {
685 const cgiarginfo *info = argsinfo.getarginfo((*this_file).first);
686 if (info != NULL) {
687
688 if ((*info).fileupload && (file_exists((*this_file).second.tmp_name))) {
689
690 args.setargfile((*this_file).first, (*this_file).second);
691 }
692 }
693 this_file++;
694 }
695}
696
697// compress_save_args will compress the arguments and return
698// them in compressed_args. If an error was encountered
699// compressed_args will be set to to "", an error will be
700// written to logout, and the function will return false.
701bool compress_save_args (const cgiargsinfoclass &argsinfo,
702 const text_t &saveconf,
703 cgiargsclass &args,
704 text_t &compressed_args,
705 outconvertclass &outconvert,
706 ostream &logout) {
707 outconvertclass text_t2ascii;
708
709 compressed_args.clear();
710
711 text_t argname, argvalue;
712 const cgiarginfo *argnameinfo;
713
714 text_t::const_iterator saveconfhere = saveconf.begin();
715 text_t::const_iterator saveconfend = saveconf.end();
716
717 while (saveconfhere != saveconfend) {
718 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
719
720 if (!argname.empty()) {
721 // found another entry
722 argnameinfo = argsinfo.getarginfo (argname);
723
724 if (argnameinfo == NULL) {
725 // no information about the argument could be found
726 // we can't keep going because we don't know whether
727 // this argument is a single or multiple character value
728 logout << text_t2ascii << "Error: the cgi argument \"" << argname
729 << "\" was specified as being a compressed argument\n"
730 << "but no information about it could be found within the "
731 << "cgiargsinfoclass.\n";
732 compressed_args.clear();
733 return false;
734
735 } else {
736 // found the argument information
737 if (argnameinfo->multiplechar) {
738 // multiple character argument -- sort out any '-' chars
739 if (args["w"]=="utf-16be") // browsers don't like \0 in urls...
740 compressed_args += minus_safe (args[argname]);
741 else
742 compressed_args += minus_safe (outconvert.convert(args[argname]));
743
744 if (saveconfhere != saveconfend) compressed_args.push_back ('-');
745
746 } else {
747 // single character argument
748 if (args[argname].size() == 0) {
749 logout << text_t2ascii << "Error: the cgi argument \"" << argname
750 << "\" was specified as being a compressed argument which\n"
751 << "should have a one character value but it was empty.\n\n";
752 compressed_args.clear ();
753 return false;
754
755 } else if (args[argname].size() > 1) {
756 logout << text_t2ascii << "Error: the cgi argument \"" << argname
757 << "\" was specified as being a compressed argument which\n"
758 << "should have a one character value but it had multiple characters.\n\n";
759 compressed_args.clear ();
760 return false;
761 }
762
763 // everything is ok
764 compressed_args += args[argname];
765 }
766 }
767 }
768 }
769
770 return true;
771}
772
773
774// args_tounicode converts any arguments which are not in unicode
775// to unicode using inconvert
776void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
777 cgiargsclass::iterator here = args.begin();
778 cgiargsclass::iterator end = args.end();
779
780 while (here != end) {
781 if ((*here).second.value.getencoding() > 0) {
782 (*here).second.value = inconvert.convert((*here).second.value);
783 }
784
785 ++here;
786 }
787}
788
789// fcgienv will be loaded with environment name-value pairs
790// if using fastcgi (had to do this as getenv doesn't work
791// with our implementation of fastcgi). if fcgienv is empty
792// we'll simply use getenv
793text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv) {
794 if (fcgienv.empty()) {
795 char *n = name.getcstr();
796 char *v = getenv(n);
797 delete []n;
798 if (v != NULL) return v;
799 return g_EmptyText;
800
801 } else return fcgienv[name];
802}
Note: See TracBrowser for help on using the repository browser.