root/main/trunk/greenstone2/runtime-src/src/recpt/cgiutils.cpp @ 22792

Revision 22792, 26.4 KB (checked in by mdewsnip, 10 years ago)

No longer need to include md5.h.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
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 "fileutil.h"
28#include "gsdlunicode.h"
29#include "fileutil.h"
30#include "unitool.h" // in mg, for output_utf8_char
31#include <cstdlib>
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, using the current timestamp
111      text_t tmp_name(time(NULL));
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      newvalue.setencoding(1); // other encoding
371      args.setarg (key, newvalue, cgiarg_t::cgi_arg);
372    }
373      }
374      else {
375    if (info->multiplevalue) {
376
377      text_t newvalue = args[key];
378      if (args.lookupcgiarg(key).source == cgiarg_t::cgi_arg) newvalue += ",";
379      newvalue += encode_commas(value);
380      newvalue.setencoding(1); // other encoding
381      args.setarg (key, newvalue, cgiarg_t::cgi_arg);
382
383    } else {
384      args.setarg (key, value, cgiarg_t::cgi_arg);
385    }
386      }
387    }
388  }
389}
390
391text_t encode_commas (const text_t &intext) {
392
393  text_t outtext;
394
395  text_t::const_iterator here = intext.begin ();
396  text_t::const_iterator end = intext.end ();
397
398  while (here != end) {
399    if (*here == ',') outtext += "%2C";
400    else outtext.push_back (*here);
401    ++here;
402  }
403  return outtext;
404}
405
406text_t decode_commas (const text_t &intext) {
407
408  text_t outtext;
409 
410  text_t::const_iterator here = intext.begin ();
411  text_t::const_iterator end = intext.end ();
412 
413  while (here != end) {
414    if ((here+2<end) && *here == '%' && *(here+1) == '2' &&
415    (*(here+2) == 'C' || *(here+2) == 'c')) {
416      here += 2;
417      outtext.push_back(',');
418     
419    }else outtext.push_back (*here);
420    ++here;
421  }
422  return outtext;
423}
424
425// set utf8 to true if input is in utf-8, otherwise expects input in unicode
426text_t minus_safe (const text_t &intext, bool utf8) {
427
428  text_t outtext;
429
430  text_t::const_iterator here = intext.begin ();
431  text_t::const_iterator end = intext.end ();
432
433  while (here != end) {
434    if (*here == '-') outtext += "Zz-";
435    else outtext.push_back (*here);
436    ++here;
437  }
438  if (utf8) {
439    outtext = cgi_safe_utf8 (outtext);
440  } else {
441    outtext = cgi_safe_unicode (outtext);
442  }
443  return outtext;
444}
445
446// takes utf-8 input
447text_t cgi_safe_utf8 (const text_t &intext) {
448  text_t outtext;
449 
450  text_t::const_iterator here = intext.begin ();
451  text_t::const_iterator end = intext.end ();
452  unsigned short c;
453  text_t ttmp;
454 
455  while (here != end) {
456    c = *here;
457    if (((c >= 'a') && (c <= 'z')) ||
458    ((c >= 'A') && (c <= 'Z')) ||
459    ((c >= '0') && (c <= '9')) ||
460    (c == '%') || (c == '-')) {
461      // alphanumeric character
462      outtext.push_back(c);
463    } else if (c == ' ') {
464      // space
465      outtext.push_back('+');
466    } else if (c > 255) { // not utf-8 character
467      cerr << "WARNING: expected utf-8 char, but got unicode!!\n";
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// takes unicode input
481text_t cgi_safe_unicode (const text_t &intext) {
482  text_t outtext;
483 
484  text_t::const_iterator here = intext.begin ();
485  text_t::const_iterator end = intext.end ();
486  unsigned short c;
487  text_t ttmp;
488 
489  while (here != end) {
490    c = *here;
491    if (((c >= 'a') && (c <= 'z')) ||
492    ((c >= 'A') && (c <= 'Z')) ||
493    ((c >= '0') && (c <= '9')) ||
494    (c == '%') || (c == '-')) {
495      // alphanumeric character
496      outtext.push_back(c);
497    } else if (c == ' ') {
498      // space
499      outtext.push_back('+');
500    } else if (c > 127) { // unicode character
501      unsigned char buf[3]; // up to 3 bytes
502      buf[0]='\0';buf[1]='\0';buf[2]='\0';
503      output_utf8_char(c,buf, buf+2);
504      outtext.push_back('%');
505      c2hex(buf[0], ttmp);
506      outtext += ttmp;
507      outtext.push_back('%');
508      c2hex(buf[1], ttmp);
509      outtext += ttmp;
510      if (buf[2]) {
511      outtext.push_back('%');
512      c2hex(buf[2], ttmp);
513      outtext += ttmp;
514      }
515    } else {
516      // everything else
517      outtext.push_back('%');
518      c2hex(c, ttmp);
519      outtext += ttmp;
520    }
521   
522    ++here;
523  }
524 
525  return outtext;
526}
527
528
529
530
531static text_t::const_iterator get_next_save_arg (text_t::const_iterator first,
532                       text_t::const_iterator last,
533                       text_t &argname) {
534  first = getdelimitstr (first, last, '-', argname);
535  return first;
536}
537
538
539// check_save_conf_str checks the configuration string for
540// the saved args and makes sure it does not conflict with
541// the information about the arguments. If an error is encountered
542// it will return false and the program should not produce any
543// output.
544bool check_save_conf_str (const text_t &saveconf,
545              const cgiargsinfoclass &argsinfo,
546              ostream &logout) {
547  outconvertclass text_t2ascii;
548
549  text_tset argsset;
550  text_t::const_iterator saveconfhere = saveconf.begin ();
551  text_t::const_iterator saveconfend = saveconf.end ();
552  text_t argname;
553  const cgiarginfo *info;
554
555  // first check to make sure all saved arguments can be saved
556 
557  while (saveconfhere != saveconfend) {
558    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
559
560    if (!argname.empty()) {
561      // save the argument name for later
562      argsset.insert (argname);
563
564      // check the argument
565      info =  argsinfo.getarginfo (argname);
566      if (info == NULL) {
567    logout << text_t2ascii << "Error: the cgi argument \"" << argname
568           << "\" is used in the configuration string for the\n"
569           << "saved arguments but does not exist as a valid argument.\n\n";
570    return false;
571      }
572      if (info->savedarginfo == cgiarginfo::mustnot) {
573    logout << text_t2ascii << "Error: the cgi argument \"" << argname
574           << "\" is used in the configuration string for the\n"
575           << "saved arguments but has been specified as an argument whose\n"
576           << "state must not be saved.\n\n";
577    return false;
578      }
579    }
580  }
581
582
583  // next check that all saved arguments that should be saved
584  // are saved
585  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
586  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
587
588  while (argsinfohere != argsinfoend) {
589    if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
590    (argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
591      logout << text_t2ascii << "Error: the cgi argument \""
592         << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
593         << "be save but was not listed in the saved arguments.\n\n";
594      return false;
595    }
596
597    ++argsinfohere;
598  }
599 
600  return true; // made it, no clashes
601}
602
603
604// create_save_conf_str will create a configuration string
605// based on the information in argsinfo. This method of configuration
606// is not recomended as small changes can produce large changes in
607// the resulting configuration string (for instance a totally different
608// ordering). Only arguments which "must" be saved are included in
609// the resulting string.
610text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
611                 ostream &/*logout*/) {
612  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
613  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
614  text_t saveconf;
615  bool first = true;
616
617  while (argsinfohere != argsinfoend) {
618    // save this argument if it must be saved
619    if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
620      if (!first) saveconf.push_back ('-');
621      else first = false;
622      saveconf += (*argsinfohere).second.shortname;
623    }
624
625    ++argsinfohere;
626  }
627 
628  return saveconf;
629}
630
631
632// expand_save_args will expand the saved arguments based
633// on saveconf placing the results in args if they are not
634// already defined. If it encounters an error it will return false
635// and output more information to logout.
636bool expand_save_args (const cgiargsinfoclass &argsinfo,
637               const text_t &saveconf,
638               cgiargsclass &args,
639               ostream &logout) {
640  outconvertclass text_t2ascii;
641
642  text_t *arg_e = args.getarg("e");
643  if (arg_e == NULL) return true; // no compressed arguments
644  if (arg_e->empty()) return true; // no compressed arguments
645
646  text_t argname, argvalue;
647  const cgiarginfo *argnameinfo;
648 
649  text_t::const_iterator saveconfhere = saveconf.begin();
650  text_t::const_iterator saveconfend = saveconf.end();
651 
652  text_t::iterator arg_ebegin = arg_e->begin();
653  text_t::iterator arg_eend = arg_e->end();
654  text_t::iterator arg_ehere = arg_ebegin;
655  while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
656    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
657
658    if (!argname.empty()) {
659      // found another entry
660      argnameinfo = argsinfo.getarginfo (argname);
661
662      if (argnameinfo == NULL) {
663    // no information about the argument could be found
664    // we can't keep going because we don't know whether
665    // this argument is a single or multiple character value
666    logout << text_t2ascii << "Error: the cgi argument \"" << argname
667           << "\" was specified as being a compressed argument\n"
668           << "but no information about it could be found within the "
669           << "cgiargsinfoclass.\n";
670    return false;
671
672      } else {
673
674    // found the argument information
675    if (argnameinfo->multiplechar) {
676      text_t::const_iterator sav = arg_ehere;
677      arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
678      if (distance(arg_ebegin, arg_ehere) > 2) {
679        // replace any '-' chars escaped with 'Zz'
680        bool first = true;
681        while ((*(arg_ehere-3) == 'Z') && (*(arg_ehere-2) == 'z')) {
682          if (first) argvalue.clear();
683
684          // Hey, here's a wild idea. Why don't we check that there is
685          // another hyphen in the cgiarge before we get a pointer to it and
686          // add one. That way we are far less likely to wander off into
687          // random memory merrily parsing arguments that are then lovingly
688          // spewed all over the HTML page returned at the usage logs.
689          text_t::iterator minus_itr = findchar (arg_ehere, arg_eend, '-');
690          if (minus_itr == arg_eend)
691          {
692        logout << text_t2ascii << "Error: the cgi argument \"" << argname << "\" was specified as being a compressed argument but we have run out of cgiarge to decompress!\n";
693        return false;             
694          }
695          arg_ehere = minus_itr + 1;
696
697          while (sav != (arg_ehere-1)) {
698        if (!((*sav == 'Z') && (*(sav+1) == 'z') && (*(sav+2) == '-')) &&
699            !((*(sav-1) == 'Z') && (*sav == 'z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
700        ++sav;
701          }
702          first = false;
703        }
704      }
705      argvalue.setencoding(1); // other encoding
706      if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
707    } else {
708      args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
709      ++arg_ehere;
710    }
711      }
712    }
713  }
714
715  return true;
716}
717
718
719// adds the default values for those arguments which have not
720// been specified
721void add_default_args (const cgiargsinfoclass &argsinfo,
722               cgiargsclass &args,
723               ostream &/*logout*/) {
724  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
725  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
726
727  while (argsinfohere != argsinfoend) {
728    if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
729      args.setdefaultarg ((*argsinfohere).second.shortname,
730              (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
731    }
732    ++argsinfohere;
733  }
734}
735
736void add_fileupload_args (const cgiargsinfoclass &argsinfo,
737              cgiargsclass &args,
738              fileupload_tmap &fileuploads,
739              ostream &logout) {
740 
741  const cgiarginfo *info = argsinfo.getarginfo("a");
742  fileupload_tmap::const_iterator this_file = fileuploads.begin();
743  fileupload_tmap::const_iterator end_file = fileuploads.end();
744  while (this_file != end_file) {
745    const cgiarginfo *info = argsinfo.getarginfo((*this_file).first);
746    if (info != NULL) {
747
748      if ((*info).fileupload && (file_exists((*this_file).second.tmp_name))) {
749
750    args.setargfile((*this_file).first, (*this_file).second);
751      }
752    }
753    this_file++;
754  }
755}
756
757// compress_save_args will compress the arguments and return
758// them in compressed_args. If an error was encountered
759// compressed_args will be set to to "", an error will be
760// written to logout, and the function will return false.
761bool compress_save_args (const cgiargsinfoclass &argsinfo,
762             const text_t &saveconf,
763             cgiargsclass &args,
764             text_t &compressed_args,
765             outconvertclass &outconvert,
766             ostream &logout) {
767  outconvertclass text_t2ascii;
768
769  compressed_args.clear();
770
771  text_t argname, argvalue;
772  const cgiarginfo *argnameinfo;
773 
774  text_t::const_iterator saveconfhere = saveconf.begin();
775  text_t::const_iterator saveconfend = saveconf.end();
776 
777  while (saveconfhere != saveconfend) {
778    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
779
780    if (!argname.empty()) {
781      // found another entry
782      argnameinfo = argsinfo.getarginfo (argname);
783
784      if (argnameinfo == NULL) {
785    // no information about the argument could be found
786    // we can't keep going because we don't know whether
787    // this argument is a single or multiple character value
788    logout << text_t2ascii << "Error: the cgi argument \"" << argname
789           << "\" was specified as being a compressed argument\n"
790           << "but no information about it could be found within the "
791           << "cgiargsinfoclass.\n";
792    compressed_args.clear();
793    return false;
794
795      } else {
796    // found the argument information
797    if (argnameinfo->multiplechar) {
798      // multiple character argument -- sort out any '-' chars
799      if (args["w"]=="utf-16be") // browsers don't like \0 in urls...
800        compressed_args += minus_safe (args[argname], false);
801      else
802        compressed_args += minus_safe (outconvert.convert(args[argname]), true);
803     
804      if (saveconfhere != saveconfend) compressed_args.push_back ('-');
805
806    } else {
807      // single character argument
808      if (args[argname].size() == 0) {
809        logout << text_t2ascii << "Error: the cgi argument \"" << argname
810           << "\" was specified as being a compressed argument which\n"
811           << "should have a one character value but it was empty.\n\n";
812        compressed_args.clear ();
813        return false;
814
815      } else if (args[argname].size() > 1) {
816        logout << text_t2ascii << "Error: the cgi argument \"" << argname
817           << "\" was specified as being a compressed argument which\n"
818           << "should have a one character value but it had multiple characters.\n\n";
819        compressed_args.clear ();
820        return false;
821      }
822
823      // everything is ok
824      compressed_args += args[argname];
825    }
826      }
827    }
828  }
829
830  return true;
831}
832
833
834// args_tounicode converts any arguments which are not in unicode
835// to unicode using inconvert
836void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
837  cgiargsclass::iterator here = args.begin();
838  cgiargsclass::iterator end = args.end();
839
840  while (here != end) {
841    if ((*here).second.value.getencoding() > 0) {
842      // Call reset() before converting each argument, to prevent problems when converting the last
843      //   argument left the converter in a bad state
844      inconvert.reset();
845      (*here).second.value = inconvert.convert((*here).second.value);
846    }
847   
848    ++here;
849  }
850}
851
852// fcgienv will be loaded with environment name-value pairs
853// if using fastcgi (had to do this as getenv doesn't work
854// with our implementation of fastcgi). if fcgienv is empty
855// we'll simply use getenv
856text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv) {
857  if (fcgienv.empty()) {
858    char *n = name.getcstr();
859    char *v = getenv(n);
860    delete []n;
861    if (v != NULL) return v;
862    return g_EmptyText;
863
864  } else return fcgienv[name];
865}
Note: See TracBrowser for help on using the browser.