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

Last change on this file since 671 was 614, checked in by sjboddie, 25 years ago

fixed a couple of problems in what I committed last

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 14.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 * $Id: cgiutils.cpp 614 1999-09-21 21:41:17Z sjboddie $
25 *
26 *********************************************************************/
27
28/*
29 $Log$
30 Revision 1.10 1999/09/21 21:41:17 sjboddie
31 fixed a couple of problems in what I committed last
32
33 Revision 1.9 1999/09/21 11:30:39 sjboddie
34 added ability to escape out '-' in saved args (currently
35 with a 'Z' ???)
36
37 Revision 1.8 1999/09/07 04:56:53 sjboddie
38 added GPL notice
39
40 Revision 1.7 1999/08/25 22:27:13 sjboddie
41 prevented cgi_safe from converting '+' and '-'. It was causing problems
42 with query strings containing spaces. The space was being converted
43 to '+', then %2b, then %xx2b over time when saved in compressed args.
44 I hope this won't cause problems elsewhere...
45
46 Revision 1.6 1999/07/11 01:05:19 rjmcnab
47 Stored origin of cgiarg with argument.
48
49 Revision 1.5 1999/06/26 01:08:36 rjmcnab
50 Added encoding and decoding of multibyte compresesd arguments.
51
52 Revision 1.4 1999/06/08 22:03:43 sjboddie
53 query string is now made cgi safe before being added to compressed args
54
55 Revision 1.3 1999/02/08 01:28:00 rjmcnab
56
57 Got the receptionist producing something using the statusaction.
58
59 Revision 1.2 1999/02/05 10:42:43 rjmcnab
60
61 Continued working on receptionist
62
63 Revision 1.1 1999/01/08 08:40:56 rjmcnab
64
65 Moved from lib directory.
66
67 Revision 1.1 1999/01/08 03:57:45 rjmcnab
68
69 Initial revision
70
71 */
72
73
74#include "cgiutils.h"
75
76
77static unsigned short hexdigit (unsigned short c) {
78 if (c >= '0' && c <= '9') return (c-'0');
79 if (c >= 'a' && c <= 'f') return (c-'a'+10);
80 if (c >= 'A' && c <= 'F') return (c-'A'+10);
81 return c;
82}
83
84
85static void c2hex (unsigned short c, text_t &t) {
86 t.clear();
87
88 if (c >= 256) {
89 t = "20"; // ' '
90 return;
91 }
92
93 unsigned short o1, o2;
94
95 o1 = (c/16) % 16;
96 o2 = c % 16;
97 if (o1 >= 10) o1 += 'a' - 10;
98 else o1 += '0';
99 if (o2 >= 10) o2 += 'a' - 10;
100 else o2 += '0';
101
102 t.push_back(o1);
103 t.push_back(o2);
104}
105
106// convert %xx and + to their appropriate equivalents
107void decode_cgi_arg (text_t &argstr) {
108 text_t::iterator in = argstr.begin();
109 text_t::iterator out = in;
110 text_t::iterator end = argstr.end();
111
112 while (in != end) {
113 if (*in == '+') *out = ' ';
114
115 else if (*in == '%') {
116 unsigned short c = '%';
117 in++;
118 if (in != end) {
119 c = hexdigit (*in);
120 in++;
121 }
122 if (in != end && c < 16) { // sanity check on the previous character
123 c = c*16 + hexdigit (*in);
124 }
125
126 *out = c;
127 } else *out = *in;
128
129 if (in != end) in++;
130 out++;
131 }
132
133 // remove the excess characters
134 argstr.erase (out, end);
135}
136
137
138// split up the cgi arguments
139void split_cgi_args (text_t argstr, cgiargsclass &args) {
140 args.clear();
141
142 text_t::iterator here = argstr.begin();
143 text_t::iterator end = argstr.end();
144 text_t key, value;
145
146 // extract out the key=value pairs
147 while (here != end) {
148 // get the next key and value pair
149 here = getdelimitstr (here, end, '=', key);
150 here = getdelimitstr (here, end, '&', value);
151
152 // convert %xx and + to their appropriate equivalents
153 decode_cgi_arg (value);
154
155 value.setencoding(1); // other encoding
156 // store this key=value pair
157 if (!key.empty()) args.setarg (key, value, cgiarg_t::cgi_arg);
158 }
159}
160
161text_t minus_safe (const text_t &intext) {
162
163 text_t outtext;
164
165 text_t::const_iterator here = intext.begin ();
166 text_t::const_iterator end = intext.end ();
167
168 while (here != end) {
169 if (*here == '-') outtext += "Z-";
170 else outtext.push_back (*here);
171 here ++;
172 }
173 outtext = cgi_safe (outtext);
174 return outtext;
175}
176
177text_t cgi_safe (const text_t &intext) {
178 text_t outtext;
179
180 text_t::const_iterator here = intext.begin ();
181 text_t::const_iterator end = intext.end ();
182 unsigned short c;
183 text_t ttmp;
184
185 while (here != end) {
186 c = *here;
187 if (((c >= 'a') && (c <= 'z')) ||
188 ((c >= 'A') && (c <= 'Z')) ||
189 ((c >= '0') && (c <= '9')) ||
190 (c == '+') || (c == '%') || (c == '-')) {
191 // alphanumeric character
192 outtext.push_back(c);
193 } else if (c == ' ') {
194 // space
195 outtext.push_back('+');
196 } else {
197 // everything else
198 outtext.push_back('%');
199 c2hex(c, ttmp);
200 outtext += ttmp;
201 }
202
203 here++;
204 }
205
206 return outtext;
207}
208
209
210
211
212static text_t::const_iterator get_next_save_arg (text_t::const_iterator first,
213 text_t::const_iterator last,
214 text_t &argname) {
215 first = getdelimitstr (first, last, '-', argname);
216 return first;
217}
218
219
220// check_save_conf_str checks the configuration string for
221// the saved args and makes sure it does not conflict with
222// the information about the arguments. If an error is encountered
223// it will return false and the program should not produce any
224// output.
225bool check_save_conf_str (const text_t &saveconf,
226 const cgiargsinfoclass &argsinfo,
227 ostream &logout) {
228 outconvertclass text_t2ascii;
229
230 text_tset argsset;
231 text_t::const_iterator saveconfhere = saveconf.begin ();
232 text_t::const_iterator saveconfend = saveconf.end ();
233 text_t argname;
234 const cgiarginfo *info;
235
236 // first check to make sure all saved arguments can be saved
237
238 while (saveconfhere != saveconfend) {
239 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
240
241 if (!argname.empty()) {
242 // save the argument name for later
243 argsset.insert (argname);
244
245 // check the argument
246 info = argsinfo.getarginfo (argname);
247 if (info == NULL) {
248 logout << text_t2ascii << "Error: the cgi argument \"" << argname
249 << "\" is used in the configuration string for the\n"
250 << "saved arguments but does not exist as a valid argument.\n\n";
251 return false;
252 }
253 if (info->savedarginfo == cgiarginfo::mustnot) {
254 logout << text_t2ascii << "Error: the cgi argument \"" << argname
255 << "\" is used in the configuration string for the\n"
256 << "saved arguments but has been specified as an argument whose\n"
257 << "state must not be saved.\n\n";
258 return false;
259 }
260 }
261 }
262
263
264 // next check that all saved arguments that should be saved
265 // are saved
266 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
267 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
268
269 while (argsinfohere != argsinfoend) {
270 if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
271 (argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
272 logout << text_t2ascii << "Error: the cgi argument \""
273 << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
274 << "be save but was not listed in the saved arguments.\n\n";
275 return false;
276 }
277
278 argsinfohere++;
279 }
280
281 return true; // made it, no clashes
282}
283
284
285// create_save_conf_str will create a configuration string
286// based on the information in argsinfo. This method of configuration
287// is not recomended as small changes can produce large changes in
288// the resulting configuration string (for instance a totally different
289// ordering). Only arguments which "must" be saved are included in
290// the resulting string.
291text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
292 ostream &/*logout*/) {
293 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
294 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
295 text_t saveconf;
296 bool first = true;
297
298 while (argsinfohere != argsinfoend) {
299 // save this argument if it must be saved
300 if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
301 if (!first) saveconf.push_back ('-');
302 else first = false;
303 saveconf += (*argsinfohere).second.shortname;
304 }
305
306 argsinfohere++;
307 }
308
309 return saveconf;
310}
311
312
313// expand_save_args will expand the saved arguments based
314// on saveconf placing the results in args if they are not
315// already defined. If it encounters an error it will return false
316// and output more information to logout.
317bool expand_save_args (const cgiargsinfoclass &argsinfo,
318 const text_t &saveconf,
319 cgiargsclass &args,
320 ostream &logout) {
321 outconvertclass text_t2ascii;
322
323 text_t *arg_e = args.getarg("e");
324 if (arg_e == NULL) return true; // no compressed arguments
325 if (arg_e->empty()) return true; // no compressed arguments
326
327 text_t argname, argvalue;
328 const cgiarginfo *argnameinfo;
329
330 text_t::const_iterator saveconfhere = saveconf.begin();
331 text_t::const_iterator saveconfend = saveconf.end();
332
333 text_t::iterator arg_ehere = arg_e->begin();
334 text_t::iterator arg_eend = arg_e->end();
335 while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
336 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
337
338 if (!argname.empty()) {
339 // found another entry
340 argnameinfo = argsinfo.getarginfo (argname);
341
342 if (argnameinfo == NULL) {
343 // no information about the argument could be found
344 // we can't keep going because we don't know whether
345 // this argument is a single or multiple character value
346 logout << text_t2ascii << "Error: the cgi argument \"" << argname
347 << "\" was specified as being a compressed argument\n"
348 << "but no information about it could be found within the "
349 << "cgiargsinfoclass.\n";
350 return false;
351
352 } else {
353
354 // found the argument information
355 if (argnameinfo->multiplechar) {
356 text_t::const_iterator sav = arg_ehere;
357 arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
358 // replace any '-' chars escaped with 'Z'
359 if (*(arg_ehere-2) == 'Z') {
360 argvalue.clear();
361 arg_ehere = (findchar (arg_ehere, arg_eend, '-')) + 1;
362 while (sav != (arg_ehere-1)) {
363 if (!((*sav == 'Z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
364 sav ++;
365 }
366 }
367
368 argvalue.setencoding(1); // other encoding
369 if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
370 } else {
371 args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
372 arg_ehere++;
373 }
374 }
375 }
376 }
377
378 return true;
379}
380
381
382// adds the default values for those arguments which have not
383// been specified
384void add_default_args (const cgiargsinfoclass &argsinfo,
385 cgiargsclass &args,
386 ostream &/*logout*/) {
387 cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
388 cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
389
390 while (argsinfohere != argsinfoend) {
391 if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
392 args.setdefaultarg ((*argsinfohere).second.shortname,
393 (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
394 }
395 argsinfohere++;
396 }
397}
398
399
400// compress_save_args will compress the arguments and return
401// them in compressed_args. If an error was encountered
402// compressed_args will be set to to "", an error will be
403// written to logout, and the function will return false.
404bool compress_save_args (const cgiargsinfoclass &argsinfo,
405 const text_t &saveconf,
406 cgiargsclass &args,
407 text_t &compressed_args,
408 outconvertclass &outconvert,
409 ostream &logout) {
410 outconvertclass text_t2ascii;
411
412 compressed_args.clear();
413
414 text_t argname, argvalue;
415 const cgiarginfo *argnameinfo;
416
417 text_t::const_iterator saveconfhere = saveconf.begin();
418 text_t::const_iterator saveconfend = saveconf.end();
419
420 while (saveconfhere != saveconfend) {
421 saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
422
423 if (!argname.empty()) {
424 // found another entry
425 argnameinfo = argsinfo.getarginfo (argname);
426
427 if (argnameinfo == NULL) {
428 // no information about the argument could be found
429 // we can't keep going because we don't know whether
430 // this argument is a single or multiple character value
431 logout << text_t2ascii << "Error: the cgi argument \"" << argname
432 << "\" was specified as being a compressed argument\n"
433 << "but no information about it could be found within the "
434 << "cgiargsinfoclass.\n";
435 compressed_args.clear();
436 return false;
437
438 } else {
439 // found the argument information
440 if (argnameinfo->multiplechar) {
441 // multiple character argument -- sort out any '-' chars
442 compressed_args += minus_safe (outconvert.convert(args[argname]));
443 if (saveconfhere != saveconfend) compressed_args.push_back ('-');
444
445 } else {
446 // single character argument
447 if (args[argname].size() == 0) {
448 logout << text_t2ascii << "Error: the cgi argument \"" << argname
449 << "\" was specified as being a compressed argument which\n"
450 << "should have a one character value but it was empty.\n\n";
451 compressed_args.clear ();
452 return false;
453
454 } else if (args[argname].size() > 1) {
455 logout << text_t2ascii << "Error: the cgi argument \"" << argname
456 << "\" was specified as being a compressed argument which\n"
457 << "should have a one character value but it had multiple characters.\n\n";
458 compressed_args.clear ();
459 return false;
460 }
461
462 // everything is ok
463 compressed_args += args[argname];
464 }
465 }
466 }
467 }
468
469 return true;
470}
471
472
473// args_tounicode converts any arguments which are not in unicode
474// to unicode using inconvert
475void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
476 cgiargsclass::iterator here = args.begin();
477 cgiargsclass::iterator end = args.end();
478
479 while (here != end) {
480 if ((*here).second.value.getencoding() > 0) {
481 (*here).second.value = inconvert.convert((*here).second.value);
482 }
483
484 here++;
485 }
486}
Note: See TracBrowser for help on using the repository browser.