root/trunk/mapserver/cgiutil.c

Revision 7998, 11.2 kB (checked in by sdlime, 1 month ago)

Updated header notes crediting NCSA CGI sample code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  cgiRequestObj and CGI parameter parsing.
6  * Author:   Steve Lime and the MapServer team.
7  *
8  * Notes: Portions derived from NCSA HTTPd Server's example CGI programs (util.c).
9  *
10  ******************************************************************************
11  * Copyright (c) 1996-2005 Regents of the University of Minnesota.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies of this Software or works derived from this Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  ****************************************************************************/
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "cgiutil.h"
37 #include "mapserver.h"
38
39 MS_CVSID("$Id$")
40
41 #define LF 10
42 #define CR 13
43
44 static char *readPostBody( cgiRequestObj *request )
45 {
46   char *data;
47   int data_max, data_len, chunk_size;
48
49   msIO_needBinaryStdin();
50
51   /* -------------------------------------------------------------------- */
52   /*      If the length is provided, read in one gulp.                    */
53   /* -------------------------------------------------------------------- */
54   if( getenv("CONTENT_LENGTH") != NULL ) {
55     data_max = atoi(getenv("CONTENT_LENGTH"));
56     data = (char *) malloc(data_max+1);
57     if( data == NULL ) {
58       msIO_printf("Content-type: text/html%c%c",10,10);
59       msIO_printf("malloc() failed, Content-Length: %d unreasonably large?\n", data_max );
60       exit( 1 );
61     }
62
63     if( (int) msIO_fread(data, 1, data_max, stdin) < data_max ) {
64       msIO_printf("Content-type: text/html%c%c",10,10);
65       msIO_printf("POST body is short\n");
66       exit(1);
67     }
68
69     data[data_max] = '\0';
70     return data;
71   }
72
73   /* -------------------------------------------------------------------- */
74   /*      Otherwise read in chunks to the end.                            */
75   /* -------------------------------------------------------------------- */
76   data_max = 10000;
77   data_len = 0;
78   data = (char *) malloc(data_max+1);
79
80   while( (chunk_size = msIO_fread( data + data_len, 1, data_max-data_len, stdin )) > 0 ) {
81     data_len += chunk_size;
82
83     if( data_len == data_max ) {
84       data_max = data_max + 10000;
85       data = (char *) realloc(data, data_max+1);
86
87       if( data == NULL ) {
88         msIO_printf("Content-type: text/html%c%c",10,10);
89         msIO_printf("out of memory trying to allocate %d input buffer, POST body too large?\n", data_max+1 );
90         exit(1);
91       }
92     }
93   }
94
95   data[data_len] = '\0'
96   return data;
97 }
98
99 int loadParams(cgiRequestObj *request) {
100   register int x,m=0;
101   char *s;
102   int debuglevel;
103
104   if(getenv("REQUEST_METHOD")==NULL) {
105     msIO_printf("This script can only be used to decode form results and \n");
106     msIO_printf("should be initiated as a CGI process via a httpd server.\n");
107     exit(0);
108   }
109
110   debuglevel = (int)msGetGlobalDebugLevel();
111
112   if(strcmp(getenv("REQUEST_METHOD"),"POST") == 0) { /* we've got a post from a form */     
113     char *post_data;
114
115     request->type = MS_POST_REQUEST;
116
117     s = getenv("CONTENT_TYPE");
118     if (s != NULL)
119       request->contenttype = strdup(s);
120      /* we've to set default content-type which is
121       * application/octet-stream according to
122       * W3 RFC 2626 section 7.2.1 */
123     else request->contenttype = strdup("application/octet-stream");
124
125     post_data = readPostBody( request );
126     if(strcmp(request->contenttype, "application/x-www-form-urlencoded"))
127       request->postrequest = post_data;
128     else {
129       int data_len = strlen(post_data);
130       while( data_len > 0 && isspace(post_data[data_len-1]) )
131         post_data[--data_len] = '\0';
132
133       while( post_data[0] ) {
134         if(m >= MS_MAX_CGI_PARAMS) {
135           msIO_printf("Too many name/value pairs, aborting.\n");
136           exit(0);
137         }
138
139         request->ParamValues[m] = makeword(post_data,'&');
140         plustospace(request->ParamValues[m]);
141         unescape_url(request->ParamValues[m]);
142         request->ParamNames[m] = makeword(request->ParamValues[m],'=');
143         m++;
144       }
145       free( post_data );
146     }
147
148     /* check the QUERY_STRING even in the post request since it can contain
149        information. Eg a wfs request with  */
150     s = getenv("QUERY_STRING");
151     if(s) {
152       if (debuglevel >= MS_DEBUGLEVEL_DEBUG)
153                   msDebug("loadParams() QUERY_STRING: %s\n", s);
154
155       for(x=0;s[0] != '\0';x++) {       
156         if(m >= MS_MAX_CGI_PARAMS) {
157           msIO_printf("Too many name/value pairs, aborting.\n");
158           exit(0);
159         }
160         request->ParamValues[m] = makeword(s,'&');
161         plustospace(request->ParamValues[m]);
162         unescape_url(request->ParamValues[m]);
163         request->ParamNames[m] = makeword(request->ParamValues[m],'=');
164         m++;
165       }
166     }     
167   } else {
168     if(strcmp(getenv("REQUEST_METHOD"),"GET") == 0) { /* we've got a get request */
169       request->type = MS_GET_REQUEST;
170
171       s = getenv("QUERY_STRING");
172       if(s == NULL) {
173         msIO_printf("Content-type: text/html%c%c",10,10);
174         msIO_printf("No query information to decode. QUERY_STRING not set.\n");
175         exit(1);
176       }
177
178           if (debuglevel >= MS_DEBUGLEVEL_DEBUG)
179                   msDebug("loadParams() QUERY_STRING: %s\n", s);
180
181       if(strlen(s)==0) {
182         msIO_printf("Content-type: text/html%c%c",10,10);
183         msIO_printf("No query information to decode. QUERY_STRING is set, but empty.\n");
184         exit(1);
185       }
186
187       for(x=0;s[0] != '\0';x++) {       
188         if(m >= MS_MAX_CGI_PARAMS) {
189           msIO_printf("Too many name/value pairs, aborting.\n");
190           exit(0);
191         }
192         request->ParamValues[m] = makeword(s,'&');
193         plustospace(request->ParamValues[m]);
194         unescape_url(request->ParamValues[m]);
195         request->ParamNames[m] = makeword(request->ParamValues[m],'=');
196         m++;
197       }
198     } else {
199       msIO_printf("Content-type: text/html%c%c",10,10);
200       msIO_printf("This script should be referenced with a METHOD of GET or METHOD of POST.\n");
201       exit(1);
202     }
203   }
204
205   /* check for any available cookies */
206   s = getenv("HTTP_COOKIE");
207   if(s != NULL) {
208     request->httpcookiedata = strdup(s);
209     for(x=0;s[0] != '\0';x++) {
210       if(m >= MS_MAX_CGI_PARAMS) {
211         msIO_printf("Too many name/value pairs, aborting.\n");
212         exit(0);
213       }
214       request->ParamValues[m] = makeword(s,';');
215       plustospace(request->ParamValues[m]);
216       unescape_url(request->ParamValues[m]);
217       request->ParamNames[m] = makeword_skip(request->ParamValues[m],'=',' ');
218       m++;
219     }
220   }
221
222   return(m);
223 }
224
225 void getword(char *word, char *line, char stop) {
226   int x = 0,y;
227
228   for(x=0;((line[x]) && (line[x] != stop));x++)
229     word[x] = line[x];
230
231   word[x] = '\0';
232   if(line[x]) ++x;
233   y=0;
234
235   while((line[y++] = line[x++]));
236 }
237
238 char *makeword_skip(char *line, char stop, char skip) {
239   int x = 0,y,offset=0;
240   char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
241
242   for(x=0;((line[x]) && (line[x] == skip));x++);
243   offset = x;
244
245   for(x=offset;((line[x]) && (line[x] != stop));x++)
246     word[x-offset] = line[x];
247
248   word[x-offset] = '\0';
249   if(line[x]) ++x;
250   y=0;
251
252   while((line[y++] = line[x++]));
253   return word;
254 }
255
256 char *makeword(char *line, char stop) {
257   int x = 0,y;
258   char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
259
260   for(x=0;((line[x]) && (line[x] != stop));x++)
261     word[x] = line[x];
262
263   word[x] = '\0';
264   if(line[x]) ++x;
265   y=0;
266
267   while((line[y++] = line[x++]));
268   return word;
269 }
270
271 char *fmakeword(FILE *f, char stop, int *cl) {
272   int wsize;
273   char *word;
274   int ll;
275
276   wsize = 102400;
277   ll=0;
278   word = (char *) malloc(sizeof(char) * (wsize + 1));
279
280   while(1) {
281     word[ll] = (char)fgetc(f);
282     if(ll==wsize) {
283       word[ll+1] = '\0';
284       wsize+=102400;
285       word = (char *)realloc(word,sizeof(char)*(wsize+1));
286     }
287     --(*cl);
288     if((word[ll] == stop) || (feof(f)) || (!(*cl))) {
289       if(word[ll] != stop) ll++;
290       word[ll] = '\0';
291             word = (char *) realloc(word, ll+1);
292       return word;
293     }
294     ++ll;
295   }
296 }
297
298 char x2c(char *what) {
299   register char digit;
300
301   digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
302   digit *= 16;
303   digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
304   return(digit);
305 }
306
307 void unescape_url(char *url) {
308   register int x,y;
309
310   for(x=0,y=0;url[y];++x,++y) {
311     if((url[x] = url[y]) == '%') {
312       url[x] = x2c(&url[y+1]);
313       y+=2;
314     }
315   }
316   url[x] = '\0';
317 }
318
319 void plustospace(char *str) {
320   register int x;
321
322   for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
323 }
324
325 int rind(char *s, char c) {
326   register int x;
327   for(x=strlen(s) - 1;x != -1; x--)
328     if(s[x] == c) return x;
329   return -1;
330 }
331
332 int _getline(char *s, int n, FILE *f) {
333   register int i=0;
334
335   while(1) {
336     s[i] = (char)fgetc(f);
337
338     if(s[i] == CR)
339       s[i] = fgetc(f);
340
341     if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) {
342       s[i] = '\0';
343       return (feof(f) ? 1 : 0);
344     }
345     ++i;
346   }
347 }
348
349 void send_fd(FILE *f, FILE *fd) {
350   char c;
351
352   while (1) {
353     c = fgetc(f);
354     if(feof(f))
355       return;
356     fputc(c,fd);
357   }
358 }
359
360 int ind(char *s, char c) {
361   register int x;
362
363   for(x=0;s[x];x++)
364     if(s[x] == c) return x;
365
366   return -1;
367 }
368
369 /*
370 ** patched version according to CERT advisory...
371 */
372 void escape_shell_cmd(char *cmd) {
373   register int x,y,l;
374
375   l=strlen(cmd);
376   for(x=0;cmd[x];x++) {
377     if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1) {
378       for(y=l+1;y>x;y--)
379         cmd[y] = cmd[y-1];
380       l++; /* length has been increased */
381       cmd[x] = '\\';
382       x++; /* skip the character */
383     }
384   }
385 }
386
387 /*
388 ** Allocate a new request holder structure
389 */
390 cgiRequestObj *msAllocCgiObj() {
391   cgiRequestObj *request = (cgiRequestObj *)malloc(sizeof(cgiRequestObj));
392
393   if(!request)
394     return NULL;
395
396   request->ParamNames = NULL;
397   request->ParamValues = NULL;
398   request->NumParams = 0;
399   request->type = -1;
400   request->contenttype = NULL;
401   request->postrequest = NULL;
402   request->httpcookiedata = NULL;
403
404   return request;
405 }
406      
407 void msFreeCgiObj(cgiRequestObj *request) {
408   msFreeCharArray(request->ParamNames, request->NumParams);
409   msFreeCharArray(request->ParamValues, request->NumParams);
410   request->ParamNames = NULL;
411   request->ParamValues = NULL;
412   request->NumParams = 0;
413   request->type = -1;
414   msFree(request->contenttype);
415   msFree(request->postrequest);
416   msFree(request->httpcookiedata);
417   request->contenttype = NULL;
418   request->postrequest = NULL;
419   request->httpcookiedata = NULL;
420
421   msFree(request);
422 }
Note: See TracBrowser for help on using the browser.