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

Last change on this file since 491 was 474, checked in by sjboddie, 25 years ago

prevented cgi_safe from converting '+' and '-'. It was causing problems
with query strings containing spaces. The space was being converted
to '+', then %2b, then %xx2b over time when saved in compressed args.
I hope this won't cause problems elsewhere...

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