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

Last change on this file since 411 was 366, checked in by rjmcnab, 25 years ago

Stored origin of cgiarg with argument.

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