]>
git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/var.c
5c55af741413ddaed3ee369bb1923c9103a9d867
2 * "$Id: var.c 177 2006-06-21 00:20:03Z jlovell $"
4 * CGI form variable and array functions.
6 * Copyright 1997-2005 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * cgiCheckVariables() - Check for the presence of "required" variables.
27 * cgiGetArray() - Get an element from a form array...
28 * cgiGetFile() - Get the file (if any) that was submitted in the form.
29 * cgiGetSize() - Get the size of a form array value.
30 * cgiGetVariable() - Get a CGI variable from the database...
31 * cgiInitialize() - Initialize the CGI variable "database"...
32 * cgiIsPOST() - Determine whether this page was POSTed.
33 * cgiSetArray() - Set array element N to the specified string.
34 * cgiSetSize() - Set the array size.
35 * cgiSetVariable() - Set a CGI variable in the database...
36 * cgi_add_variable() - Add a form variable.
37 * cgi_compare_variables() - Compare two variables.
38 * cgi_find_variable() - Find a variable...
39 * cgi_initialize_get() - Initialize form variables using the GET method.
40 * cgi_initialize_multipart() - Initialize variables and file using the POST method.
41 * cgi_initialize_post() - Initialize variables using the POST method.
42 * cgi_initialize_string() - Initialize form variables from a string.
43 * cgi_passwd() - Catch authentication requests and notify the server.
44 * cgi_sort_variables() - Sort all form variables for faster lookup.
45 * cgi_unlink_file() - Remove the uploaded form.
49 #include "cgi-private.h"
54 * Data structure to hold all the CGI form variables and arrays...
57 typedef struct /**** Form variable structure ****/
59 const char *name
; /* Name of variable */
60 int nvalues
, /* Number of values */
61 avalues
; /* Number of values allocated */
62 const char **values
; /* Value(s) of variable */
70 static int form_count
= 0, /* Form variable count */
71 form_alloc
= 0; /* Number of variables allocated */
72 static _cgi_var_t
*form_vars
= NULL
;
74 static cgi_file_t
*form_file
= NULL
;
82 static void cgi_add_variable(const char *name
, int element
,
84 static int cgi_compare_variables(const _cgi_var_t
*v1
,
85 const _cgi_var_t
*v2
);
86 static _cgi_var_t
*cgi_find_variable(const char *name
);
87 static int cgi_initialize_get(void);
88 static int cgi_initialize_multipart(const char *boundary
);
89 static int cgi_initialize_post(void);
90 static int cgi_initialize_string(const char *data
);
91 static const char *cgi_passwd(const char *prompt
);
92 static void cgi_sort_variables(void);
93 static void cgi_unlink_file(void);
97 * 'cgiCheckVariables()' - Check for the presence of "required" variables.
99 * Names may be separated by spaces and/or commas.
102 int /* O - 1 if all variables present, 0 otherwise */
103 cgiCheckVariables(const char *names
) /* I - Variables to look for */
105 char name
[255], /* Current variable name */
106 *s
; /* Pointer in string */
107 const char *val
; /* Value of variable */
108 int element
; /* Array element number */
114 while (*names
!= '\0')
116 while (*names
== ' ' || *names
== ',')
119 for (s
= name
; *names
!= '\0' && *names
!= ' ' && *names
!= ','; s
++, names
++)
126 if ((s
= strrchr(name
, '-')) != NULL
)
129 element
= atoi(s
+ 1) - 1;
130 val
= cgiGetArray(name
, element
);
133 val
= cgiGetVariable(name
);
139 return (0); /* Can't be blank, either! */
147 * 'cgiGetArray()' - Get an element from a form array...
150 const char * /* O - Element value or NULL */
151 cgiGetArray(const char *name
, /* I - Name of array variable */
152 int element
) /* I - Element number (0 to N) */
154 _cgi_var_t
*var
; /* Pointer to variable */
157 if ((var
= cgi_find_variable(name
)) == NULL
)
160 if (var
->nvalues
== 1)
161 return (var
->values
[0]);
163 if (element
< 0 || element
>= var
->nvalues
)
166 return (var
->values
[element
]);
171 * 'cgiGetFile()' - Get the file (if any) that was submitted in the form.
174 const cgi_file_t
* /* O - Attached file or NULL */
182 * 'cgiGetSize()' - Get the size of a form array value.
185 int /* O - Number of elements */
186 cgiGetSize(const char *name
) /* I - Name of variable */
188 _cgi_var_t
*var
; /* Pointer to variable */
191 if ((var
= cgi_find_variable(name
)) == NULL
)
194 return (var
->nvalues
);
199 * 'cgiGetVariable()' - Get a CGI variable from the database...
201 * Returns NULL if the variable doesn't exist. If the variable is an
202 * array of values, returns the last element...
205 const char * /* O - Value of variable */
206 cgiGetVariable(const char *name
) /* I - Name of variable */
208 const _cgi_var_t
*var
; /* Returned variable */
211 var
= cgi_find_variable(name
);
215 printf("cgiGetVariable(\"%s\") is returning NULL...\n", name
);
217 printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name
,
218 var
->values
[var
->nvalues
- 1]);
221 return ((var
== NULL
) ? NULL
: var
->values
[var
->nvalues
- 1]);
226 * 'cgiInitialize()' - Initialize the CGI variable "database"...
229 int /* O - Non-zero if there was form data */
232 const char *method
; /* Form posting method */
233 const char *content_type
; /* Content-Type of post data */
237 * Setup a password callback for authentication...
240 cupsSetPasswordCB(cgi_passwd
);
243 * Set the locale so that times, etc. are formatted properly...
246 setlocale(LC_ALL
, "");
250 * Disable output buffering to find bugs...
253 setbuf(stdout
, NULL
);
254 puts("Content-type: text/plain\n");
258 * Get the request method (GET or POST)...
261 method
= getenv("REQUEST_METHOD");
262 content_type
= getenv("CONTENT_TYPE");
267 * Grab form data from the corresponding location...
270 if (!strcasecmp(method
, "GET"))
271 return (cgi_initialize_get());
272 else if (!strcasecmp(method
, "POST") && content_type
)
274 const char *boundary
= strstr(content_type
, "boundary=");
279 if (content_type
&& !strncmp(content_type
, "multipart/form-data; ", 21))
280 return (cgi_initialize_multipart(boundary
));
282 return (cgi_initialize_post());
290 * 'cgiIsPOST()' - Determine whether this page was POSTed.
293 int /* O - 1 if POST, 0 if GET */
296 const char *method
; /* REQUEST_METHOD environment variable */
299 if ((method
= getenv("REQUEST_METHOD")) == NULL
)
302 return (!strcmp(method
, "POST"));
307 * 'cgiSetArray()' - Set array element N to the specified string.
309 * If the variable array is smaller than (element + 1), the intervening
310 * elements are set to NULL.
314 cgiSetArray(const char *name
, /* I - Name of variable */
315 int element
, /* I - Element number (0 to N) */
316 const char *value
) /* I - Value of variable */
318 int i
; /* Looping var */
319 _cgi_var_t
*var
; /* Returned variable */
322 if (name
== NULL
|| value
== NULL
|| element
< 0 || element
> 100000)
325 if ((var
= cgi_find_variable(name
)) == NULL
)
327 cgi_add_variable(name
, element
, value
);
328 cgi_sort_variables();
332 if (element
>= var
->avalues
)
334 var
->avalues
= element
+ 16;
335 var
->values
= (const char **)realloc((void *)(var
->values
),
336 sizeof(char *) * var
->avalues
);
339 if (element
>= var
->nvalues
)
341 for (i
= var
->nvalues
; i
< element
; i
++)
342 var
->values
[i
] = NULL
;
344 var
->nvalues
= element
+ 1;
346 else if (var
->values
[element
])
347 free((char *)var
->values
[element
]);
349 var
->values
[element
] = strdup(value
);
355 * 'cgiSetSize()' - Set the array size.
359 cgiSetSize(const char *name
, /* I - Name of variable */
360 int size
) /* I - Number of elements (0 to N) */
362 int i
; /* Looping var */
363 _cgi_var_t
*var
; /* Returned variable */
366 if (name
== NULL
|| size
< 0 || size
> 100000)
369 if ((var
= cgi_find_variable(name
)) == NULL
)
372 if (size
>= var
->avalues
)
374 var
->avalues
= size
+ 16;
375 var
->values
= (const char **)realloc((void *)(var
->values
),
376 sizeof(char *) * var
->avalues
);
379 if (size
> var
->nvalues
)
381 for (i
= var
->nvalues
; i
< size
; i
++)
382 var
->values
[i
] = NULL
;
384 else if (size
< var
->nvalues
)
386 for (i
= size
; i
< var
->nvalues
; i
++)
388 free((void *)(var
->values
[i
]));
396 * 'cgiSetVariable()' - Set a CGI variable in the database...
398 * If the variable is an array, this truncates the array to a single element.
402 cgiSetVariable(const char *name
, /* I - Name of variable */
403 const char *value
) /* I - Value of variable */
405 int i
; /* Looping var */
406 _cgi_var_t
*var
; /* Returned variable */
409 if (name
== NULL
|| value
== NULL
)
412 if ((var
= cgi_find_variable(name
)) == NULL
)
414 cgi_add_variable(name
, 0, value
);
415 cgi_sort_variables();
419 for (i
= 0; i
< var
->nvalues
; i
++)
421 free((char *)var
->values
[i
]);
423 var
->values
[0] = strdup(value
);
430 * 'cgi_add_variable()' - Add a form variable.
434 cgi_add_variable(const char *name
, /* I - Variable name */
435 int element
, /* I - Array element number */
436 const char *value
) /* I - Variable value */
438 _cgi_var_t
*var
; /* New variable */
441 if (name
== NULL
|| value
== NULL
|| element
< 0 || element
> 100000)
445 printf("Adding variable \'%s\' with value \'%s\'...\n", name
, value
);
448 if (form_count
>= form_alloc
)
451 form_vars
= malloc(sizeof(_cgi_var_t
) * 16);
453 form_vars
= realloc(form_vars
, (form_alloc
+ 16) * sizeof(_cgi_var_t
));
458 var
= form_vars
+ form_count
;
459 var
->name
= strdup(name
);
460 var
->nvalues
= element
+ 1;
461 var
->avalues
= element
+ 1;
462 var
->values
= calloc(element
+ 1, sizeof(char *));
463 var
->values
[element
] = strdup(value
);
470 * 'cgi_compare_variables()' - Compare two variables.
473 static int /* O - Result of comparison */
474 cgi_compare_variables(
475 const _cgi_var_t
*v1
, /* I - First variable */
476 const _cgi_var_t
*v2
) /* I - Second variable */
478 return (strcasecmp(v1
->name
, v2
->name
));
483 * 'cgi_find_variable()' - Find a variable...
486 static _cgi_var_t
* /* O - Variable pointer or NULL */
487 cgi_find_variable(const char *name
) /* I - Name of variable */
489 _cgi_var_t key
; /* Search key */
492 if (form_count
< 1 || name
== NULL
)
497 return ((_cgi_var_t
*)bsearch(&key
, form_vars
, form_count
, sizeof(_cgi_var_t
),
498 (int (*)(const void *, const void *))cgi_compare_variables
));
503 * 'cgi_initialize_get()' - Initialize form variables using the GET method.
506 static int /* O - 1 if form data read */
507 cgi_initialize_get(void)
509 char *data
; /* Pointer to form data string */
513 puts("Initializing variables using GET method...");
517 * Check to see if there is anything for us to read...
520 data
= getenv("QUERY_STRING");
521 if (data
== NULL
|| strlen(data
) == 0)
525 * Parse it out and return...
528 return (cgi_initialize_string(data
));
533 * 'cgi_initialize_multipart()' - Initialize variables and file using the POST method.
535 * TODO: Update to support files > 2GB.
538 static int /* O - 1 if form data was read */
539 cgi_initialize_multipart(
540 const char *boundary
) /* I - Boundary string */
542 char line
[10240], /* MIME header line */
543 name
[1024], /* Form variable name */
544 filename
[1024], /* Form filename */
545 mimetype
[1024], /* MIME media type */
546 bstring
[256], /* Boundary string to look for */
547 *ptr
, /* Pointer into name/filename */
548 *end
; /* End of buffer */
549 int ch
, /* Character from file */
550 fd
, /* Temporary file descriptor */
551 blen
; /* Length of boundary string */
554 DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary
));
557 * Read multipart form data until we run out...
564 snprintf(bstring
, sizeof(bstring
), "\r\n--%s", boundary
);
565 blen
= strlen(bstring
);
567 while (fgets(line
, sizeof(line
), stdin
))
569 if (!strcmp(line
, "\r\n"))
572 * End of headers, grab value...
578 * Read an embedded file...
584 * Remove previous file...
591 * Allocate memory for the new file...
594 if ((form_file
= calloc(1, sizeof(cgi_file_t
))) == NULL
)
597 form_file
->name
= strdup(name
);
598 form_file
->filename
= strdup(filename
);
599 form_file
->mimetype
= strdup(mimetype
);
601 fd
= cupsTempFd(form_file
->tempfile
, sizeof(form_file
->tempfile
));
606 atexit(cgi_unlink_file
);
609 * Copy file data to the temp file...
614 while ((ch
= getchar()) != EOF
)
618 if ((ptr
- line
) >= blen
&& !memcmp(ptr
- blen
, bstring
, blen
))
624 if ((ptr
- line
- blen
) >= 8192)
627 * Write out the first 8k of the buffer...
630 write(fd
, line
, 8192);
631 memmove(line
, line
+ 8192, ptr
- line
- 8192);
637 * Write the rest of the data and close the temp file...
641 write(fd
, line
, ptr
- line
);
648 * Just get a form variable; the current code only handles
649 * form values up to 10k in size...
653 end
= line
+ sizeof(line
) - 1;
655 while ((ch
= getchar()) != EOF
)
660 if ((ptr
- line
) >= blen
&& !memcmp(ptr
- blen
, bstring
, blen
))
670 * Set the form variable...
673 if ((ptr
= strrchr(name
, '-')) != NULL
&& isdigit(ptr
[1] & 255))
676 * Set a specific index in the array...
681 cgiSetArray(name
, atoi(ptr
) - 1, line
);
683 else if (cgiGetVariable(name
))
686 * Add another element in the array...
689 cgiSetArray(name
, cgiGetSize(name
), line
);
694 * Just set the line...
697 cgiSetVariable(name
, line
);
702 * Read the rest of the current line...
705 fgets(line
, sizeof(line
), stdin
);
708 * Clear the state vars...
715 else if (!strncasecmp(line
, "Content-Disposition:", 20))
717 if ((ptr
= strstr(line
+ 20, " name=\"")) != NULL
)
719 strlcpy(name
, ptr
+ 7, sizeof(name
));
721 if ((ptr
= strchr(name
, '\"')) != NULL
)
725 if ((ptr
= strstr(line
+ 20, " filename=\"")) != NULL
)
727 strlcpy(filename
, ptr
+ 11, sizeof(filename
));
729 if ((ptr
= strchr(filename
, '\"')) != NULL
)
733 else if (!strncasecmp(line
, "Content-Type:", 13))
735 for (ptr
= line
+ 13; isspace(*ptr
& 255); ptr
++);
737 strlcpy(mimetype
, ptr
, sizeof(mimetype
));
739 for (ptr
= mimetype
+ strlen(mimetype
) - 1;
740 ptr
> mimetype
&& isspace(*ptr
& 255);
746 * Return 1 for "form data found"...
754 * 'cgi_initialize_post()' - Initialize variables using the POST method.
757 static int /* O - 1 if form data was read */
758 cgi_initialize_post(void)
760 char *content_length
, /* Length of input data (string) */
761 *data
; /* Pointer to form data string */
762 int length
, /* Length of input data */
763 nbytes
, /* Number of bytes read this read() */
764 tbytes
, /* Total number of bytes read */
765 status
; /* Return status */
769 puts("Initializing variables using POST method...");
773 * Check to see if there is anything for us to read...
776 content_length
= getenv("CONTENT_LENGTH");
777 if (content_length
== NULL
|| atoi(content_length
) <= 0)
781 * Get the length of the input stream and allocate a buffer for it...
784 length
= atoi(content_length
);
785 data
= malloc(length
+ 1);
791 * Read the data into the buffer...
794 for (tbytes
= 0; tbytes
< length
; tbytes
+= nbytes
)
795 if ((nbytes
= read(0, data
+ tbytes
, length
- tbytes
)) < 0)
808 status
= cgi_initialize_string(data
);
811 * Free the data and return...
821 * 'cgi_initialize_string()' - Initialize form variables from a string.
824 static int /* O - 1 if form data was processed */
825 cgi_initialize_string(const char *data
) /* I - Form data string */
827 int done
; /* True if we're done reading a form variable */
828 char *s
, /* Pointer to current form string */
829 ch
, /* Temporary character */
830 name
[255], /* Name of form variable */
831 value
[65536]; /* Variable value... */
842 * Loop until we've read all the form data...
845 while (*data
!= '\0')
848 * Get the variable name...
851 for (s
= name
; *data
!= '\0'; data
++)
854 else if (*data
>= ' ' && s
< (name
+ sizeof(name
) - 1))
864 * Read the variable value...
867 for (s
= value
, done
= 0; !done
&& *data
!= '\0'; data
++)
870 case '&' : /* End of data... */
874 case '+' : /* Escaped space character */
875 if (s
< (value
+ sizeof(value
) - 1))
879 case '%' : /* Escaped control character */
881 * Read the hex code...
884 if (s
< (value
+ sizeof(value
) - 1))
902 default : /* Other characters come straight through */
903 if (*data
>= ' ' && s
< (value
+ sizeof(value
) - 1))
908 *s
= '\0'; /* nul terminate the string */
911 * Remove trailing whitespace...
917 while (s
>= value
&& *s
== ' ')
921 * Add the string to the variable "database"...
924 if ((s
= strrchr(name
, '-')) != NULL
&& isdigit(s
[1] & 255))
928 cgiSetArray(name
, atoi(s
) - 1, value
);
930 else if (cgiGetVariable(name
) != NULL
)
931 cgiSetArray(name
, cgiGetSize(name
), value
);
933 cgiSetVariable(name
, value
);
941 * 'cgi_passwd()' - Catch authentication requests and notify the server.
943 * This function sends a Status header and exits, forcing authentication
947 static const char * /* O - NULL (no return) */
948 cgi_passwd(const char *prompt
) /* I - Prompt (not used) */
952 fprintf(stderr
, "DEBUG: cgi_passwd(prompt=\"%s\") called!\n",
953 prompt
? prompt
: "(null)");
956 * Send a 401 (unauthorized) status to the server, so it can notify
957 * the client that authentication is required.
960 puts("Status: 401\n");
964 * This code is never executed, but is present to satisfy the compiler.
972 * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
976 cgi_sort_variables(void)
982 puts("Sorting variables...");
988 qsort(form_vars
, form_count
, sizeof(_cgi_var_t
),
989 (int (*)(const void *, const void *))cgi_compare_variables
);
992 puts("Sorted variable list is:");
993 for (i
= 0; i
< form_count
; i
++)
994 printf("%d: %s (%d) = \"%s\" ...\n", i
, form_vars
[i
].name
,
995 form_vars
[i
].nvalues
, form_vars
[i
].values
[0]);
1001 * 'cgi_unlink_file()' - Remove the uploaded form.
1005 cgi_unlink_file(void)
1010 * Remove the temporary file...
1013 unlink(form_file
->tempfile
);
1016 * Free memory used...
1019 free(form_file
->name
);
1020 free(form_file
->filename
);
1021 free(form_file
->mimetype
);
1030 * End of "$Id: var.c 177 2006-06-21 00:20:03Z jlovell $".