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

Last change on this file since 241 was 155, checked in by rjmcnab, 25 years ago

Got the receptionist producing something using the statusaction.

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