]>
git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/var.c
2 * "$Id: var.c 7460 2008-04-16 02:19:54Z mike $"
4 * CGI form variable and array functions.
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cgiCheckVariables() - Check for the presence of "required" variables.
18 * cgiClearVariables() - Clear all form variables.
19 * cgiGetArray() - Get an element from a form array...
20 * cgiGetFile() - Get the file (if any) that was submitted in the form.
21 * cgiGetSize() - Get the size of a form array value.
22 * cgiGetVariable() - Get a CGI variable from the database...
23 * cgiInitialize() - Initialize the CGI variable "database"...
24 * cgiIsPOST() - Determine whether this page was POSTed.
25 * cgiSetArray() - Set array element N to the specified string.
26 * cgiSetSize() - Set the array size.
27 * cgiSetVariable() - Set a CGI variable in the database...
28 * cgi_add_variable() - Add a form variable.
29 * cgi_compare_variables() - Compare two variables.
30 * cgi_find_variable() - Find a variable...
31 * cgi_initialize_get() - Initialize form variables using the GET method.
32 * cgi_initialize_multipart() - Initialize variables and file using the POST method.
33 * cgi_initialize_post() - Initialize variables using the POST method.
34 * cgi_initialize_string() - Initialize form variables from a string.
35 * cgi_passwd() - Catch authentication requests and notify the server.
36 * cgi_sort_variables() - Sort all form variables for faster lookup.
37 * cgi_unlink_file() - Remove the uploaded form.
41 #include "cgi-private.h"
46 * Data structure to hold all the CGI form variables and arrays...
49 typedef struct /**** Form variable structure ****/
51 const char *name
; /* Name of variable */
52 int nvalues
, /* Number of values */
53 avalues
; /* Number of values allocated */
54 const char **values
; /* Value(s) of variable */
62 static int form_count
= 0, /* Form variable count */
63 form_alloc
= 0; /* Number of variables allocated */
64 static _cgi_var_t
*form_vars
= NULL
;
66 static cgi_file_t
*form_file
= NULL
;
74 static void cgi_add_variable(const char *name
, int element
,
76 static int cgi_compare_variables(const _cgi_var_t
*v1
,
77 const _cgi_var_t
*v2
);
78 static _cgi_var_t
*cgi_find_variable(const char *name
);
79 static int cgi_initialize_get(void);
80 static int cgi_initialize_multipart(const char *boundary
);
81 static int cgi_initialize_post(void);
82 static int cgi_initialize_string(const char *data
);
83 static const char *cgi_passwd(const char *prompt
);
84 static void cgi_sort_variables(void);
85 static void cgi_unlink_file(void);
89 * 'cgiCheckVariables()' - Check for the presence of "required" variables.
91 * Names may be separated by spaces and/or commas.
94 int /* O - 1 if all variables present, 0 otherwise */
95 cgiCheckVariables(const char *names
) /* I - Variables to look for */
97 char name
[255], /* Current variable name */
98 *s
; /* Pointer in string */
99 const char *val
; /* Value of variable */
100 int element
; /* Array element number */
106 while (*names
!= '\0')
108 while (*names
== ' ' || *names
== ',')
111 for (s
= name
; *names
!= '\0' && *names
!= ' ' && *names
!= ','; s
++, names
++)
118 if ((s
= strrchr(name
, '-')) != NULL
)
121 element
= atoi(s
+ 1) - 1;
122 val
= cgiGetArray(name
, element
);
125 val
= cgiGetVariable(name
);
131 return (0); /* Can't be blank, either! */
139 * 'cgiClearVariables()' - Clear all form variables.
143 cgiClearVariables(void)
145 int i
, j
; /* Looping vars */
146 _cgi_var_t
*v
; /* Current variable */
149 for (v
= form_vars
, i
= form_count
; i
> 0; v
++, i
--)
151 _cupsStrFree(v
->name
);
152 for (j
= 0; j
< v
->nvalues
; j
++)
154 _cupsStrFree(v
->values
[j
]);
164 * 'cgiGetArray()' - Get an element from a form array...
167 const char * /* O - Element value or NULL */
168 cgiGetArray(const char *name
, /* I - Name of array variable */
169 int element
) /* I - Element number (0 to N) */
171 _cgi_var_t
*var
; /* Pointer to variable */
174 if ((var
= cgi_find_variable(name
)) == NULL
)
177 if (element
< 0 || element
>= var
->nvalues
)
180 return (_cupsStrRetain(var
->values
[element
]));
185 * 'cgiGetFile()' - Get the file (if any) that was submitted in the form.
188 const cgi_file_t
* /* O - Attached file or NULL */
196 * 'cgiGetSize()' - Get the size of a form array value.
199 int /* O - Number of elements */
200 cgiGetSize(const char *name
) /* I - Name of variable */
202 _cgi_var_t
*var
; /* Pointer to variable */
205 if ((var
= cgi_find_variable(name
)) == NULL
)
208 return (var
->nvalues
);
213 * 'cgiGetVariable()' - Get a CGI variable from the database...
215 * Returns NULL if the variable doesn't exist. If the variable is an
216 * array of values, returns the last element...
219 const char * /* O - Value of variable */
220 cgiGetVariable(const char *name
) /* I - Name of variable */
222 const _cgi_var_t
*var
; /* Returned variable */
225 var
= cgi_find_variable(name
);
229 DEBUG_printf(("cgiGetVariable(\"%s\") is returning NULL...\n", name
));
231 DEBUG_printf(("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name
,
232 var
->values
[var
->nvalues
- 1]));
235 return ((var
== NULL
) ? NULL
: _cupsStrRetain(var
->values
[var
->nvalues
- 1]));
240 * 'cgiInitialize()' - Initialize the CGI variable "database"...
243 int /* O - Non-zero if there was form data */
246 const char *method
; /* Form posting method */
247 const char *content_type
; /* Content-Type of post data */
251 * Setup a password callback for authentication...
254 cupsSetPasswordCB(cgi_passwd
);
257 * Set the locale so that times, etc. are formatted properly...
260 setlocale(LC_ALL
, "");
264 * Disable output buffering to find bugs...
267 setbuf(stdout
, NULL
);
271 * Get the request method (GET or POST)...
274 method
= getenv("REQUEST_METHOD");
275 content_type
= getenv("CONTENT_TYPE");
280 * Grab form data from the corresponding location...
283 if (!strcasecmp(method
, "GET"))
284 return (cgi_initialize_get());
285 else if (!strcasecmp(method
, "POST") && content_type
)
287 const char *boundary
= strstr(content_type
, "boundary=");
292 if (content_type
&& !strncmp(content_type
, "multipart/form-data; ", 21))
293 return (cgi_initialize_multipart(boundary
));
295 return (cgi_initialize_post());
303 * 'cgiIsPOST()' - Determine whether this page was POSTed.
306 int /* O - 1 if POST, 0 if GET */
309 const char *method
; /* REQUEST_METHOD environment variable */
312 if ((method
= getenv("REQUEST_METHOD")) == NULL
)
315 return (!strcmp(method
, "POST"));
320 * 'cgiSetArray()' - Set array element N to the specified string.
322 * If the variable array is smaller than (element + 1), the intervening
323 * elements are set to NULL.
327 cgiSetArray(const char *name
, /* I - Name of variable */
328 int element
, /* I - Element number (0 to N) */
329 const char *value
) /* I - Value of variable */
331 int i
; /* Looping var */
332 _cgi_var_t
*var
; /* Returned variable */
335 if (name
== NULL
|| value
== NULL
|| element
< 0 || element
> 100000)
338 if ((var
= cgi_find_variable(name
)) == NULL
)
340 cgi_add_variable(name
, element
, value
);
341 cgi_sort_variables();
345 if (element
>= var
->avalues
)
347 const char **temp
; /* Temporary pointer */
349 temp
= (const char **)realloc((void *)(var
->values
),
350 sizeof(char *) * (element
+ 16));
354 var
->avalues
= element
+ 16;
358 if (element
>= var
->nvalues
)
360 for (i
= var
->nvalues
; i
< element
; i
++)
361 var
->values
[i
] = NULL
;
363 var
->nvalues
= element
+ 1;
365 else if (var
->values
[element
])
366 _cupsStrFree((char *)var
->values
[element
]);
368 var
->values
[element
] = _cupsStrAlloc(value
);
374 * 'cgiSetSize()' - Set the array size.
378 cgiSetSize(const char *name
, /* I - Name of variable */
379 int size
) /* I - Number of elements (0 to N) */
381 int i
; /* Looping var */
382 _cgi_var_t
*var
; /* Returned variable */
385 if (name
== NULL
|| size
< 0 || size
> 100000)
388 if ((var
= cgi_find_variable(name
)) == NULL
)
391 if (size
>= var
->avalues
)
393 const char **temp
; /* Temporary pointer */
395 temp
= (const char **)realloc((void *)(var
->values
),
396 sizeof(char *) * (size
+ 16));
400 var
->avalues
= size
+ 16;
404 if (size
> var
->nvalues
)
406 for (i
= var
->nvalues
; i
< size
; i
++)
407 var
->values
[i
] = NULL
;
409 else if (size
< var
->nvalues
)
411 for (i
= size
; i
< var
->nvalues
; i
++)
413 _cupsStrFree((void *)(var
->values
[i
]));
421 * 'cgiSetVariable()' - Set a CGI variable in the database...
423 * If the variable is an array, this truncates the array to a single element.
427 cgiSetVariable(const char *name
, /* I - Name of variable */
428 const char *value
) /* I - Value of variable */
430 int i
; /* Looping var */
431 _cgi_var_t
*var
; /* Returned variable */
434 if (name
== NULL
|| value
== NULL
)
437 if ((var
= cgi_find_variable(name
)) == NULL
)
439 cgi_add_variable(name
, 0, value
);
440 cgi_sort_variables();
444 for (i
= 0; i
< var
->nvalues
; i
++)
446 _cupsStrFree((char *)var
->values
[i
]);
448 var
->values
[0] = _cupsStrAlloc(value
);
455 * 'cgi_add_variable()' - Add a form variable.
459 cgi_add_variable(const char *name
, /* I - Variable name */
460 int element
, /* I - Array element number */
461 const char *value
) /* I - Variable value */
463 _cgi_var_t
*var
; /* New variable */
466 if (name
== NULL
|| value
== NULL
|| element
< 0 || element
> 100000)
469 DEBUG_printf(("cgi_add_variable: Adding variable \'%s\' with value "
470 "\'%s\'...\n", name
, value
));
472 if (form_count
>= form_alloc
)
474 _cgi_var_t
*temp_vars
; /* Temporary form pointer */
478 temp_vars
= malloc(sizeof(_cgi_var_t
) * 16);
480 temp_vars
= realloc(form_vars
, (form_alloc
+ 16) * sizeof(_cgi_var_t
));
485 form_vars
= temp_vars
;
489 var
= form_vars
+ form_count
;
491 if ((var
->values
= calloc(element
+ 1, sizeof(char *))) == NULL
)
494 var
->name
= _cupsStrAlloc(name
);
495 var
->nvalues
= element
+ 1;
496 var
->avalues
= element
+ 1;
497 var
->values
[element
] = _cupsStrAlloc(value
);
504 * 'cgi_compare_variables()' - Compare two variables.
507 static int /* O - Result of comparison */
508 cgi_compare_variables(
509 const _cgi_var_t
*v1
, /* I - First variable */
510 const _cgi_var_t
*v2
) /* I - Second variable */
512 return (strcasecmp(v1
->name
, v2
->name
));
517 * 'cgi_find_variable()' - Find a variable...
520 static _cgi_var_t
* /* O - Variable pointer or NULL */
521 cgi_find_variable(const char *name
) /* I - Name of variable */
523 _cgi_var_t key
; /* Search key */
526 if (form_count
< 1 || name
== NULL
)
531 return ((_cgi_var_t
*)bsearch(&key
, form_vars
, form_count
, sizeof(_cgi_var_t
),
532 (int (*)(const void *, const void *))cgi_compare_variables
));
537 * 'cgi_initialize_get()' - Initialize form variables using the GET method.
540 static int /* O - 1 if form data read */
541 cgi_initialize_get(void)
543 char *data
; /* Pointer to form data string */
546 DEBUG_puts("cgi_initialize_get: Initializing variables using GET method...");
549 * Check to see if there is anything for us to read...
552 data
= getenv("QUERY_STRING");
553 if (data
== NULL
|| strlen(data
) == 0)
557 * Parse it out and return...
560 return (cgi_initialize_string(data
));
565 * 'cgi_initialize_multipart()' - Initialize variables and file using the POST method.
567 * TODO: Update to support files > 2GB.
570 static int /* O - 1 if form data was read */
571 cgi_initialize_multipart(
572 const char *boundary
) /* I - Boundary string */
574 char line
[10240], /* MIME header line */
575 name
[1024], /* Form variable name */
576 filename
[1024], /* Form filename */
577 mimetype
[1024], /* MIME media type */
578 bstring
[256], /* Boundary string to look for */
579 *ptr
, /* Pointer into name/filename */
580 *end
; /* End of buffer */
581 int ch
, /* Character from file */
582 fd
, /* Temporary file descriptor */
583 blen
; /* Length of boundary string */
586 DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary
));
589 * Read multipart form data until we run out...
596 snprintf(bstring
, sizeof(bstring
), "\r\n--%s", boundary
);
597 blen
= strlen(bstring
);
599 while (fgets(line
, sizeof(line
), stdin
))
601 if (!strcmp(line
, "\r\n"))
604 * End of headers, grab value...
610 * Read an embedded file...
616 * Remove previous file...
623 * Allocate memory for the new file...
626 if ((form_file
= calloc(1, sizeof(cgi_file_t
))) == NULL
)
629 form_file
->name
= strdup(name
);
630 form_file
->filename
= strdup(filename
);
631 form_file
->mimetype
= strdup(mimetype
);
633 fd
= cupsTempFd(form_file
->tempfile
, sizeof(form_file
->tempfile
));
638 atexit(cgi_unlink_file
);
641 * Copy file data to the temp file...
646 while ((ch
= getchar()) != EOF
)
650 if ((ptr
- line
) >= blen
&& !memcmp(ptr
- blen
, bstring
, blen
))
656 if ((ptr
- line
- blen
) >= 8192)
659 * Write out the first 8k of the buffer...
662 write(fd
, line
, 8192);
663 memmove(line
, line
+ 8192, ptr
- line
- 8192);
669 * Write the rest of the data and close the temp file...
673 write(fd
, line
, ptr
- line
);
680 * Just get a form variable; the current code only handles
681 * form values up to 10k in size...
685 end
= line
+ sizeof(line
) - 1;
687 while ((ch
= getchar()) != EOF
)
692 if ((ptr
- line
) >= blen
&& !memcmp(ptr
- blen
, bstring
, blen
))
702 * Set the form variable...
705 if ((ptr
= strrchr(name
, '-')) != NULL
&& isdigit(ptr
[1] & 255))
708 * Set a specific index in the array...
713 cgiSetArray(name
, atoi(ptr
) - 1, line
);
715 else if (cgiGetVariable(name
))
718 * Add another element in the array...
721 cgiSetArray(name
, cgiGetSize(name
), line
);
726 * Just set the line...
729 cgiSetVariable(name
, line
);
734 * Read the rest of the current line...
737 fgets(line
, sizeof(line
), stdin
);
740 * Clear the state vars...
747 else if (!strncasecmp(line
, "Content-Disposition:", 20))
749 if ((ptr
= strstr(line
+ 20, " name=\"")) != NULL
)
751 strlcpy(name
, ptr
+ 7, sizeof(name
));
753 if ((ptr
= strchr(name
, '\"')) != NULL
)
757 if ((ptr
= strstr(line
+ 20, " filename=\"")) != NULL
)
759 strlcpy(filename
, ptr
+ 11, sizeof(filename
));
761 if ((ptr
= strchr(filename
, '\"')) != NULL
)
765 else if (!strncasecmp(line
, "Content-Type:", 13))
767 for (ptr
= line
+ 13; isspace(*ptr
& 255); ptr
++);
769 strlcpy(mimetype
, ptr
, sizeof(mimetype
));
771 for (ptr
= mimetype
+ strlen(mimetype
) - 1;
772 ptr
> mimetype
&& isspace(*ptr
& 255);
778 * Return 1 for "form data found"...
786 * 'cgi_initialize_post()' - Initialize variables using the POST method.
789 static int /* O - 1 if form data was read */
790 cgi_initialize_post(void)
792 char *content_length
, /* Length of input data (string) */
793 *data
; /* Pointer to form data string */
794 int length
, /* Length of input data */
795 nbytes
, /* Number of bytes read this read() */
796 tbytes
, /* Total number of bytes read */
797 status
; /* Return status */
800 DEBUG_puts("cgi_initialize_post: Initializing variables using POST method...");
803 * Check to see if there is anything for us to read...
806 content_length
= getenv("CONTENT_LENGTH");
807 if (content_length
== NULL
|| atoi(content_length
) <= 0)
811 * Get the length of the input stream and allocate a buffer for it...
814 length
= atoi(content_length
);
815 data
= malloc(length
+ 1);
821 * Read the data into the buffer...
824 for (tbytes
= 0; tbytes
< length
; tbytes
+= nbytes
)
825 if ((nbytes
= read(0, data
+ tbytes
, length
- tbytes
)) < 0)
835 else if (nbytes
== 0)
838 * CUPS STR #3176: OpenBSD: Early end-of-file on POST data causes 100% CPU
840 * This should never happen, but does on OpenBSD. If we see early end-of-
841 * file, treat this as an error and process no data.
854 status
= cgi_initialize_string(data
);
857 * Free the data and return...
867 * 'cgi_initialize_string()' - Initialize form variables from a string.
870 static int /* O - 1 if form data was processed */
871 cgi_initialize_string(const char *data
) /* I - Form data string */
873 int done
; /* True if we're done reading a form variable */
874 char *s
, /* Pointer to current form string */
875 ch
, /* Temporary character */
876 name
[255], /* Name of form variable */
877 value
[65536]; /* Variable value... */
888 * Loop until we've read all the form data...
891 while (*data
!= '\0')
894 * Get the variable name...
897 for (s
= name
; *data
!= '\0'; data
++)
900 else if (*data
>= ' ' && s
< (name
+ sizeof(name
) - 1))
910 * Read the variable value...
913 for (s
= value
, done
= 0; !done
&& *data
!= '\0'; data
++)
916 case '&' : /* End of data... */
920 case '+' : /* Escaped space character */
921 if (s
< (value
+ sizeof(value
) - 1))
925 case '%' : /* Escaped control character */
927 * Read the hex code...
930 if (s
< (value
+ sizeof(value
) - 1))
948 default : /* Other characters come straight through */
949 if (*data
>= ' ' && s
< (value
+ sizeof(value
) - 1))
954 *s
= '\0'; /* nul terminate the string */
957 * Remove trailing whitespace...
963 while (s
>= value
&& isspace(*s
& 255))
967 * Add the string to the variable "database"...
970 if ((s
= strrchr(name
, '-')) != NULL
&& isdigit(s
[1] & 255))
974 cgiSetArray(name
, atoi(s
) - 1, value
);
976 else if (cgiGetVariable(name
) != NULL
)
977 cgiSetArray(name
, cgiGetSize(name
), value
);
979 cgiSetVariable(name
, value
);
987 * 'cgi_passwd()' - Catch authentication requests and notify the server.
989 * This function sends a Status header and exits, forcing authentication
993 static const char * /* O - NULL (no return) */
994 cgi_passwd(const char *prompt
) /* I - Prompt (not used) */
998 fprintf(stderr
, "DEBUG: cgi_passwd(prompt=\"%s\") called!\n",
999 prompt
? prompt
: "(null)");
1002 * Send a 401 (unauthorized) status to the server, so it can notify
1003 * the client that authentication is required.
1006 puts("Status: 401\n");
1010 * This code is never executed, but is present to satisfy the compiler.
1018 * 'cgi_sort_variables()' - Sort all form variables for faster lookup.
1022 cgi_sort_variables(void)
1028 DEBUG_puts("cgi_sort_variables: Sorting variables...");
1034 qsort(form_vars
, form_count
, sizeof(_cgi_var_t
),
1035 (int (*)(const void *, const void *))cgi_compare_variables
);
1038 DEBUG_puts("cgi_sort_variables: Sorted variable list is:");
1039 for (i
= 0; i
< form_count
; i
++)
1040 DEBUG_printf(("cgi_sort_variables: %d: %s (%d) = \"%s\" ...\n", i
,
1041 form_vars
[i
].name
, form_vars
[i
].nvalues
,
1042 form_vars
[i
].values
[0]));
1048 * 'cgi_unlink_file()' - Remove the uploaded form.
1052 cgi_unlink_file(void)
1057 * Remove the temporary file...
1060 unlink(form_file
->tempfile
);
1063 * Free memory used...
1066 free(form_file
->name
);
1067 free(form_file
->filename
);
1068 free(form_file
->mimetype
);
1077 * End of "$Id: var.c 7460 2008-04-16 02:19:54Z mike $".