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

Last change on this file since 357 was 294, checked in by rjmcnab, 25 years ago

Added encoding and decoding of multibyte compresesd arguments.

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