From 3dfe78b3363fe9e058a98197eda9a856991cbc6f Mon Sep 17 00:00:00 2001 From: msweet Date: Mon, 21 Apr 2008 23:14:57 +0000 Subject: [PATCH] Merge changes from CUPS 1.4svn-r7485. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@718 a1ca3aef-8c08-0410-bb20-df032aa958be --- CHANGES-1.3.txt | 20 +- CHANGES.txt | 8 +- backend/ipp.c | 2 +- backend/test1284.c | 3 - doc/help/ref-cupsd-conf.html.in | 16 + filter/image-private.h | 6 +- filter/image.c | 66 +- filter/pdftops.c | 14 +- packaging/cups.list.in | 2 +- ppdc/drv.cxx | 13 +- scheduler/auth.c | 15 +- scheduler/client.c | 67 +- scheduler/client.h | 4 +- scheduler/conf.c | 6 +- scheduler/dirsvc.c | 60 +- scheduler/ipp.c | 216 +++- scheduler/job.c | 173 ++- scheduler/job.h | 7 +- scheduler/main.c | 69 +- scheduler/printers.c | 7 +- scheduler/server.c | 10 +- scheduler/subscriptions.c | 6 +- scheduler/sysman.c | 115 +- scheduler/sysman.h | 23 +- standards/rfc3875.txt | 2019 +++++++++++++++++++++++++++++++ templates/jobs.tmpl | 3 +- test/4.3-job-ops.test | 23 +- 27 files changed, 2714 insertions(+), 259 deletions(-) create mode 100644 standards/rfc3875.txt diff --git a/CHANGES-1.3.txt b/CHANGES-1.3.txt index 271225ac7..f668b502f 100644 --- a/CHANGES-1.3.txt +++ b/CHANGES-1.3.txt @@ -4,6 +4,24 @@ CHANGES-1.3.txt CHANGES IN CUPS V1.3.8 - Documentation updates (STR #2785) + - The scheduler did not set QUERY_STRING all of the time + for CGI scripts (STR #2781) + - The scheduler now returns an error for bad job-sheets + values (STR #2775) + - Authenticated remote printing did not work over domain + sockets (STR #2750) + - The scheduler incorrectly logged errors for print filters + when a job was canceled (STR #2806, #2808) + - The scheduler not long allows multiple RSS subscriptions + with the same URI (STR #2789) + - The scheduler now supports Kerberized printing with + multiple server names (STR #2783) + - "Satisfy any" did not work in IPP policies (STR #2782) + - The CUPS imaging library would crash with very large + images - more than 16Mx16M pixels (STR #2805) + - The PNG image loading code would crash with large images + (STR #2790) + - The scheduler did not limit the total number of filters. - The scheduler now ensures that the RSS directory has the correct permissions. - The RSS notifier did not quote the feed URL in the RSS @@ -14,8 +32,6 @@ CHANGES IN CUPS V1.3.8 9999 to match the limit imposed by the print dialog. - The scheduler did not reject requests with an empty Content-Length field (STR #2787) - - The PNG image loading code would crash with large images - (STR #2790) - The scheduler did not log the current date and time and did not escape special characters in request URIs when logging bad requests to the access_log file (STR #2788) diff --git a/CHANGES.txt b/CHANGES.txt index de23174da..2e1f937a2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,14 @@ -CHANGES.txt - 2008-04-14 +CHANGES.txt - 2008-04-21 ------------------------ CHANGES IN CUPS V1.4b1 + - Driver information files can now be installed in + /Library/Printers/PPDs.drv on Mac OS X. + - The CUPS image library now supports reading images larger + than 2GB. + - The scheduler now delays writing config and state files to + reduce disk activity (STR #2684) - The CUPS-Get-Devices operation now supports the exclude-schemes and timeout attributes to control which backends are polled and for how long. diff --git a/backend/ipp.c b/backend/ipp.c index 68806382e..1feb6fdb1 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1410,7 +1410,7 @@ password_cb(const char *prompt) /* I - Prompt (not used) */ { (void)prompt; - if (password && password_tries < 3) + if (password && *password && password_tries < 3) { password_tries ++; diff --git a/backend/test1284.c b/backend/test1284.c index bbb4f2c3f..2f2766b42 100644 --- a/backend/test1284.c +++ b/backend/test1284.c @@ -34,9 +34,6 @@ # include #endif /* WIN32 */ -#ifndef DEBUG -# define DEBUG -#endif /* !DEBUG */ #include "ieee1284.c" diff --git a/doc/help/ref-cupsd-conf.html.in b/doc/help/ref-cupsd-conf.html.in index 39768d5ec..07ba7ad51 100644 --- a/doc/help/ref-cupsd-conf.html.in +++ b/doc/help/ref-cupsd-conf.html.in @@ -1007,6 +1007,22 @@ HREF="#Location">Location or Limit section.

+

DirtyCleanInterval

+ +

Examples

+ +
+DirtyCleanInterval 60
+DirtyCleanInterval 0
+
+ +

Description

+ +

The DirtyCleanInterval directive specifies the number of +seconds to wait before updating configuration and state files for printers, +classes, subscriptions, and jobs. The default is 60 seconds.

+ +

DocumentRoot

Examples

diff --git a/filter/image-private.h b/filter/image-private.h index dcf03a7e6..1323d75a7 100644 --- a/filter/image-private.h +++ b/filter/image-private.h @@ -4,7 +4,7 @@ * Private image library definitions for the Common UNIX Printing * System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1993-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -78,7 +78,7 @@ struct cups_ic_s; typedef struct cups_itile_s /**** Image tile ****/ { int dirty; /* True if tile is dirty */ - long pos; /* Position of tile on disk (-1 if not written) */ + off_t pos; /* Position of tile on disk (-1 if not written) */ struct cups_ic_s *ic; /* Pixel data */ } cups_itile_t; @@ -102,7 +102,7 @@ struct cups_image_s /**** Image file data ****/ cups_itile_t **tiles; /* Tiles in image */ cups_ic_t *first, /* First cached tile in image */ *last; /* Last cached tile in image */ - FILE *cachefile; /* Tile cache file */ + int cachefile; /* Tile cache file */ char cachename[256]; /* Tile cache filename */ }; diff --git a/filter/image.c b/filter/image.c index 589ba7df5..493c50633 100644 --- a/filter/image.c +++ b/filter/image.c @@ -63,11 +63,11 @@ cupsImageClose(cups_image_t *img) /* I - Image to close */ * Wipe the tile cache file (if any)... */ - if (img->cachefile != NULL) + if (img->cachefile >= 0) { DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img->cachename)); - fclose(img->cachefile); + close(img->cachefile); unlink(img->cachename); } @@ -620,7 +620,6 @@ cupsImageSetMaxTiles( static void flush_tile(cups_image_t *img) /* I - Image */ { - int fd; /* Cache file descriptor */ int bpp; /* Bytes per pixel */ cups_itile_t *tile; /* Pointer to tile */ @@ -634,64 +633,40 @@ flush_tile(cups_image_t *img) /* I - Image */ return; } - if (img->cachefile == NULL) + if (img->cachefile < 0) { - if ((fd = cupsTempFd(img->cachename, sizeof(img->cachename))) < 0) + if ((img->cachefile = cupsTempFd(img->cachename, + sizeof(img->cachename))) < 0) { -/* perror("ERROR: Unable to create image swap file"); -*/ tile->ic = NULL; + tile->ic = NULL; tile->dirty = 0; return; } DEBUG_printf(("Created swap file \"%s\"...\n", img->cachename)); + } - if ((img->cachefile = fdopen(fd, "wb+")) == NULL) + if (tile->pos >= 0) + { + if (lseek(img->cachefile, tile->pos, SEEK_SET) != tile->pos) { -/* perror("ERROR: Unable to create image swap file"); -*/ close(fd); - unlink(img->cachename); tile->ic = NULL; tile->dirty = 0; return; } } - - if (tile->pos >= 0) - { - if (ftell(img->cachefile) != tile->pos) - if (fseek(img->cachefile, tile->pos, SEEK_SET)) - { -/* perror("ERROR: Unable to seek in swap file"); -*/ tile->ic = NULL; - tile->dirty = 0; - return; - } - } else { - if (fseek(img->cachefile, 0, SEEK_END)) + if ((tile->pos = lseek(img->cachefile, 0, SEEK_END)) < 0) { -/* perror("ERROR: Unable to append to swap file"); -*/ tile->ic = NULL; + tile->ic = NULL; tile->dirty = 0; return; } - - tile->pos = ftell(img->cachefile); } + write(img->cachefile, tile->ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE); -/* if (fwrite(tile->ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE, - img->cachefile) < 1) - perror("ERROR: Unable to write tile to swap file"); - else - DEBUG_printf(("Wrote tile at position %ld...\n", tile->pos)); -*/ - - fwrite(tile->ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE, - img->cachefile); - tile->ic = NULL; tile->dirty = 0; } @@ -725,7 +700,7 @@ get_tile(cups_image_t *img, /* I - Image */ if ((img->tiles = calloc(sizeof(cups_itile_t *), ytiles)) == NULL) return (NULL); - if ((tile = calloc(sizeof(cups_itile_t), xtiles * ytiles)) == NULL) + if ((tile = calloc(xtiles * sizeof(cups_itile_t), ytiles)) == NULL) return (NULL); for (tiley = 0; tiley < ytiles; tiley ++) @@ -778,16 +753,11 @@ get_tile(cups_image_t *img, /* I - Image */ if (tile->pos >= 0) { - DEBUG_printf(("Loading cache tile from file position %ld...\n", - tile->pos)); - - if (ftell(img->cachefile) != tile->pos) - fseek(img->cachefile, tile->pos, SEEK_SET); -/* if (fseek(img->cachefile, tile->pos, SEEK_SET)) - perror("get_tile:"); -*/ + DEBUG_printf(("Loading cache tile from file position " CUPS_LLFMT "...\n", + CUPS_LLCAST tile->pos)); - fread(ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE, img->cachefile); + lseek(img->cachefile, tile->pos, SEEK_SET); + read(img->cachefile, ic->pixels, bpp * CUPS_TILE_SIZE * CUPS_TILE_SIZE); } else { diff --git a/filter/pdftops.c b/filter/pdftops.c index 0529dd144..69ed05ab6 100644 --- a/filter/pdftops.c +++ b/filter/pdftops.c @@ -327,22 +327,20 @@ main(int argc, /* I - Number of command-line args */ * Parent comes here... */ - while ((pdfwaitpid = wait(&pdfstatus)) < 0 && errno == EINTR) + while ((pdfwaitpid = wait(&pdfstatus)) != pdfpid && errno == EINTR) { /* * Wait until we get a valid process ID or the job is canceled... */ if (job_canceled) - break; + { + kill(pdfpid, SIGTERM); + job_canceled = 0; + } } - if (pdfwaitpid != pdfpid) - { - kill(pdfpid, SIGTERM); - pdfstatus = 1; - } - else if (pdfstatus) + if (pdfstatus) { if (WIFEXITED(pdfstatus)) { diff --git a/packaging/cups.list.in b/packaging/cups.list.in index 45e70c9ef..b5c069dd1 100644 --- a/packaging/cups.list.in +++ b/packaging/cups.list.in @@ -269,7 +269,7 @@ f 0755 root sys $SERVERBIN/filter/imagetops filter/imagetops f 0755 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster %endif %if PDFTOPS -f 0755 root sys $SERVERBIN/filter/pdftops pdftops/pdftops +f 0755 root sys $SERVERBIN/filter/pdftops filter/pdftops %endif f 0755 root sys $SERVERBIN/filter/pstops filter/pstops f 0755 root sys $SERVERBIN/filter/rastertoespcx driver/rastertoescpx diff --git a/ppdc/drv.cxx b/ppdc/drv.cxx index 23b9ecec9..8c0aec6c9 100644 --- a/ppdc/drv.cxx +++ b/ppdc/drv.cxx @@ -3,7 +3,7 @@ // // DDK driver interface main entry for the CUPS PPD Compiler. // -// Copyright 2007 by Apple Inc. +// Copyright 2007-2008 by Apple Inc. // Copyright 2002-2006 by Easy Software Products. // // These coded instructions, statements, and computer programs are the @@ -66,6 +66,11 @@ main(int argc, // I - Number of command-line arguments // List all available PPDs or cat a single PPD... if (argc == 2 && !strcmp(argv[1], "list")) { +#ifdef __APPLE__ + if (!access("/Library/Printers/PPDs.drv", 0)) + list_drvs("/Library/Printers/PPDs.drv", "/Library/Printers/PPDs.drv"); +#endif // __APPLE__ + snprintf(filename, sizeof(filename), "%s/drv", datadir); return (list_drvs(filename, "/")); } @@ -85,6 +90,12 @@ main(int argc, // I - Number of command-line arguments *pc_file_name++ = '\0'; +#ifdef __APPLE__ + if (!strncmp(resource, "/Library/Printers/PPDs.drv/", 27)) + strlcpy(filename, resource, sizeof(filename)); + else +#endif // __APPLE__ + snprintf(filename, sizeof(filename), "%s/drv%s", datadir, resource); src = new ppdcSource(filename); diff --git a/scheduler/auth.c b/scheduler/auth.c index ed49087a8..9516f28ba 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -114,7 +114,8 @@ static int compare_locations(cupsd_location_t *a, static char *cups_crypt(const char *pw, const char *salt); #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */ #ifdef HAVE_GSSAPI -static gss_cred_id_t get_gss_creds(const char *service_name); +static gss_cred_id_t get_gss_creds(const char *service_name, + const char *con_server_name); #endif /* HAVE_GSSAPI */ static char *get_md5_password(const char *username, const char *group, char passwd[33]); @@ -990,7 +991,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ * Get the server credentials... */ - if ((server_creds = get_gss_creds(GSSServiceName)) == NULL) + if ((server_creds = get_gss_creds(GSSServiceName, con->servername)) == NULL) return; /* @@ -2468,7 +2469,9 @@ cups_crypt(const char *pw, /* I - Password string */ */ static gss_cred_id_t /* O - Server credentials */ -get_gss_creds(const char *service_name) /* I - Service name */ +get_gss_creds( + const char *service_name, /* I - Service name */ + const char *con_server_name) /* I - Hostname of server */ { OM_uint32 major_status, /* Major status code */ minor_status; /* Minor status code */ @@ -2476,12 +2479,10 @@ get_gss_creds(const char *service_name) /* I - Service name */ gss_cred_id_t server_creds; /* Server credentials */ gss_buffer_desc token = GSS_C_EMPTY_BUFFER; /* Service name token */ - char buf[1024], /* Service name buffer */ - fqdn[HTTP_MAX_URI]; /* Hostname of server */ + char buf[1024]; /* Service name buffer */ - snprintf(buf, sizeof(buf), "%s@%s", service_name, - httpGetHostname(NULL, fqdn, sizeof(fqdn))); + snprintf(buf, sizeof(buf), "%s@%s", service_name, con_server_name); token.value = buf; token.length = strlen(buf); diff --git a/scheduler/client.c b/scheduler/client.c index ba016434a..107482773 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -28,6 +28,7 @@ * cupsdUpdateCGI() - Read status messages from CGI scripts and programs. * cupsdWriteClient() - Write data to a client as needed. * check_if_modified() - Decode an "If-Modified-Since" line. + * compare_clients() - Compare two client connections. * encrypt_client() - Enable encryption for the client... * get_cdsa_certificate() - Convert a keychain name into the CFArrayRef * required by SSLSetCertificate. @@ -82,6 +83,8 @@ extern const char *cssmErrorString(int error); static int check_if_modified(cupsd_client_t *con, struct stat *filestats); +static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, + void *data); #ifdef HAVE_SSL static int encrypt_client(cupsd_client_t *con); #endif /* HAVE_SSL */ @@ -145,7 +148,18 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ if (!Clients) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for client array!"); + "Unable to allocate memory for clients array!"); + cupsdPauseListening(); + return; + } + + if (!ActiveClients) + ActiveClients = cupsArrayNew((cups_array_func_t)compare_clients, NULL); + + if (!ActiveClients) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate memory for active clients array!"); cupsdPauseListening(); return; } @@ -607,8 +621,11 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ * Close the socket and clear the file from the input set for select()... */ - if (con->http.fd > 0) + if (con->http.fd >= 0) { + cupsArrayRemove(ActiveClients, con); + cupsdSetBusyState(); + if (partial) { /* @@ -973,6 +990,9 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ con->http.status = HTTP_OK; + cupsArrayAdd(ActiveClients, con); + cupsdSetBusyState(); + case HTTP_OPTIONS : case HTTP_DELETE : case HTTP_GET : @@ -2144,8 +2164,16 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ break; /* Anti-compiler-warning-code */ } - if (!con->http.keep_alive && con->http.state == HTTP_WAITING) - cupsdCloseClient(con); + if (con->http.state == HTTP_WAITING) + { + if (!con->http.keep_alive) + cupsdCloseClient(con); + else + { + cupsArrayRemove(ActiveClients, con); + cupsdSetBusyState(); + } + } } @@ -2913,6 +2941,26 @@ check_if_modified( } +/* + * 'compare_clients()' - Compare two client connections. + */ + +static int /* O - Result of comparison */ +compare_clients(cupsd_client_t *a, /* I - First client */ + cupsd_client_t *b, /* I - Second client */ + void *data) /* I - User data (not used) */ +{ + (void)data; + + if (a == b) + return (0); + else if (a < b) + return (-1); + else + return (1); +} + + #ifdef HAVE_SSL /* * 'encrypt_client()' - Enable encryption for the client... @@ -3649,12 +3697,7 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ */ if ((options = strchr(con->uri, '?')) != NULL) - { - options ++; - - if (strchr(options, '=')) - cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options); - } + cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", options + 1); /* * Check for known types... @@ -3677,7 +3720,7 @@ is_cgi(cupsd_client_t *con, /* I - Client connection */ filename = strrchr(filename, '/') + 1; /* Filename always absolute */ - cupsdSetString(&con->options, options); + cupsdSetStringf(&con->options, " %s", options); cupsdLogMessage(CUPSD_LOG_DEBUG2, "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"", @@ -4678,6 +4721,8 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */ envp[envc ++] = con->query_string; } + else + envp[envc ++] = "QUERY_STRING="; } else { diff --git a/scheduler/client.h b/scheduler/client.h index f185c1e91..e6d946d47 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -93,8 +93,10 @@ VAR cups_array_t *Listeners VALUE(NULL); /* Listening sockets */ VAR time_t ListeningPaused VALUE(0); /* Time when listening was paused */ -VAR cups_array_t *Clients VALUE(NULL); +VAR cups_array_t *Clients VALUE(NULL), /* HTTP clients */ + *ActiveClients VALUE(NULL); + /* Active HTTP clients */ VAR http_addrlist_t *ServerAddrs VALUE(NULL); /* Server address(es) */ VAR char *ServerHeader VALUE(NULL); diff --git a/scheduler/conf.c b/scheduler/conf.c index c8e814886..de4d98adc 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -103,6 +103,7 @@ static const cupsd_var_t variables[] = { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING }, { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN }, + { "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_INTEGER }, { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, { "ErrorPolicy", &ErrorPolicy, CUPSD_VARTYPE_STRING }, @@ -516,6 +517,7 @@ cupsdReadConfiguration(void) #ifdef HAVE_SSL DefaultEncryption = HTTP_ENCRYPT_REQUIRED; #endif /* HAVE_SSL */ + DirtyCleanInterval = 60; JobRetryLimit = 5; JobRetryInterval = 300; FileDevice = FALSE; @@ -1188,7 +1190,7 @@ cupsdReadConfiguration(void) cupsdLoadAllPrinters(); cupsdLoadAllClasses(); cupsdLoadRemoteCache(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdCreateCommonData(); @@ -1219,7 +1221,7 @@ cupsdReadConfiguration(void) */ cupsdUpdatePrinters(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete."); } diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c index f9ee02320..5bc61f680 100644 --- a/scheduler/dirsvc.c +++ b/scheduler/dirsvc.c @@ -98,7 +98,7 @@ static void process_browse_data(const char *uri, const char *host, ipp_pstate_t state, const char *location, const char *info, const char *make_model, int num_attrs, cups_option_t *attrs); -static void process_implicit_classes(int *write_printcap); +static void process_implicit_classes(void); static void send_cups_browse(cupsd_printer_t *p); #ifdef HAVE_LDAP static void send_ldap_browse(cupsd_printer_t *p); @@ -616,7 +616,7 @@ cupsdLoadRemoteCache(void) * Do auto-classing if needed... */ - process_implicit_classes(NULL); + process_implicit_classes(); } @@ -801,7 +801,6 @@ cupsdSendBrowseList(void) cupsd_printer_t *p; /* Current printer */ time_t ut, /* Minimum update time */ to; /* Timeout time */ - int write_printcap; /* Write the printcap file? */ if (!Browsing || !BrowseLocalProtocols || !Printers) @@ -899,7 +898,7 @@ cupsdSendBrowseList(void) * Loop through all of the printers and send local updates as needed... */ - for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0; + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { @@ -924,13 +923,10 @@ cupsdSendBrowseList(void) cupsArraySave(Printers); cupsdDeletePrinter(p, 1); cupsArrayRestore(Printers); - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } } - - if (write_printcap) - cupsdWritePrintcap(); } @@ -1749,8 +1745,7 @@ process_browse_data( cups_option_t *attrs) /* I - Attributes */ { int i; /* Looping var */ - int update, /* Update printer attributes? */ - write_printcap; /* Write the printcap file? */ + int update; /* Update printer attributes? */ char finaluri[HTTP_MAX_URI], /* Final URI for printer */ name[IPP_MAX_NAME], /* Name of printer */ newname[IPP_MAX_NAME], /* New name of printer */ @@ -1837,12 +1832,11 @@ process_browse_data( * See if we already have it listed in the Printers list, and add it if not... */ - type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; - type &= ~CUPS_PRINTER_IMPLICIT; - update = 0; - write_printcap = 0; - hptr = strchr(host, '.'); - sptr = strchr(ServerName, '.'); + type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED; + type &= ~CUPS_PRINTER_IMPLICIT; + update = 0; + hptr = strchr(host, '.'); + sptr = strchr(ServerName, '.'); if (!ServerNameIsIP && sptr != NULL && hptr != NULL) { @@ -1965,8 +1959,9 @@ process_browse_data( cupsdSetString(&p->device_uri, uri); cupsdSetString(&p->hostname, host); - update = 1; - write_printcap = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } else @@ -2072,8 +2067,9 @@ process_browse_data( cupsdSetString(&p->uri, uri); cupsdSetString(&p->device_uri, uri); - write_printcap = 1; - update = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } } @@ -2132,8 +2128,9 @@ process_browse_data( if (info && (!p->info || strcmp(p->info, info))) { cupsdSetString(&p->info, info); - update = 1; - write_printcap = 1; + update = 1; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } if (!make_model || !make_model[0]) @@ -2198,7 +2195,7 @@ process_browse_data( cupsdDeletePrinter(p, 1); cupsdUpdateImplicitClasses(); - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); } else if (update) { @@ -2223,7 +2220,7 @@ process_browse_data( if (p->type & CUPS_PRINTER_DEFAULT) { DefaultPrinter = p; - write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); break; } } @@ -2232,14 +2229,7 @@ process_browse_data( * Do auto-classing if needed... */ - process_implicit_classes(&write_printcap); - - /* - * Update the printcap file... - */ - - if (write_printcap) - cupsdWritePrintcap(); + process_implicit_classes(); } @@ -2766,8 +2756,7 @@ dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */ */ static void -process_implicit_classes( - int *write_printcap) /* O - Write printcap file? */ +process_implicit_classes(void) { int i; /* Looping var */ int update; /* Update printer attributes? */ @@ -2848,8 +2837,7 @@ process_implicit_classes( update = 1; - if (write_printcap) - *write_printcap = 1; + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...", name); diff --git a/scheduler/ipp.c b/scheduler/ipp.c index f29006b86..dc08f621b 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -42,6 +42,8 @@ * cancel_job() - Cancel a print job. * cancel_subscription() - Cancel a subscription. * check_quotas() - Check quotas for a printer and user. + * check_rss_recipient() - Check that we do not have a duplicate RSS + * feed URI. * copy_attribute() - Copy a single attribute. * copy_attrs() - Copy attributes from one request to another. * copy_banner() - Copy a banner file to the requests directory @@ -157,6 +159,7 @@ static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_subscription(cupsd_client_t *con, int id); +static int check_rss_recipient(const char *recipient); static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p); static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr, int quickcopy); @@ -858,14 +861,14 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ if (dtype & CUPS_PRINTER_CLASS) { - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" now accepting jobs (\"%s\").", printer->name, get_username(con)); } else { - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").", @@ -1162,7 +1165,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ */ cupsdSetPrinterAttrs(pclass); - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); if (need_restart_job && pclass->job) { @@ -1183,7 +1186,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job) cupsdCheckJobs(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) { @@ -1265,6 +1268,9 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ job->num_files ++; + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + return (0); } @@ -1320,7 +1326,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ send_http_error(con, status, printer); return (NULL); } - else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && + else if (printer->num_auth_info_required > 0 && + strcmp(printer->auth_info_required[0], "none") && !con->username[0] && !auth_info) { send_http_error(con, HTTP_UNAUTHORIZED, printer); @@ -1388,6 +1395,34 @@ add_job(cupsd_client_t *con, /* I - Client connection */ } } + if ((attr = ippFindAttribute(con->request, "job-sheets", + IPP_TAG_ZERO)) != NULL) + { + if (attr->value_tag != IPP_TAG_KEYWORD && + attr->value_tag != IPP_TAG_NAME) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type!")); + return (NULL); + } + + if (attr->num_values > 2) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Too many job-sheets values (%d > 2)!"), + attr->num_values); + return (NULL); + } + + for (i = 0; i < attr->num_values; i ++) + if (strcmp(attr->values[i].string.text, "none") && + !cupsdFindBanner(attr->values[i].string.text)) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"!"), + attr->values[i].string.text); + return (NULL); + } + } + if ((attr = ippFindAttribute(con->request, "number-up", IPP_TAG_INTEGER)) != NULL) { @@ -1487,8 +1522,11 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE); job->attrs = con->request; + job->dirty = 1; con->request = ippNewRequest(job->attrs->request.op.operation_id); + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + add_job_uuid(con, job); apply_printer_defaults(printer, job); @@ -1812,7 +1850,10 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->id, attr->values[0].string.text); if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0) + { + cupsdDeleteJob(job); return (NULL); + } cupsdUpdateQuota(printer, job->username, 0, kbytes); } @@ -1986,10 +2027,70 @@ add_job_subscriptions( { if (!strcmp(attr->name, "notify-recipient-uri") && attr->value_tag == IPP_TAG_URI) + { + /* + * Validate the recipient scheme against the ServerBin/notifier + * directory... + */ + + char notifier[1024], /* Notifier filename */ + scheme[HTTP_MAX_URI], /* Scheme portion of URI */ + userpass[HTTP_MAX_URI], /* Username portion of URI */ + host[HTTP_MAX_URI], /* Host portion of URI */ + resource[HTTP_MAX_URI]; /* Resource portion of URI */ + int port; /* Port portion of URI */ + + recipient = attr->values[0].string.text; + + if (httpSeparateURI(HTTP_URI_CODING_ALL, recipient, + scheme, sizeof(scheme), userpass, sizeof(userpass), + host, sizeof(host), &port, + resource, sizeof(resource)) < HTTP_URI_OK) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Bad notify-recipient-uri URI \"%s\"!"), recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_URI_SCHEME); + return; + } + + snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, + scheme); + if (access(notifier, X_OK)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" uses unknown " + "scheme!"), recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_URI_SCHEME); + return; + } + + if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" is already used!"), + recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } + } else if (!strcmp(attr->name, "notify-pull-method") && attr->value_tag == IPP_TAG_KEYWORD) + { pullmethod = attr->values[0].string.text; + + if (strcmp(pullmethod, "ippget")) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Bad notify-pull-method \"%s\"!"), pullmethod); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } + } else if (!strcmp(attr->name, "notify-charset") && attr->value_tag == IPP_TAG_CHARSET && strcmp(attr->values[0].string.text, "us-ascii") && @@ -2071,7 +2172,7 @@ add_job_subscriptions( attr = attr->next; } - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); /* * Remove all of the subscription attributes from the job request... @@ -2720,7 +2821,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ */ cupsdSetPrinterAttrs(printer); - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); if (need_restart_job && printer->job) { @@ -2741,7 +2842,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job) cupsdCheckJobs(); - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) { @@ -3913,6 +4014,40 @@ cancel_subscription( } +/* + * 'check_rss_recipient()' - Check that we do not have a duplicate RSS feed URI. + */ + +static int /* O - 1 if OK, 0 if not */ +check_rss_recipient( + const char *recipient) /* I - Recipient URI */ +{ + cupsd_subscription_t *sub; /* Current subscription */ + + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if (sub->recipient) + { + /* + * Compare the URIs up to the first ?... + */ + + const char *r1, *r2; + + for (r1 = recipient, r2 = sub->recipient; + *r1 == *r2 && *r1 && *r1 != '?' && *r2 && *r2 != '?'; + r1 ++, r2 ++); + + if (*r1 == *r2) + return (0); + } + + return (1); +} + + /* * 'check_quotas()' - Check quotas for a printer and user. */ @@ -4436,7 +4571,8 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(%p[%d], %p[%d], %s)", + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")", con, con ? con->http.fd : -1, job, job->id, name ? name : "(null)"); @@ -4460,7 +4596,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ if ((out = cupsFileOpen(filename, "w")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "copy_banner: Unable to create banner job file %s - %s", + "Unable to create banner job file %s - %s", filename, strerror(errno)); job->num_files --; return (0); @@ -4516,7 +4652,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsFileClose(out); unlink(filename); cupsdLogMessage(CUPSD_LOG_ERROR, - "copy_banner: Unable to open banner template file %s - %s", + "Unable to open banner template file %s - %s", filename, strerror(errno)); job->num_files --; return (0); @@ -5453,8 +5589,6 @@ create_job(cupsd_client_t *con, /* I - Client connection */ * Save and log the job... */ - cupsdSaveJob(job); - cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Queued on \"%s\" by \"%s\".", job->id, job->dest, job->username); } @@ -5694,10 +5828,10 @@ create_subscription( for (attr = con->request->attrs; attr; attr = attr->next) { if (attr->group_tag != IPP_TAG_ZERO) - cupsdLogMessage(CUPSD_LOG_DEBUG, "g%04x v%04x %s", attr->group_tag, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "g%04x v%04x %s", attr->group_tag, attr->value_tag, attr->name); else - cupsdLogMessage(CUPSD_LOG_DEBUG, "----SEP----"); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "----SEP----"); } #endif /* DEBUG */ @@ -5851,6 +5985,16 @@ create_subscription( "notify-status-code", IPP_URI_SCHEME); return; } + + if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("notify-recipient-uri URI \"%s\" is already used!"), + recipient); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, + "notify-status-code", IPP_ATTRIBUTES); + return; + } } else if (!strcmp(attr->name, "notify-pull-method") && attr->value_tag == IPP_TAG_KEYWORD) @@ -6001,8 +6145,7 @@ create_subscription( attr = attr->next; } - cupsdSaveAllSubscriptions(); - + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } @@ -6091,7 +6234,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); } else { @@ -6099,10 +6242,10 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); /* * Return with no errors... @@ -6597,6 +6740,11 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ completed = 0; list = Jobs; } + else if (attr && !strcmp(attr->values[0].string.text, "printing")) + { + completed = 0; + list = PrintingJobs; + } else { completed = 0; @@ -6611,7 +6759,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) != NULL) limit = attr->values[0].integer; else - limit = 1000000; + limit = 0; if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) @@ -6637,7 +6785,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ */ for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list); - count < limit && job; + (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list)) { /* @@ -8271,8 +8419,6 @@ print_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] hold_until = %d", job->id, (int)job->hold_until); - cupsdSaveJob(job); - /* * Start the job if possible... */ @@ -8525,14 +8671,14 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ if (dtype & CUPS_PRINTER_CLASS) { - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").", printer->name, get_username(con)); } else { - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" rejecting jobs (\"%s\").", printer->name, get_username(con)); @@ -8761,7 +8907,7 @@ renew_subscription( sub->expire = sub->lease ? time(NULL) + sub->lease : 0; - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); con->response->request.status.status_code = IPP_OK; @@ -9485,7 +9631,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ } } - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * Start the job if possible... Since cupsdCheckJobs() can cancel a @@ -9509,7 +9656,9 @@ send_document(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; job->hold_until = time(NULL) + 60; - cupsdSaveJob(job); + job->dirty = 1; + + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } } @@ -9676,10 +9825,8 @@ set_default(cupsd_client_t *con, /* I - Client connection */ DefaultPrinter = printer; - cupsdSaveAllPrinters(); - cupsdSaveAllClasses(); - - cupsdWritePrintcap(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES | + CUPSD_DIRTY_REMOTE | CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Default destination set to \"%s\" by \"%s\".", @@ -10025,7 +10172,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Save the job... */ - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * Send events as needed... diff --git a/scheduler/job.c b/scheduler/job.c index 11cc5fe1d..0e4e94af9 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -21,6 +21,7 @@ * cupsdCheckJobs() - Check the pending jobs and start any if * the destination is available. * cupsdCleanJobs() - Clean out old jobs. + * cupsdDeleteJob() - Free all memory used by a job. * cupsdFinishJob() - Finish a job. * cupsdFreeAllJobs() - Free all jobs from memory. * cupsdFindJob() - Find the specified job. @@ -44,7 +45,6 @@ * compare_active_jobs() - Compare the job IDs and priorities of two * jobs. * compare_jobs() - Compare the job IDs of two jobs. - * free_job() - Free all memory used by a job. * ipp_length() - Compute the size of the buffer needed to * hold the textual IPP attributes. * load_job_cache() - Load jobs from the job.cache file. @@ -89,7 +89,6 @@ static mime_filter_t gziptoany_filter = static int compare_active_jobs(void *first, void *second, void *data); static int compare_jobs(void *first, void *second, void *data); -static void free_job(cupsd_job_t *job); static int ipp_length(ipp_t *ipp); static void load_job_cache(const char *filename); static void load_next_job_id(const char *filename); @@ -211,10 +210,11 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ cupsdExpireSubscriptions(NULL, job); /* - * Remove the job from the active list... + * Remove the job from the active and printing lists... */ cupsArrayRemove(ActiveJobs, job); + cupsArrayRemove(PrintingJobs, job); /* * Remove any authentication data... @@ -277,7 +277,8 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ * Save job state info... */ - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } else { @@ -299,8 +300,10 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ * Free all memory used... */ - free_job(job); + cupsdDeleteJob(job); } + + cupsdSetBusyState(); } @@ -395,7 +398,8 @@ cupsdCheckJobs(void) { attr->value_tag = IPP_TAG_KEYWORD; cupsdSetString(&(attr->values[0].string.text), "no-hold"); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } } @@ -462,6 +466,9 @@ cupsdCheckJobs(void) else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-actual-printer-uri", NULL, printer->uri); + + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */ @@ -510,6 +517,45 @@ cupsdCleanJobs(void) } +/* + * 'cupsdDeleteJob()' - Free all memory used by a job. + */ + +void +cupsdDeleteJob(cupsd_job_t *job) /* I - Job */ +{ + cupsdClearString(&job->username); + cupsdClearString(&job->dest); + cupsdClearString(&job->auth_username); + cupsdClearString(&job->auth_domain); + cupsdClearString(&job->auth_password); + +#ifdef HAVE_GSSAPI + /* + * Destroy the credential cache and clear the KRB5CCNAME env var string. + */ + + if (job->ccache) + { + krb5_cc_destroy(KerberosContext, job->ccache); + job->ccache = NULL; + } + + cupsdClearString(&job->ccname); +#endif /* HAVE_GSSAPI */ + + if (job->num_files > 0) + { + free(job->compressions); + free(job->filetypes); + } + + ippDelete(job->attrs); + + free(job); +} + + /* * 'cupsdFinishJob()' - Finish a job. */ @@ -608,7 +654,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state_value = IPP_JOB_PENDING; } - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); /* * If the job was queued to a class, try requeuing it... For @@ -686,7 +733,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Job held due to backend errors; please consult " @@ -703,7 +751,9 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, @@ -730,7 +780,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Authentication is required for job %d.", job->id); @@ -752,7 +803,8 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Job stopped due to filter errors.", job->id); cupsdStopJob(job, 1); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Job stopped due to filter errors; please consult the " "error_log file for details."); @@ -812,8 +864,9 @@ cupsdFreeAllJobs(void) { cupsArrayRemove(Jobs, job); cupsArrayRemove(ActiveJobs, job); + cupsArrayRemove(PrintingJobs, job); - free_job(job); + cupsdDeleteJob(job); } cupsdReleaseSignals(); @@ -902,7 +955,8 @@ cupsdHoldJob(cupsd_job_t *job) /* I - Job data */ job->state_value = IPP_JOB_HELD; job->current_file = 0; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdCheckJobs(); } @@ -931,6 +985,9 @@ cupsdLoadAllJobs(void) if (!ActiveJobs) ActiveJobs = cupsArrayNew(compare_active_jobs, NULL); + if (!PrintingJobs) + PrintingJobs = cupsArrayNew(compare_jobs, NULL); + /* * See whether the job.cache file is older than the RequestRoot directory... */ @@ -1317,7 +1374,8 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ "Job #%d moved from %s to %s.", job->id, olddest, p->name); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -1336,7 +1394,8 @@ cupsdReleaseJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdCheckJobs(); } } @@ -1364,7 +1423,8 @@ cupsdRestartJob(cupsd_job_t *job) /* I - Job */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); if (old_state > IPP_JOB_STOPPED) cupsArrayAdd(ActiveJobs, job); @@ -1479,6 +1539,8 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ "[Job %d] Unable to write job control file!", job->id); cupsFileClose(fp); + + job->dirty = 0; } @@ -1654,7 +1716,8 @@ cupsdSetJobPriority( cupsArrayAdd(ActiveJobs, job); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -1780,7 +1843,12 @@ cupsdUnloadCompletedJobs(void) job = (cupsd_job_t *)cupsArrayNext(Jobs)) if (job->attrs && job->state_value >= IPP_JOB_STOPPED && job->access_time < expire) + { + if (job->dirty) + cupsdSaveJob(job); + unload_job(job); + } } @@ -1817,45 +1885,6 @@ compare_jobs(void *first, /* I - First job */ } -/* - * 'free_job()' - Free all memory used by a job. - */ - -static void -free_job(cupsd_job_t *job) /* I - Job */ -{ - cupsdClearString(&job->username); - cupsdClearString(&job->dest); - cupsdClearString(&job->auth_username); - cupsdClearString(&job->auth_domain); - cupsdClearString(&job->auth_password); - -#ifdef HAVE_GSSAPI - /* - * Destroy the credential cache and clear the KRB5CCNAME env var string. - */ - - if (job->ccache) - { - krb5_cc_destroy(KerberosContext, job->ccache); - job->ccache = NULL; - } - - cupsdClearString(&job->ccname); -#endif /* HAVE_GSSAPI */ - - if (job->num_files > 0) - { - free(job->compressions); - free(job->filetypes); - } - - ippDelete(job->attrs); - - free(job); -} - - /* * 'ipp_length()' - Compute the size of the buffer needed to hold * the textual IPP attributes. @@ -2426,7 +2455,8 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ else cupsdSetString(&attr->values[0].string.text, holdstr); - cupsdSaveJob(job); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -2696,6 +2726,22 @@ start_job(cupsd_job_t *job, /* I - Job ID */ } } + /* + * Make sure we don't go over the "MAX_FILTERS" limit... + */ + + if (cupsArrayCount(filters) > MAX_FILTERS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "[Job %d] Too many filters (%d > %d), unable to print!", + job->id, cupsArrayCount(filters), MAX_FILTERS); + + cupsArrayDelete(filters); + cupsdCancelJob(job, 0, IPP_JOB_STOPPED); + + return; + } + /* * Update the printer and job state to "processing"... */ @@ -2711,6 +2757,13 @@ start_job(cupsd_job_t *job, /* I - Job ID */ if (job->current_file == 0) { + /* + * Add to the printing list... + */ + + cupsArrayAdd(PrintingJobs, job); + cupsdSetBusyState(); + /* * Set the processing time... */ @@ -3676,7 +3729,11 @@ update_job(cupsd_job_t *job) /* I - Job to check */ { cupsdSetAuthInfoRequired(job->printer, attr, NULL); cupsdSetPrinterAttrs(job->printer); - cupsdSaveAllPrinters(); + + if (job->printer->type & CUPS_PRINTER_DISCOVERED) + cupsdMarkDirty(CUPSD_DIRTY_REMOTE); + else + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL) diff --git a/scheduler/job.h b/scheduler/job.h index 78c836b75..09bf75ce0 100644 --- a/scheduler/job.h +++ b/scheduler/job.h @@ -20,7 +20,8 @@ typedef struct cupsd_job_s { int id, /* Job ID */ - priority; /* Job priority */ + priority, /* Job priority */ + dirty; /* Do we need to write the "c" file? */ ipp_jstate_t state_value; /* Cached job-state */ int pending_timeout;/* Non-zero if the job was created and waiting on files */ char *username; /* Printing user */ @@ -84,8 +85,10 @@ VAR int JobAutoPurge VALUE(0); /* Automatically purge jobs */ VAR cups_array_t *Jobs VALUE(NULL), /* List of current jobs */ - *ActiveJobs VALUE(NULL); + *ActiveJobs VALUE(NULL), /* List of active jobs */ + *PrintingJobs VALUE(NULL); + /* List of jobs that are printing */ VAR int NextJobId VALUE(1); /* Next job ID to use */ VAR int JobRetryLimit VALUE(5), diff --git a/scheduler/main.c b/scheduler/main.c index e831920a0..4c7c697e9 100644 --- a/scheduler/main.c +++ b/scheduler/main.c @@ -862,6 +862,16 @@ main(int argc, /* I - Number of command-line args */ current_time = time(NULL); + /* + * Write dirty config/state files... + */ + + if (DirtyCleanTime && current_time >= DirtyCleanTime) + { + cupsdCleanDirty(); + cupsdSetBusyState(); + } + #ifndef __APPLE__ /* * Update the network interfaces once a minute... @@ -1622,27 +1632,6 @@ process_children(void) cupsdFinishProcess(pid, name, sizeof(name)); - if (status == SIGTERM) - status = 0; - - if (status) - { - if (WIFEXITED(status)) - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!", - pid, name, WEXITSTATUS(status)); - else - cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!", - pid, name, WTERMSIG(status)); - - if (LogLevel < CUPSD_LOG_DEBUG) - cupsdLogMessage(CUPSD_LOG_INFO, - "Hint: Try setting the LogLevel to \"debug\" to find " - "out more."); - } - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", - pid, name); - /* * Delete certificates for CGI processes... */ @@ -1674,6 +1663,9 @@ process_children(void) else job->backend = -pid; + if (job->state_value == IPP_JOB_CANCELED) + status = 0; /* Ignore errors when canceling jobs */ + if (status && job->status >= 0) { /* @@ -1721,6 +1713,31 @@ process_children(void) break; } } + + /* + * Show the exit status as needed... + */ + + if (status == SIGTERM) + status = 0; + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) stopped with status %d!", + pid, name, WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d (%s) crashed on signal %d!", + pid, name, WTERMSIG(status)); + + if (LogLevel < CUPSD_LOG_DEBUG) + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Try setting the LogLevel to \"debug\" to find " + "out more."); + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "PID %d (%s) exited with no errors.", + pid, name); } } @@ -1906,6 +1923,16 @@ select_timeout(int fds) /* I - Number of descriptors returned */ } } + /* + * Check for any active jobs... + */ + + if (DirtyCleanTime && timeout > DirtyCleanTime) + { + timeout = DirtyCleanTime; + why = "write dirty config/state files"; + } + /* * Check for any active jobs... */ diff --git a/scheduler/printers.c b/scheduler/printers.c index 6dc8bd971..11abd6b8d 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -2793,9 +2793,9 @@ cupsdSetPrinterState( update) { if (p->type & CUPS_PRINTER_CLASS) - cupsdSaveAllClasses(); + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); else - cupsdSaveAllPrinters(); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } } @@ -2841,8 +2841,9 @@ cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + job->dirty = 1; - cupsdSaveJob(job); + cupsdMarkDirty(CUPSD_DIRTY_JOBS); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job, "Job stopped due to printer being paused"); diff --git a/scheduler/server.c b/scheduler/server.c index dcff28baa..9483ae658 100644 --- a/scheduler/server.c +++ b/scheduler/server.c @@ -3,7 +3,7 @@ * * Server start/stop routines for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -137,7 +137,6 @@ cupsdStopServer(void) cupsdStopPolling(); cupsdStopBrowsing(); cupsdStopAllNotifiers(); - cupsdSaveRemoteCache(); cupsdDeleteAllCerts(); if (Clients) @@ -203,6 +202,13 @@ cupsdStopServer(void) cupsdDestroyProfile(DefaultProfile); DefaultProfile = NULL; + /* + * Write out any dirty files... + */ + + if (DirtyFiles) + cupsdCleanDirty(); + started = 0; } diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c index 5bbb38c28..cea357fd3 100644 --- a/scheduler/subscriptions.c +++ b/scheduler/subscriptions.c @@ -297,7 +297,7 @@ cupsdAddEvent( } if (temp) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); else cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...", cupsdEventName(event)); @@ -463,7 +463,7 @@ cupsdDeleteSubscription( */ if (update) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } @@ -646,7 +646,7 @@ cupsdExpireSubscriptions( } if (update) - cupsdSaveAllSubscriptions(); + cupsdMarkDirty(CUPSD_DIRTY_SUBSCRIPTIONS); } diff --git a/scheduler/sysman.c b/scheduler/sysman.c index 03aa8d035..636cc9475 100644 --- a/scheduler/sysman.c +++ b/scheduler/sysman.c @@ -3,7 +3,7 @@ * * System management definitions for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -14,6 +14,11 @@ * * Contents: * + * cupsdCleanDirty() - Write dirty config and state files. + * cupsdMarkDirty() - Mark config or state files as needing a + * write. + * cupsdSetBusyState() - Let the system know when we are busy + * doing something. * cupsdStartSystemMonitor() - Start monitoring for system change. * cupsdStopSystemMonitor() - Stop monitoring for system change. * cupsdUpdateSystemMonitor() - Update the current system state. @@ -34,15 +39,108 @@ /* - * Power management is a new addition to CUPS. Right now it is only - * implemented on MacOS X, but essentially we use these three functions - * to let the OS know when it is OK to put the system to sleep, typically - * when we are not in the middle of printing a job. + * The system management functions cover disk and power management which + * are primarily used on portable computers. * - * Once put to sleep, we invalidate all remote printers since it is - * common to wake up in a new location. + * Disk management involves delaying the write of certain configuration + * and state files to minimize the number of times the disk has to spin + * up. + * + * Power management support is currently only implemented on MacOS X, but + * essentially we use four functions to let the OS know when it is OK to + * put the system to idle sleep, typically when we are not in the middle of + * printing a job. + * + * Once put to sleep, we invalidate all remote printers since it is common + * to wake up in a new location/on a new wireless network. + */ + + +/* + * 'cupsdCleanDirty()' - Write dirty config and state files. + */ + +void +cupsdCleanDirty(void) +{ + if (DirtyFiles & CUPSD_DIRTY_PRINTERS) + cupsdSaveAllPrinters(); + + if (DirtyFiles & CUPSD_DIRTY_CLASSES) + cupsdSaveAllClasses(); + + if (DirtyFiles & CUPSD_DIRTY_REMOTE) + cupsdSaveRemoteCache(); + + if (DirtyFiles & CUPSD_DIRTY_PRINTCAP) + cupsdWritePrintcap(); + + if (DirtyFiles & CUPSD_DIRTY_JOBS) + { + cupsd_job_t *job; /* Current job */ + + cupsdSaveAllJobs(); + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if (job->dirty) + cupsdSaveJob(job); + } + + if (DirtyFiles & CUPSD_DIRTY_SUBSCRIPTIONS) + cupsdSaveAllSubscriptions(); + + DirtyFiles = CUPSD_DIRTY_NONE; + DirtyCleanTime = 0; +} + + +/* + * 'cupsdMarkDirty()' - Mark config or state files as needing a write. */ +void +cupsdMarkDirty(int what) /* I - What file(s) are dirty? */ +{ + DirtyFiles |= what; + + if (!DirtyCleanTime) + DirtyCleanTime = time(NULL) + DirtyCleanInterval; + + cupsdSetBusyState(); +} + + +/* + * 'cupsdSetBusyState()' - Let the system know when we are busy doing something. + */ + +void +cupsdSetBusyState(void) +{ + int newbusy; /* New busy state */ + static int busy = 0; /* Current busy state */ + + + newbusy = DirtyCleanTime || + cupsArrayCount(PrintingJobs) || + cupsArrayCount(ActiveClients); + + if (newbusy != busy) + { + busy = newbusy; + + if (busy) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSetBusyState: Server no longer busy..."); + else + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSetBusyState: Server is now busy..."); + } +} + + #ifdef __APPLE__ /* * This is the Apple-specific system event code. It works by creating @@ -280,7 +378,6 @@ cupsdUpdateSystemMonitor(void) Sleeping = 1; cupsdStopAllJobs(0); - cupsdSaveAllJobs(); for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; @@ -302,6 +399,8 @@ cupsdUpdateSystemMonitor(void) } } + cupsdCleanDirty(); + IOAllowPowerChange(sysevent.powerKernelPort, sysevent.powerNotificationID); } diff --git a/scheduler/sysman.h b/scheduler/sysman.h index e30be84bf..50ef17f96 100644 --- a/scheduler/sysman.h +++ b/scheduler/sysman.h @@ -3,7 +3,7 @@ * * System management definitions for the Common UNIX Printing System (CUPS). * - * Copyright 2007 by Apple Inc. + * Copyright 2007-2008 by Apple Inc. * Copyright 2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -13,10 +13,28 @@ * file is missing or damaged, see the license at "http://www.cups.org/". */ +/* + * Constants... + */ + +#define CUPSD_DIRTY_NONE 0 /* Nothing is dirty */ +#define CUPSD_DIRTY_PRINTERS 1 /* printers.conf is dirty */ +#define CUPSD_DIRTY_CLASSES 2 /* classes.conf is dirty */ +#define CUPSD_DIRTY_REMOTE 4 /* remote.cache is dirty */ +#define CUPSD_DIRTY_PRINTCAP 8 /* printcap is dirty */ +#define CUPSD_DIRTY_JOBS 16 /* jobs.cache or "c" file(s) are dirty */ +#define CUPSD_DIRTY_SUBSCRIPTIONS 32 /* subscriptions.conf is dirty */ + /* * Globals... */ +VAR int DirtyFiles VALUE(CUPSD_DIRTY_NONE), + /* What files are dirty? */ + DirtyCleanInterval VALUE(60); + /* How often do we write dirty files? */ +VAR time_t DirtyCleanTime VALUE(0); + /* When to clean dirty files next */ VAR int Sleeping VALUE(0); /* Non-zero if machine is entering or * * in a sleep state... */ @@ -30,6 +48,9 @@ VAR int SysEventPipes[2] VALUE2(-1,-1); * Prototypes... */ +extern void cupsdCleanDirty(void); +extern void cupsdMarkDirty(int what); +extern void cupsdSetBusyState(void); extern void cupsdStartSystemMonitor(void); extern void cupsdStopSystemMonitor(void); extern void cupsdUpdateSystemMonitor(void); diff --git a/standards/rfc3875.txt b/standards/rfc3875.txt new file mode 100644 index 000000000..41296e1ea --- /dev/null +++ b/standards/rfc3875.txt @@ -0,0 +1,2019 @@ + + + + + + +Network Working Group D. Robinson +Request for Comments: 3875 K. Coar +Category: Informational The Apache Software Foundation + October 2004 + + + The Common Gateway Interface (CGI) Version 1.1 + +Status of this Memo + + This memo provides information for the Internet community. It does + not specify an Internet standard of any kind. Distribution of this + memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2004). + +IESG Note + + This document is not a candidate for any level of Internet Standard. + The IETF disclaims any knowledge of the fitness of this document for + any purpose, and in particular notes that it has not had IETF review + for such things as security, congestion control or inappropriate + interaction with deployed protocols. The RFC Editor has chosen to + publish this document at its discretion. Readers of this document + should exercise caution in evaluating its value for implementation + and deployment. + +Abstract + + The Common Gateway Interface (CGI) is a simple interface for running + external programs, software or gateways under an information server + in a platform-independent manner. Currently, the supported + information servers are HTTP servers. + + The interface has been in use by the World-Wide Web (WWW) since 1993. + This specification defines the 'current practice' parameters of the + 'CGI/1.1' interface developed and documented at the U.S. National + Centre for Supercomputing Applications. This document also defines + the use of the CGI/1.1 interface on UNIX(R) and other, similar + systems. + + + + + + + + + +Robinson & Coar Informational [Page 1] + +RFC 3875 CGI Version 1.1 October 2004 + + +Table of Contents + + 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Purpose . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.2. Requirements . . . . . . . . . . . . . . . . . . . . . . 4 + 1.3. Specifications . . . . . . . . . . . . . . . . . . . . . 4 + 1.4. Terminology . . . . . . . . . . . . . . . . . . . . . . 5 + + 2. Notational Conventions and Generic Grammar. . . . . . . . . . 5 + 2.1. Augmented BNF . . . . . . . . . . . . . . . . . . . . . 5 + 2.2. Basic Rules . . . . . . . . . . . . . . . . . . . . . . 6 + 2.3. URL Encoding . . . . . . . . . . . . . . . . . . . . . . 7 + + 3. Invoking the Script . . . . . . . . . . . . . . . . . . . . . 8 + 3.1. Server Responsibilities . . . . . . . . . . . . . . . . 8 + 3.2. Script Selection . . . . . . . . . . . . . . . . . . . . 9 + 3.3. The Script-URI . . . . . . . . . . . . . . . . . . . . . 9 + 3.4. Execution . . . . . . . . . . . . . . . . . . . . . . . 10 + + 4. The CGI Request . . . . . . . . . . . . . . . . . . . . . . . 10 + 4.1. Request Meta-Variables . . . . . . . . . . . . . . . . . 10 + 4.1.1. AUTH_TYPE. . . . . . . . . . . . . . . . . . . . 11 + 4.1.2. CONTENT_LENGTH . . . . . . . . . . . . . . . . . 12 + 4.1.3. CONTENT_TYPE . . . . . . . . . . . . . . . . . . 12 + 4.1.4. GATEWAY_INTERFACE. . . . . . . . . . . . . . . . 13 + 4.1.5. PATH_INFO. . . . . . . . . . . . . . . . . . . . 13 + 4.1.6. PATH_TRANSLATED. . . . . . . . . . . . . . . . . 14 + 4.1.7. QUERY_STRING . . . . . . . . . . . . . . . . . . 15 + 4.1.8. REMOTE_ADDR. . . . . . . . . . . . . . . . . . . 15 + 4.1.9. REMOTE_HOST. . . . . . . . . . . . . . . . . . . 16 + 4.1.10. REMOTE_IDENT . . . . . . . . . . . . . . . . . . 16 + 4.1.11. REMOTE_USER. . . . . . . . . . . . . . . . . . . 16 + 4.1.12. REQUEST_METHOD . . . . . . . . . . . . . . . . . 17 + 4.1.13. SCRIPT_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.14. SERVER_NAME. . . . . . . . . . . . . . . . . . . 17 + 4.1.15. SERVER_PORT. . . . . . . . . . . . . . . . . . . 18 + 4.1.16. SERVER_PROTOCOL. . . . . . . . . . . . . . . . . 18 + 4.1.17. SERVER_SOFTWARE. . . . . . . . . . . . . . . . . 19 + 4.1.18. Protocol-Specific Meta-Variables . . . . . . . . 19 + 4.2. Request Message-Body . . . . . . . . . . . . . . . . . . 20 + 4.3. Request Methods . . . . . . . . . . . . . . . . . . . . 20 + 4.3.1. GET. . . . . . . . . . . . . . . . . . . . . . . 20 + 4.3.2. POST . . . . . . . . . . . . . . . . . . . . . . 21 + 4.3.3. HEAD . . . . . . . . . . . . . . . . . . . . . . 21 + 4.3.4. Protocol-Specific Methods. . . . . . . . . . . . 21 + 4.4. The Script Command Line. . . . . . . . . . . . . . . . . 21 + + + + + +Robinson & Coar Informational [Page 2] + +RFC 3875 CGI Version 1.1 October 2004 + + + 5. NPH Scripts . . . . . . . . . . . . . . . . . . . . . . . . . 22 + 5.1. Identification . . . . . . . . . . . . . . . . . . . . . 22 + 5.2. NPH Response . . . . . . . . . . . . . . . . . . . . . . 22 + + 6. CGI Response. . . . . . . . . . . . . . . . . . . . . . . . . 23 + 6.1. Response Handling. . . . . . . . . . . . . . . . . . . . 23 + 6.2. Response Types . . . . . . . . . . . . . . . . . . . . . 23 + 6.2.1. Document Response. . . . . . . . . . . . . . . . 23 + 6.2.2. Local Redirect Response. . . . . . . . . . . . . 24 + 6.2.3. Client Redirect Response . . . . . . . . . . . . 24 + 6.2.4. Client Redirect Response with Document . . . . . 24 + 6.3. Response Header Fields . . . . . . . . . . . . . . . . . 25 + 6.3.1. Content-Type . . . . . . . . . . . . . . . . . . 25 + 6.3.2. Location . . . . . . . . . . . . . . . . . . . . 26 + 6.3.3. Status . . . . . . . . . . . . . . . . . . . . . 26 + 6.3.4. Protocol-Specific Header Fields. . . . . . . . . 27 + 6.3.5. Extension Header Fields. . . . . . . . . . . . . 27 + 6.4. Response Message-Body. . . . . . . . . . . . . . . . . . 28 + + 7. System Specifications . . . . . . . . . . . . . . . . . . . . 28 + 7.1. AmigaDOS . . . . . . . . . . . . . . . . . . . . . . . . 28 + 7.2. UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . 28 + 7.3. EBCDIC/POSIX . . . . . . . . . . . . . . . . . . . . . . 29 + + 8. Implementation. . . . . . . . . . . . . . . . . . . . . . . . 29 + 8.1. Recommendations for Servers. . . . . . . . . . . . . . . 29 + 8.2. Recommendations for Scripts. . . . . . . . . . . . . . . 30 + + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 30 + 9.1. Safe Methods . . . . . . . . . . . . . . . . . . . . . . 30 + 9.2. Header Fields Containing Sensitive Information . . . . . 31 + 9.3. Data Privacy . . . . . . . . . . . . . . . . . . . . . . 31 + 9.4. Information Security Model . . . . . . . . . . . . . . . 31 + 9.5. Script Interference with the Server. . . . . . . . . . . 31 + 9.6. Data Length and Buffering Considerations . . . . . . . . 32 + 9.7. Stateless Processing . . . . . . . . . . . . . . . . . . 32 + 9.8. Relative Paths . . . . . . . . . . . . . . . . . . . . . 33 + 9.9. Non-parsed Header Output . . . . . . . . . . . . . . . . 33 + + 10. Acknowledgements. . . . . . . . . . . . . . . . . . . . . . . 33 + + 11. References. . . . . . . . . . . . . . . . . . . . . . . . . . 33 + 11.1. Normative References. . . . . . . . . . . . . . . . . . 33 + 11.2. Informative References. . . . . . . . . . . . . . . . . 34 + + 12. Authors' Addresses. . . . . . . . . . . . . . . . . . . . . . 35 + + 13. Full Copyright Statement. . . . . . . . . . . . . . . . . . . 36 + + + +Robinson & Coar Informational [Page 3] + +RFC 3875 CGI Version 1.1 October 2004 + + +1. Introduction + +1.1. Purpose + + The Common Gateway Interface (CGI) [22] allows an HTTP [1], [4] + server and a CGI script to share responsibility for responding to + client requests. The client request comprises a Uniform Resource + Identifier (URI) [11], a request method and various ancillary + information about the request provided by the transport protocol. + + The CGI defines the abstract parameters, known as meta-variables, + which describe a client's request. Together with a concrete + programmer interface this specifies a platform-independent interface + between the script and the HTTP server. + + The server is responsible for managing connection, data transfer, + transport and network issues related to the client request, whereas + the CGI script handles the application issues, such as data access + and document processing. + +1.2. Requirements + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL NOT', + 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'MAY' and 'OPTIONAL' in this + document are to be interpreted as described in BCP 14, RFC 2119 [3]. + + An implementation is not compliant if it fails to satisfy one or more + of the 'must' requirements for the protocols it implements. An + implementation that satisfies all of the 'must' and all of the + 'should' requirements for its features is said to be 'unconditionally + compliant'; one that satisfies all of the 'must' requirements but not + all of the 'should' requirements for its features is said to be + 'conditionally compliant'. + +1.3. Specifications + + Not all of the functions and features of the CGI are defined in the + main part of this specification. The following phrases are used to + describe the features that are not specified: + + 'system-defined' + The feature may differ between systems, but must be the same for + different implementations using the same system. A system will + usually identify a class of operating systems. Some systems are + defined in section 7 of this document. New systems may be defined + by new specifications without revision of this document. + + + + + +Robinson & Coar Informational [Page 4] + +RFC 3875 CGI Version 1.1 October 2004 + + + 'implementation-defined' + The behaviour of the feature may vary from implementation to + implementation; a particular implementation must document its + behaviour. + +1.4. Terminology + + This specification uses many terms defined in the HTTP/1.1 + specification [4]; however, the following terms are used here in a + sense which may not accord with their definitions in that document, + or with their common meaning. + + 'meta-variable' + A named parameter which carries information from the server to the + script. It is not necessarily a variable in the operating + system's environment, although that is the most common + implementation. + + 'script' + The software that is invoked by the server according to this + interface. It need not be a standalone program, but could be a + dynamically-loaded or shared library, or even a subroutine in the + server. It might be a set of statements interpreted at run-time, + as the term 'script' is frequently understood, but that is not a + requirement and within the context of this specification the term + has the broader definition stated. + + 'server' + The application program that invokes the script in order to + service requests from the client. + +2. Notational Conventions and Generic Grammar + +2.1. Augmented BNF + + All of the mechanisms specified in this document are described in + both prose and an augmented Backus-Naur Form (BNF) similar to that + used by RFC 822 [13]. Unless stated otherwise, the elements are + case-sensitive. This augmented BNF contains the following + constructs: + + name = definition + The name of a rule and its definition are separated by the equals + character ('='). Whitespace is only significant in that + continuation lines of a definition are indented. + + + + + + +Robinson & Coar Informational [Page 5] + +RFC 3875 CGI Version 1.1 October 2004 + + + "literal" + Double quotation marks (") surround literal text, except for a + literal quotation mark, which is surrounded by angle-brackets ('<' + and '>'). + + rule1 | rule2 + Alternative rules are separated by a vertical bar ('|'). + + (rule1 rule2 rule3) + Elements enclosed in parentheses are treated as a single element. + + *rule + A rule preceded by an asterisk ('*') may have zero or more + occurrences. The full form is 'n*m rule' indicating at least n + and at most m occurrences of the rule. n and m are optional + decimal values with default values of 0 and infinity respectively. + + [rule] + An element enclosed in square brackets ('[' and ']') is optional, + and is equivalent to '*1 rule'. + + N rule + A rule preceded by a decimal number represents exactly N + occurrences of the rule. It is equivalent to 'N*N rule'. + +2.2. Basic Rules + + This specification uses a BNF-like grammar defined in terms of + characters. Unlike many specifications which define the bytes + allowed by a protocol, here each literal in the grammar corresponds + to the character it represents. How these characters are represented + in terms of bits and bytes within a system are either system-defined + or specified in the particular context. The single exception is the + rule 'OCTET', defined below. + + The following rules are used throughout this specification to + describe basic parsing constructs. + + alpha = lowalpha | hialpha + lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | + "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | + "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | + "y" | "z" + hialpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | + "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | + "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | + "Y" | "Z" + + + + +Robinson & Coar Informational [Page 6] + +RFC 3875 CGI Version 1.1 October 2004 + + + digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | + "8" | "9" + alphanum = alpha | digit + OCTET = + CHAR = alpha | digit | separator | "!" | "#" | "$" | + "%" | "&" | "'" | "*" | "+" | "-" | "." | "`" | + "^" | "_" | "{" | "|" | "}" | "~" | CTL + CTL = + SP = + HT = + NL = + LWSP = SP | HT | NL + separator = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | + "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{" | + "}" | SP | HT + token = 1* + quoted-string = <"> *qdtext <"> + qdtext = and CTLs but including LWSP> + TEXT = + + Note that newline (NL) need not be a single control character, but + can be a sequence of control characters. A system MAY define TEXT to + be a larger set of characters than . + +2.3. URL Encoding + + Some variables and constructs used here are described as being + 'URL-encoded'. This encoding is described in section 2 of RFC 2396 + [2]. In a URL-encoded string an escape sequence consists of a + percent character ("%") followed by two hexadecimal digits, where the + two hexadecimal digits form an octet. An escape sequence represents + the graphic character that has the octet as its code within the + US-ASCII [9] coded character set, if it exists. Currently there is + no provision within the URI syntax to identify which character set + non-ASCII codes represent, so CGI handles this issue on an ad-hoc + basis. + + Note that some unsafe (reserved) characters may have different + semantics when encoded. The definition of which characters are + unsafe depends on the context; see section 2 of RFC 2396 [2], updated + by RFC 2732 [7], for an authoritative treatment. These reserved + characters are generally used to provide syntactic structure to the + character string, for example as field separators. In all cases, the + string is first processed with regard to any reserved characters + present, and then the resulting data can be URL-decoded by replacing + "%" escape sequences by their character values. + + + + +Robinson & Coar Informational [Page 7] + +RFC 3875 CGI Version 1.1 October 2004 + + + To encode a character string, all reserved and forbidden characters + are replaced by the corresponding "%" escape sequences. The string + can then be used in assembling a URI. The reserved characters will + vary from context to context, but will always be drawn from this set: + + reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | + "," | "[" | "]" + + The last two characters were added by RFC 2732 [7]. In any + particular context, a sub-set of these characters will be reserved; + the other characters from this set MUST NOT be encoded when a string + is URL-encoded in that context. Other basic rules used to describe + URI syntax are: + + hex = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" + | "c" | "d" | "e" | "f" + escaped = "%" hex hex + unreserved = alpha | digit | mark + mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + +3. Invoking the Script + +3.1. Server Responsibilities + + The server acts as an application gateway. It receives the request + from the client, selects a CGI script to handle the request, converts + the client request to a CGI request, executes the script and converts + the CGI response into a response for the client. When processing the + client request, it is responsible for implementing any protocol or + transport level authentication and security. The server MAY also + function in a 'non-transparent' manner, modifying the request or + response in order to provide some additional service, such as media + type transformation or protocol reduction. + + The server MUST perform translations and protocol conversions on the + client request data required by this specification. Furthermore, the + server retains its responsibility to the client to conform to the + relevant network protocol even if the CGI script fails to conform to + this specification. + + If the server is applying authentication to the request, then it MUST + NOT execute the script unless the request passes all defined access + controls. + + + + + + + + +Robinson & Coar Informational [Page 8] + +RFC 3875 CGI Version 1.1 October 2004 + + +3.2. Script Selection + + The server determines which CGI is script to be executed based on a + generic-form URI supplied by the client. This URI includes a + hierarchical path with components separated by "/". For any + particular request, the server will identify all or a leading part of + this path with an individual script, thus placing the script at a + particular point in the path hierarchy. The remainder of the path, + if any, is a resource or sub-resource identifier to be interpreted by + the script. + + Information about this split of the path is available to the script + in the meta-variables, described below. Support for non-hierarchical + URI schemes is outside the scope of this specification. + +3.3. The Script-URI + + The mapping from client request URI to choice of script is defined by + the particular server implementation and its configuration. The + server may allow the script to be identified with a set of several + different URI path hierarchies, and therefore is permitted to replace + the URI by other members of this set during processing and generation + of the meta-variables. The server + + 1. MAY preserve the URI in the particular client request; or + + 2. it MAY select a canonical URI from the set of possible values + for each script; or + + 3. it can implement any other selection of URI from the set. + + From the meta-variables thus generated, a URI, the 'Script-URI', can + be constructed. This MUST have the property that if the client had + accessed this URI instead, then the script would have been executed + with the same values for the SCRIPT_NAME, PATH_INFO and QUERY_STRING + meta-variables. The Script-URI has the structure of a generic URI as + defined in section 3 of RFC 2396 [2], with the exception that object + parameters and fragment identifiers are not permitted. The various + components of the Script-URI are defined by some of the + meta-variables (see below); + + script-URI = "://" ":" + "?" + + where is found from SERVER_PROTOCOL, , + and are the values of the respective + meta-variables. The SCRIPT_NAME and PATH_INFO values, URL-encoded + with ";", "=" and "?" reserved, give and . + + + +Robinson & Coar Informational [Page 9] + +RFC 3875 CGI Version 1.1 October 2004 + + + See section 4.1.5 for more information about the PATH_INFO + meta-variable. + + The scheme and the protocol are not identical as the scheme + identifies the access method in addition to the application protocol. + For example, a resource accessed using Transport Layer Security (TLS) + [14] would have a request URI with a scheme of https when using the + HTTP protocol [19]. CGI/1.1 provides no generic means for the script + to reconstruct this, and therefore the Script-URI as defined includes + the base protocol used. However, a script MAY make use of + scheme-specific meta-variables to better deduce the URI scheme. + + Note that this definition also allows URIs to be constructed which + would invoke the script with any permitted values for the path-info + or query-string, by modifying the appropriate components. + +3.4. Execution + + The script is invoked in a system-defined manner. Unless specified + otherwise, the file containing the script will be invoked as an + executable program. The server prepares the CGI request as described + in section 4; this comprises the request meta-variables (immediately + available to the script on execution) and request message data. The + request data need not be immediately available to the script; the + script can be executed before all this data has been received by the + server from the client. The response from the script is returned to + the server as described in sections 5 and 6. + + In the event of an error condition, the server can interrupt or + terminate script execution at any time and without warning. That + could occur, for example, in the event of a transport failure between + the server and the client; so the script SHOULD be prepared to handle + abnormal termination. + +4. The CGI Request + + Information about a request comes from two different sources; the + request meta-variables and any associated message-body. + +4.1. Request Meta-Variables + + Meta-variables contain data about the request passed from the server + to the script, and are accessed by the script in a system-defined + manner. Meta-variables are identified by case-insensitive names; + there cannot be two different variables whose names differ in case + only. Here they are shown using a canonical representation of + capitals plus underscore ("_"). A particular system can define a + different representation. + + + +Robinson & Coar Informational [Page 10] + +RFC 3875 CGI Version 1.1 October 2004 + + + meta-variable-name = "AUTH_TYPE" | "CONTENT_LENGTH" | + "CONTENT_TYPE" | "GATEWAY_INTERFACE" | + "PATH_INFO" | "PATH_TRANSLATED" | + "QUERY_STRING" | "REMOTE_ADDR" | + "REMOTE_HOST" | "REMOTE_IDENT" | + "REMOTE_USER" | "REQUEST_METHOD" | + "SCRIPT_NAME" | "SERVER_NAME" | + "SERVER_PORT" | "SERVER_PROTOCOL" | + "SERVER_SOFTWARE" | scheme | + protocol-var-name | extension-var-name + protocol-var-name = ( protocol | scheme ) "_" var-name + scheme = alpha *( alpha | digit | "+" | "-" | "." ) + var-name = token + extension-var-name = token + + Meta-variables with the same name as a scheme, and names beginning + with the name of a protocol or scheme (e.g., HTTP_ACCEPT) are also + defined. The number and meaning of these variables may change + independently of this specification. (See also section 4.1.18.) + + The server MAY set additional implementation-defined extension meta- + variables, whose names SHOULD be prefixed with "X_". + + This specification does not distinguish between zero-length (NULL) + values and missing values. For example, a script cannot distinguish + between the two requests http://host/script and http://host/script? + as in both cases the QUERY_STRING meta-variable would be NULL. + + meta-variable-value = "" | 1* + + An optional meta-variable may be omitted (left unset) if its value is + NULL. Meta-variable values MUST be considered case-sensitive except + as noted otherwise. The representation of the characters in the + meta-variables is system-defined; the server MUST convert values to + that representation. + +4.1.1. AUTH_TYPE + + The AUTH_TYPE variable identifies any mechanism used by the server to + authenticate the user. It contains a case-insensitive value defined + by the client protocol or server implementation. + + For HTTP, if the client request required authentication for external + access, then the server MUST set the value of this variable from the + 'auth-scheme' token in the request Authorization header field. + + + + + + +Robinson & Coar Informational [Page 11] + +RFC 3875 CGI Version 1.1 October 2004 + + + AUTH_TYPE = "" | auth-scheme + auth-scheme = "Basic" | "Digest" | extension-auth + extension-auth = token + + HTTP access authentication schemes are described in RFC 2617 [5]. + +4.1.2. CONTENT_LENGTH + + The CONTENT_LENGTH variable contains the size of the message-body + attached to the request, if any, in decimal number of octets. If no + data is attached, then NULL (or unset). + + CONTENT_LENGTH = "" | 1*digit + + The server MUST set this meta-variable if and only if the request is + accompanied by a message-body entity. The CONTENT_LENGTH value must + reflect the length of the message-body after the server has removed + any transfer-codings or content-codings. + +4.1.3. CONTENT_TYPE + + If the request includes a message-body, the CONTENT_TYPE variable is + set to the Internet Media Type [6] of the message-body. + + CONTENT_TYPE = "" | media-type + media-type = type "/" subtype *( ";" parameter ) + type = token + subtype = token + parameter = attribute "=" value + attribute = token + value = token | quoted-string + + The type, subtype and parameter attribute names are not + case-sensitive. Parameter values may be case sensitive. Media types + and their use in HTTP are described section 3.7 of the HTTP/1.1 + specification [4]. + + There is no default value for this variable. If and only if it is + unset, then the script MAY attempt to determine the media type from + the data received. If the type remains unknown, then the script MAY + choose to assume a type of application/octet-stream or it may reject + the request with an error (as described in section 6.3.3). + + Each media-type defines a set of optional and mandatory parameters. + This may include a charset parameter with a case-insensitive value + defining the coded character set for the message-body. If the + + + + + +Robinson & Coar Informational [Page 12] + +RFC 3875 CGI Version 1.1 October 2004 + + + charset parameter is omitted, then the default value should be + derived according to whichever of the following rules is the first to + apply: + + 1. There MAY be a system-defined default charset for some + media-types. + + 2. The default for media-types of type "text" is ISO-8859-1 [4]. + + 3. Any default defined in the media-type specification. + + 4. The default is US-ASCII. + + The server MUST set this meta-variable if an HTTP Content-Type field + is present in the client request header. If the server receives a + request with an attached entity but no Content-Type header field, it + MAY attempt to determine the correct content type, otherwise it + should omit this meta-variable. + +4.1.4. GATEWAY_INTERFACE + + The GATEWAY_INTERFACE variable MUST be set to the dialect of CGI + being used by the server to communicate with the script. Syntax: + + GATEWAY_INTERFACE = "CGI" "/" 1*digit "." 1*digit + + Note that the major and minor numbers are treated as separate + integers and hence each may be incremented higher than a single + digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in turn + is lower than CGI/12.3. Leading zeros MUST be ignored by the script + and MUST NOT be generated by the server. + + This document defines the 1.1 version of the CGI interface. + +4.1.5. PATH_INFO + + The PATH_INFO variable specifies a path to be interpreted by the CGI + script. It identifies the resource or sub-resource to be returned by + the CGI script, and is derived from the portion of the URI path + hierarchy following the part that identifies the script itself. + Unlike a URI path, the PATH_INFO is not URL-encoded, and cannot + contain path-segment parameters. A PATH_INFO of "/" represents a + single void path segment. + + PATH_INFO = "" | ( "/" path ) + path = lsegment *( "/" lsegment ) + lsegment = *lchar + lchar = + + + +Robinson & Coar Informational [Page 13] + +RFC 3875 CGI Version 1.1 October 2004 + + + The value is considered case-sensitive and the server MUST preserve + the case of the path as presented in the request URI. The server MAY + impose restrictions and limitations on what values it permits for + PATH_INFO, and MAY reject the request with an error if it encounters + any values considered objectionable. That MAY include any requests + that would result in an encoded "/" being decoded into PATH_INFO, as + this might represent a loss of information to the script. Similarly, + treatment of non US-ASCII characters in the path is system-defined. + + URL-encoded, the PATH_INFO string forms the extra-path component of + the Script-URI (see section 3.3) which follows the SCRIPT_NAME part + of that path. + +4.1.6. PATH_TRANSLATED + + The PATH_TRANSLATED variable is derived by taking the PATH_INFO + value, parsing it as a local URI in its own right, and performing any + virtual-to-physical translation appropriate to map it onto the + server's document repository structure. The set of characters + permitted in the result is system-defined. + + PATH_TRANSLATED = * + + This is the file location that would be accessed by a request for + + "://" ":" + + where is the scheme for the original client request and + is a URL-encoded version of PATH_INFO, with ";", "=" and + "?" reserved. For example, a request such as the following: + + http://somehost.com/cgi-bin/somescript/this%2eis%2epath%3binfo + + would result in a PATH_INFO value of + + /this.is.the.path;info + + An internal URI is constructed from the scheme, server location and + the URL-encoded PATH_INFO: + + http://somehost.com/this.is.the.path%3binfo + + This would then be translated to a location in the server's document + repository, perhaps a filesystem path something like this: + + /usr/local/www/htdocs/this.is.the.path;info + + The value of PATH_TRANSLATED is the result of the translation. + + + +Robinson & Coar Informational [Page 14] + +RFC 3875 CGI Version 1.1 October 2004 + + + The value is derived in this way irrespective of whether it maps to a + valid repository location. The server MUST preserve the case of the + extra-path segment unless the underlying repository supports case- + insensitive names. If the repository is only case-aware, case- + preserving, or case-blind with regard to document names, the server + is not required to preserve the case of the original segment through + the translation. + + The translation algorithm the server uses to derive PATH_TRANSLATED + is implementation-defined; CGI scripts which use this variable may + suffer limited portability. + + The server SHOULD set this meta-variable if the request URI includes + a path-info component. If PATH_INFO is NULL, then the + PATH_TRANSLATED variable MUST be set to NULL (or unset). + +4.1.7. QUERY_STRING + + The QUERY_STRING variable contains a URL-encoded search or parameter + string; it provides information to the CGI script to affect or refine + the document to be returned by the script. + + The URL syntax for a search string is described in section 3 of RFC + 2396 [2]. The QUERY_STRING value is case-sensitive. + + QUERY_STRING = query-string + query-string = *uric + uric = reserved | unreserved | escaped + + When parsing and decoding the query string, the details of the + parsing, reserved characters and support for non US-ASCII characters + depends on the context. For example, form submission from an HTML + document [18] uses application/x-www-form-urlencoded encoding, in + which the characters "+", "&" and "=" are reserved, and the ISO + 8859-1 encoding may be used for non US-ASCII characters. + + The QUERY_STRING value provides the query-string part of the + Script-URI. (See section 3.3). + + The server MUST set this variable; if the Script-URI does not include + a query component, the QUERY_STRING MUST be defined as an empty + string (""). + +4.1.8. REMOTE_ADDR + + The REMOTE_ADDR variable MUST be set to the network address of the + client sending the request to the server. + + + + +Robinson & Coar Informational [Page 15] + +RFC 3875 CGI Version 1.1 October 2004 + + + REMOTE_ADDR = hostnumber + hostnumber = ipv4-address | ipv6-address + ipv4-address = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit + ipv6-address = hexpart [ ":" ipv4-address ] + hexpart = hexseq | ( [ hexseq ] "::" [ hexseq ] ) + hexseq = 1*4hex *( ":" 1*4hex ) + + The format of an IPv6 address is described in RFC 3513 [15]. + +4.1.9. REMOTE_HOST + + The REMOTE_HOST variable contains the fully qualified domain name of + the client sending the request to the server, if available, otherwise + NULL. Fully qualified domain names take the form as described in + section 3.5 of RFC 1034 [17] and section 2.1 of RFC 1123 [12]. + Domain names are not case sensitive. + + REMOTE_HOST = "" | hostname | hostnumber + hostname = *( domainlabel "." ) toplabel [ "." ] + domainlabel = alphanum [ *alphahypdigit alphanum ] + toplabel = alpha [ *alphahypdigit alphanum ] + alphahypdigit = alphanum | "-" + + The server SHOULD set this variable. If the hostname is not + available for performance reasons or otherwise, the server MAY + substitute the REMOTE_ADDR value. + +4.1.10. REMOTE_IDENT + + The REMOTE_IDENT variable MAY be used to provide identity information + reported about the connection by an RFC 1413 [20] request to the + remote agent, if available. The server may choose not to support + this feature, or not to request the data for efficiency reasons, or + not to return available identity data. + + REMOTE_IDENT = *TEXT + + The data returned may be used for authentication purposes, but the + level of trust reposed in it should be minimal. + +4.1.11. REMOTE_USER + + The REMOTE_USER variable provides a user identification string + supplied by client as part of user authentication. + + REMOTE_USER = *TEXT + + + + + +Robinson & Coar Informational [Page 16] + +RFC 3875 CGI Version 1.1 October 2004 + + + If the client request required HTTP Authentication [5] (e.g., the + AUTH_TYPE meta-variable is set to "Basic" or "Digest"), then the + value of the REMOTE_USER meta-variable MUST be set to the user-ID + supplied. + +4.1.12. REQUEST_METHOD + + The REQUEST_METHOD meta-variable MUST be set to the method which + should be used by the script to process the request, as described in + section 4.3. + + REQUEST_METHOD = method + method = "GET" | "POST" | "HEAD" | extension-method + extension-method = "PUT" | "DELETE" | token + + The method is case sensitive. The HTTP methods are described in + section 5.1.1 of the HTTP/1.0 specification [1] and section 5.1.1 of + the HTTP/1.1 specification [4]. + +4.1.13. SCRIPT_NAME + + The SCRIPT_NAME variable MUST be set to a URI path (not URL-encoded) + which could identify the CGI script (rather than the script's + output). The syntax is the same as for PATH_INFO (section 4.1.5) + + SCRIPT_NAME = "" | ( "/" path ) + + The leading "/" is not part of the path. It is optional if the path + is NULL; however, the variable MUST still be set in that case. + + The SCRIPT_NAME string forms some leading part of the path component + of the Script-URI derived in some implementation-defined manner. No + PATH_INFO segment (see section 4.1.5) is included in the SCRIPT_NAME + value. + +4.1.14. SERVER_NAME + + The SERVER_NAME variable MUST be set to the name of the server host + to which the client request is directed. It is a case-insensitive + hostname or network address. It forms the host part of the + Script-URI. + + SERVER_NAME = server-name + server-name = hostname | ipv4-address | ( "[" ipv6-address "]" ) + + + + + + + +Robinson & Coar Informational [Page 17] + +RFC 3875 CGI Version 1.1 October 2004 + + + A deployed server can have more than one possible value for this + variable, where several HTTP virtual hosts share the same IP address. + In that case, the server would use the contents of the request's Host + header field to select the correct virtual host. + +4.1.15. SERVER_PORT + + The SERVER_PORT variable MUST be set to the TCP/IP port number on + which this request is received from the client. This value is used + in the port part of the Script-URI. + + SERVER_PORT = server-port + server-port = 1*digit + + Note that this variable MUST be set, even if the port is the default + port for the scheme and could otherwise be omitted from a URI. + +4.1.16. SERVER_PROTOCOL + + The SERVER_PROTOCOL variable MUST be set to the name and version of + the application protocol used for this CGI request. This MAY differ + from the protocol version used by the server in its communication + with the client. + + SERVER_PROTOCOL = HTTP-Version | "INCLUDED" | extension-version + HTTP-Version = "HTTP" "/" 1*digit "." 1*digit + extension-version = protocol [ "/" 1*digit "." 1*digit ] + protocol = token + + Here, 'protocol' defines the syntax of some of the information + passing between the server and the script (the 'protocol-specific' + features). It is not case sensitive and is usually presented in + upper case. The protocol is not the same as the scheme part of the + script URI, which defines the overall access mechanism used by the + client to communicate with the server. For example, a request that + reaches the script with a protocol of "HTTP" may have used an "https" + scheme. + + A well-known value for SERVER_PROTOCOL which the server MAY use is + "INCLUDED", which signals that the current document is being included + as part of a composite document, rather than being the direct target + of the client request. The script should treat this as an HTTP/1.0 + request. + + + + + + + + +Robinson & Coar Informational [Page 18] + +RFC 3875 CGI Version 1.1 October 2004 + + +4.1.17. SERVER_SOFTWARE + + The SERVER_SOFTWARE meta-variable MUST be set to the name and version + of the information server software making the CGI request (and + running the gateway). It SHOULD be the same as the server + description reported to the client, if any. + + SERVER_SOFTWARE = 1*( product | comment ) + product = token [ "/" product-version ] + product-version = token + comment = "(" *( ctext | comment ) ")" + ctext = + +4.1.18. Protocol-Specific Meta-Variables + + The server SHOULD set meta-variables specific to the protocol and + scheme for the request. Interpretation of protocol-specific + variables depends on the protocol version in SERVER_PROTOCOL. The + server MAY set a meta-variable with the name of the scheme to a + non-NULL value if the scheme is not the same as the protocol. The + presence of such a variable indicates to a script which scheme is + used by the request. + + Meta-variables with names beginning with "HTTP_" contain values read + from the client request header fields, if the protocol used is HTTP. + The HTTP header field name is converted to upper case, has all + occurrences of "-" replaced with "_" and has "HTTP_" prepended to + give the meta-variable name. The header data can be presented as + sent by the client, or can be rewritten in ways which do not change + its semantics. If multiple header fields with the same field-name + are received then the server MUST rewrite them as a single value + having the same semantics. Similarly, a header field that spans + multiple lines MUST be merged onto a single line. The server MUST, + if necessary, change the representation of the data (for example, the + character set) to be appropriate for a CGI meta-variable. + + The server is not required to create meta-variables for all the + header fields that it receives. In particular, it SHOULD remove any + header fields carrying authentication information, such as + 'Authorization'; or that are available to the script in other + variables, such as 'Content-Length' and 'Content-Type'. The server + MAY remove header fields that relate solely to client-side + communication issues, such as 'Connection'. + + + + + + + + +Robinson & Coar Informational [Page 19] + +RFC 3875 CGI Version 1.1 October 2004 + + +4.2. Request Message-Body + + Request data is accessed by the script in a system-defined method; + unless defined otherwise, this will be by reading the 'standard + input' file descriptor or file handle. + + Request-Data = [ request-body ] [ extension-data ] + request-body = OCTET + extension-data = *OCTET + + A request-body is supplied with the request if the CONTENT_LENGTH is + not NULL. The server MUST make at least that many bytes available + for the script to read. The server MAY signal an end-of-file + condition after CONTENT_LENGTH bytes have been read or it MAY supply + extension data. Therefore, the script MUST NOT attempt to read more + than CONTENT_LENGTH bytes, even if more data is available. However, + it is not obliged to read any of the data. + + For non-parsed header (NPH) scripts (section 5), the server SHOULD + attempt to ensure that the data supplied to the script is precisely + as supplied by the client and is unaltered by the server. + + As transfer-codings are not supported on the request-body, the server + MUST remove any such codings from the message-body, and recalculate + the CONTENT_LENGTH. If this is not possible (for example, because of + large buffering requirements), the server SHOULD reject the client + request. It MAY also remove content-codings from the message-body. + +4.3. Request Methods + + The Request Method, as supplied in the REQUEST_METHOD meta-variable, + identifies the processing method to be applied by the script in + producing a response. The script author can choose to implement the + methods most appropriate for the particular application. If the + script receives a request with a method it does not support it SHOULD + reject it with an error (see section 6.3.3). + +4.3.1. GET + + The GET method indicates that the script should produce a document + based on the meta-variable values. By convention, the GET method is + 'safe' and 'idempotent' and SHOULD NOT have the significance of + taking an action other than producing a document. + + The meaning of the GET method may be modified and refined by + protocol-specific meta-variables. + + + + + +Robinson & Coar Informational [Page 20] + +RFC 3875 CGI Version 1.1 October 2004 + + +4.3.2. POST + + The POST method is used to request the script perform processing and + produce a document based on the data in the request message-body, in + addition to meta-variable values. A common use is form submission in + HTML [18], intended to initiate processing by the script that has a + permanent affect, such a change in a database. + + The script MUST check the value of the CONTENT_LENGTH variable before + reading the attached message-body, and SHOULD check the CONTENT_TYPE + value before processing it. + +4.3.3. HEAD + + The HEAD method requests the script to do sufficient processing to + return the response header fields, without providing a response + message-body. The script MUST NOT provide a response message-body + for a HEAD request. If it does, then the server MUST discard the + message-body when reading the response from the script. + +4.3.4. Protocol-Specific Methods + + The script MAY implement any protocol-specific method, such as + HTTP/1.1 PUT and DELETE; it SHOULD check the value of SERVER_PROTOCOL + when doing so. + + The server MAY decide that some methods are not appropriate or + permitted for a script, and may handle the methods itself or return + an error to the client. + +4.4. The Script Command Line + + Some systems support a method for supplying an array of strings to + the CGI script. This is only used in the case of an 'indexed' HTTP + query, which is identified by a 'GET' or 'HEAD' request with a URI + query string that does not contain any unencoded "=" characters. For + such a request, the server SHOULD treat the query-string as a + search-string and parse it into words, using the rules + + search-string = search-word *( "+" search-word ) + search-word = 1*schar + schar = unreserved | escaped | xreserved + xreserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "," | + "$" + + After parsing, each search-word is URL-decoded, optionally encoded in + a system-defined manner and then added to the command line argument + list. + + + +Robinson & Coar Informational [Page 21] + +RFC 3875 CGI Version 1.1 October 2004 + + + If the server cannot create any part of the argument list, then the + server MUST NOT generate any command line information. For example, + the number of arguments may be greater than operating system or + server limits, or one of the words may not be representable as an + argument. + + The script SHOULD check to see if the QUERY_STRING value contains an + unencoded "=" character, and SHOULD NOT use the command line + arguments if it does. + +5. NPH Scripts + +5.1. Identification + + The server MAY support NPH (Non-Parsed Header) scripts; these are + scripts to which the server passes all responsibility for response + processing. + + This specification provides no mechanism for an NPH script to be + identified on the basis of its output data alone. By convention, + therefore, any particular script can only ever provide output of one + type (NPH or CGI) and hence the script itself is described as an 'NPH + script'. A server with NPH support MUST provide an implementation- + defined mechanism for identifying NPH scripts, perhaps based on the + name or location of the script. + +5.2. NPH Response + + There MUST be a system-defined method for the script to send data + back to the server or client; a script MUST always return some data. + Unless defined otherwise, this will be the same as for conventional + CGI scripts. + + Currently, NPH scripts are only defined for HTTP client requests. An + (HTTP) NPH script MUST return a complete HTTP response message, + currently described in section 6 of the HTTP specifications [1], [4]. + The script MUST use the SERVER_PROTOCOL variable to determine the + appropriate format for a response. It MUST also take account of any + generic or protocol-specific meta-variables in the request as might + be mandated by the particular protocol specification. + + The server MUST ensure that the script output is sent to the client + unmodified. Note that this requires the script to use the correct + character set (US-ASCII [9] and ISO 8859-1 [10] for HTTP) in the + header fields. The server SHOULD attempt to ensure that the script + output is sent directly to the client, with minimal internal and no + transport-visible buffering. + + + + +Robinson & Coar Informational [Page 22] + +RFC 3875 CGI Version 1.1 October 2004 + + + Unless the implementation defines otherwise, the script MUST NOT + indicate in its response that the client can send further requests + over the same connection. + +6. CGI Response + +6.1. Response Handling + + A script MUST always provide a non-empty response, and so there is a + system-defined method for it to send this data back to the server. + Unless defined otherwise, this will be via the 'standard output' file + descriptor. + + The script MUST check the REQUEST_METHOD variable when processing the + request and preparing its response. + + The server MAY implement a timeout period within which data must be + received from the script. If a server implementation defines such a + timeout and receives no data from a script within the timeout period, + the server MAY terminate the script process. + +6.2. Response Types + + The response comprises a message-header and a message-body, separated + by a blank line. The message-header contains one or more header + fields. The body may be NULL. + + generic-response = 1*header-field NL [ response-body ] + + The script MUST return one of either a document response, a local + redirect response or a client redirect (with optional document) + response. In the response definitions below, the order of header + fields in a response is not significant (despite appearing so in the + BNF). The header fields are defined in section 6.3. + + CGI-Response = document-response | local-redir-response | + client-redir-response | client-redirdoc-response + +6.2.1. Document Response + + The CGI script can return a document to the user in a document + response, with an optional error code indicating the success status + of the response. + + document-response = Content-Type [ Status ] *other-field NL + response-body + + + + + +Robinson & Coar Informational [Page 23] + +RFC 3875 CGI Version 1.1 October 2004 + + + The script MUST return a Content-Type header field. A Status header + field is optional, and status 200 'OK' is assumed if it is omitted. + The server MUST make any appropriate modifications to the script's + output to ensure that the response to the client complies with the + response protocol version. + +6.2.2. Local Redirect Response + + The CGI script can return a URI path and query-string + ('local-pathquery') for a local resource in a Location header field. + This indicates to the server that it should reprocess the request + using the path specified. + + local-redir-response = local-Location NL + + The script MUST NOT return any other header fields or a message-body, + and the server MUST generate the response that it would have produced + in response to a request containing the URL + + scheme "://" server-name ":" server-port local-pathquery + +6.2.3. Client Redirect Response + + The CGI script can return an absolute URI path in a Location header + field, to indicate to the client that it should reprocess the request + using the URI specified. + + client-redir-response = client-Location *extension-field NL + + The script MUST not provide any other header fields, except for + server-defined CGI extension fields. For an HTTP client request, the + server MUST generate a 302 'Found' HTTP response message. + +6.2.4. Client Redirect Response with Document + + The CGI script can return an absolute URI path in a Location header + field together with an attached document, to indicate to the client + that it should reprocess the request using the URI specified. + + client-redirdoc-response = client-Location Status Content-Type + *other-field NL response-body + + The Status header field MUST be supplied and MUST contain a status + value of 302 'Found', or it MAY contain an extension-code, that is, + another valid status code that means client redirection. The server + MUST make any appropriate modifications to the script's output to + ensure that the response to the client complies with the response + protocol version. + + + +Robinson & Coar Informational [Page 24] + +RFC 3875 CGI Version 1.1 October 2004 + + +6.3. Response Header Fields + + The response header fields are either CGI or extension header fields + to be interpreted by the server, or protocol-specific header fields + to be included in the response returned to the client. At least one + CGI field MUST be supplied; each CGI field MUST NOT appear more than + once in the response. The response header fields have the syntax: + + header-field = CGI-field | other-field + CGI-field = Content-Type | Location | Status + other-field = protocol-field | extension-field + protocol-field = generic-field + extension-field = generic-field + generic-field = field-name ":" [ field-value ] NL + field-name = token + field-value = *( field-content | LWSP ) + field-content = *( token | separator | quoted-string ) + + The field-name is not case sensitive. A NULL field value is + equivalent to a field not being sent. Note that each header field in + a CGI-Response MUST be specified on a single line; CGI/1.1 does not + support continuation lines. Whitespace is permitted between the ":" + and the field-value (but not between the field-name and the ":"), and + also between tokens in the field-value. + +6.3.1. Content-Type + + The Content-Type response field sets the Internet Media Type [6] of + the entity body. + + Content-Type = "Content-Type:" media-type NL + + If an entity body is returned, the script MUST supply a Content-Type + field in the response. If it fails to do so, the server SHOULD NOT + attempt to determine the correct content type. The value SHOULD be + sent unmodified to the client, except for any charset parameter + changes. + + Unless it is otherwise system-defined, the default charset assumed by + the client for text media-types is ISO-8859-1 if the protocol is HTTP + and US-ASCII otherwise. Hence the script SHOULD include a charset + parameter. See section 3.4.1 of the HTTP/1.1 specification [4] for a + discussion of this issue. + + + + + + + + +Robinson & Coar Informational [Page 25] + +RFC 3875 CGI Version 1.1 October 2004 + + +6.3.2. Location + + The Location header field is used to specify to the server that the + script is returning a reference to a document rather than an actual + document (see sections 6.2.3 and 6.2.4). It is either an absolute + URI (optionally with a fragment identifier), indicating that the + client is to fetch the referenced document, or a local URI path + (optionally with a query string), indicating that the server is to + fetch the referenced document and return it to the client as the + response. + + Location = local-Location | client-Location + client-Location = "Location:" fragment-URI NL + local-Location = "Location:" local-pathquery NL + fragment-URI = absoluteURI [ "#" fragment ] + fragment = *uric + local-pathquery = abs-path [ "?" query-string ] + abs-path = "/" path-segments + path-segments = segment *( "/" segment ) + segment = *pchar + pchar = unreserved | escaped | extra + extra = ":" | "@" | "&" | "=" | "+" | "$" | "," + + The syntax of an absoluteURI is incorporated into this document from + that specified in RFC 2396 [2] and RFC 2732 [7]. A valid absoluteURI + always starts with the name of scheme followed by ":"; scheme names + start with a letter and continue with alphanumerics, "+", "-" or ".". + The local URI path and query must be an absolute path, and not a + relative path or NULL, and hence must start with a "/". + + Note that any message-body attached to the request (such as for a + POST request) may not be available to the resource that is the target + of the redirect. + +6.3.3. Status + + The Status header field contains a 3-digit integer result code that + indicates the level of success of the script's attempt to handle the + request. + + Status = "Status:" status-code SP reason-phrase NL + status-code = "200" | "302" | "400" | "501" | extension-code + extension-code = 3digit + reason-phrase = *TEXT + + Status code 200 'OK' indicates success, and is the default value + assumed for a document response. Status code 302 'Found' is used + with a Location header field and response message-body. Status code + + + +Robinson & Coar Informational [Page 26] + +RFC 3875 CGI Version 1.1 October 2004 + + + 400 'Bad Request' may be used for an unknown request format, such as + a missing CONTENT_TYPE. Status code 501 'Not Implemented' may be + returned by a script if it receives an unsupported REQUEST_METHOD. + + Other valid status codes are listed in section 6.1.1 of the HTTP + specifications [1], [4], and also the IANA HTTP Status Code Registry + [8] and MAY be used in addition to or instead of the ones listed + above. The script SHOULD check the value of SERVER_PROTOCOL before + using HTTP/1.1 status codes. The script MAY reject with error 405 + 'Method Not Allowed' HTTP/1.1 requests made using a method it does + not support. + + Note that returning an error status code does not have to mean an + error condition with the script itself. For example, a script that + is invoked as an error handler by the server should return the code + appropriate to the server's error condition. + + The reason-phrase is a textual description of the error to be + returned to the client for human consumption. + +6.3.4. Protocol-Specific Header Fields + + The script MAY return any other header fields that relate to the + response message defined by the specification for the SERVER_PROTOCOL + (HTTP/1.0 [1] or HTTP/1.1 [4]). The server MUST translate the header + data from the CGI header syntax to the HTTP header syntax if these + differ. For example, the character sequence for newline (such as + UNIX's US-ASCII LF) used by CGI scripts may not be the same as that + used by HTTP (US-ASCII CR followed by LF). + + The script MUST NOT return any header fields that relate to + client-side communication issues and could affect the server's + ability to send the response to the client. The server MAY remove + any such header fields returned by the client. It SHOULD resolve any + conflicts between header fields returned by the script and header + fields that it would otherwise send itself. + +6.3.5. Extension Header Fields + + There may be additional implementation-defined CGI header fields, + whose field names SHOULD begin with "X-CGI-". The server MAY ignore + (and delete) any unrecognised header fields with names beginning "X- + CGI-" that are received from the script. + + + + + + + + +Robinson & Coar Informational [Page 27] + +RFC 3875 CGI Version 1.1 October 2004 + + +6.4. Response Message-Body + + The response message-body is an attached document to be returned to + the client by the server. The server MUST read all the data provided + by the script, until the script signals the end of the message-body + by way of an end-of-file condition. The message-body SHOULD be sent + unmodified to the client, except for HEAD requests or any required + transfer-codings, content-codings or charset conversions. + + response-body = *OCTET + +7. System Specifications + +7.1. AmigaDOS + + Meta-Variables + Meta-variables are passed to the script in identically named + environment variables. These are accessed by the DOS library + routine GetVar(). The flags argument SHOULD be 0. Case is + ignored, but upper case is recommended for compatibility with + case-sensitive systems. + + The current working directory + The current working directory for the script is set to the + directory containing the script. + + Character set + The US-ASCII character set [9] is used for the definition of + meta-variables, header fields and values; the newline (NL) + sequence is LF; servers SHOULD also accept CR LF as a newline. + +7.2. UNIX + + For UNIX compatible operating systems, the following are defined: + + Meta-Variables + Meta-variables are passed to the script in identically named + environment variables. These are accessed by the C library + routine getenv() or variable environ. + + The command line + This is accessed using the argc and argv arguments to main(). The + words have any characters which are 'active' in the Bourne shell + escaped with a backslash. + + The current working directory + The current working directory for the script SHOULD be set to the + directory containing the script. + + + +Robinson & Coar Informational [Page 28] + +RFC 3875 CGI Version 1.1 October 2004 + + + Character set + The US-ASCII character set [9], excluding NUL, is used for the + definition of meta-variables, header fields and CHAR values; TEXT + values use ISO-8859-1. The PATH_TRANSLATED value can contain any + 8-bit byte except NUL. The newline (NL) sequence is LF; servers + should also accept CR LF as a newline. + +7.3. EBCDIC/POSIX + + For POSIX compatible operating systems using the EBCDIC character + set, the following are defined: + + Meta-Variables + Meta-variables are passed to the script in identically named + environment variables. These are accessed by the C library + routine getenv(). + + The command line + This is accessed using the argc and argv arguments to main(). The + words have any characters which are 'active' in the Bourne shell + escaped with a backslash. + + The current working directory + The current working directory for the script SHOULD be set to the + directory containing the script. + + Character set + The IBM1047 character set [21], excluding NUL, is used for the + definition of meta-variables, header fields, values, TEXT strings + and the PATH_TRANSLATED value. The newline (NL) sequence is LF; + servers should also accept CR LF as a newline. + + media-type charset default + The default charset value for text (and other implementation- + defined) media types is IBM1047. + +8. Implementation + +8.1. Recommendations for Servers + + Although the server and the CGI script need not be consistent in + their handling of URL paths (client URLs and the PATH_INFO data, + respectively), server authors may wish to impose consistency. So the + server implementation should specify its behaviour for the following + cases: + + 1. define any restrictions on allowed path segments, in particular + whether non-terminal NULL segments are permitted; + + + +Robinson & Coar Informational [Page 29] + +RFC 3875 CGI Version 1.1 October 2004 + + + 2. define the behaviour for "." or ".." path segments; i.e., + whether they are prohibited, treated as ordinary path segments + or interpreted in accordance with the relative URL + specification [2]; + + 3. define any limits of the implementation, including limits on + path or search string lengths, and limits on the volume of + header fields the server will parse. + +8.2. Recommendations for Scripts + + If the script does not intend processing the PATH_INFO data, then it + should reject the request with 404 Not Found if PATH_INFO is not + NULL. + + If the output of a form is being processed, check that CONTENT_TYPE + is "application/x-www-form-urlencoded" [18] or "multipart/form-data" + [16]. If CONTENT_TYPE is blank, the script can reject the request + with a 415 'Unsupported Media Type' error, where supported by the + protocol. + + When parsing PATH_INFO, PATH_TRANSLATED or SCRIPT_NAME the script + should be careful of void path segments ("//") and special path + segments ("." and ".."). They should either be removed from the path + before use in OS system calls, or the request should be rejected with + 404 'Not Found'. + + When returning header fields, the script should try to send the CGI + header fields as soon as possible, and should send them before any + HTTP header fields. This may help reduce the server's memory + requirements. + + Script authors should be aware that the REMOTE_ADDR and REMOTE_HOST + meta-variables (see sections 4.1.8 and 4.1.9) may not identify the + ultimate source of the request. They identify the client for the + immediate request to the server; that client may be a proxy, gateway, + or other intermediary acting on behalf of the actual source client. + +9. Security Considerations + +9.1. Safe Methods + + As discussed in the security considerations of the HTTP + specifications [1], [4], the convention has been established that the + GET and HEAD methods should be 'safe' and 'idempotent' (repeated + requests have the same effect as a single request). See section 9.1 + of RFC 2616 [4] for a full discussion. + + + + +Robinson & Coar Informational [Page 30] + +RFC 3875 CGI Version 1.1 October 2004 + + +9.2. Header Fields Containing Sensitive Information + + Some HTTP header fields may carry sensitive information which the + server should not pass on to the script unless explicitly configured + to do so. For example, if the server protects the script by using + the Basic authentication scheme, then the client will send an + Authorization header field containing a username and password. The + server validates this information and so it should not pass on the + password via the HTTP_AUTHORIZATION meta-variable without careful + consideration. This also applies to the Proxy-Authorization header + field and the corresponding HTTP_PROXY_AUTHORIZATION meta-variable. + +9.3. Data Privacy + + Confidential data in a request should be placed in a message-body as + part of a POST request, and not placed in the URI or message headers. + On some systems, the environment used to pass meta-variables to a + script may be visible to other scripts or users. In addition, many + existing servers, proxies and clients will permanently record the URI + where it might be visible to third parties. + +9.4. Information Security Model + + For a client connection using TLS, the security model applies between + the client and the server, and not between the client and the script. + It is the server's responsibility to handle the TLS session, and thus + it is the server which is authenticated to the client, not the CGI + script. + + This specification provides no mechanism for the script to + authenticate the server which invoked it. There is no enforced + integrity on the CGI request and response messages. + +9.5. Script Interference with the Server + + The most common implementation of CGI invokes the script as a child + process using the same user and group as the server process. It + should therefore be ensured that the script cannot interfere with the + server process, its configuration, documents or log files. + + If the script is executed by calling a function linked in to the + server software (either at compile-time or run-time) then precautions + should be taken to protect the core memory of the server, or to + ensure that untrusted code cannot be executed. + + + + + + + +Robinson & Coar Informational [Page 31] + +RFC 3875 CGI Version 1.1 October 2004 + + +9.6. Data Length and Buffering Considerations + + This specification places no limits on the length of the message-body + presented to the script. The script should not assume that + statically allocated buffers of any size are sufficient to contain + the entire submission at one time. Use of a fixed length buffer + without careful overflow checking may result in an attacker + exploiting 'stack-smashing' or 'stack-overflow' vulnerabilities of + the operating system. The script may spool large submissions to disk + or other buffering media, but a rapid succession of large submissions + may result in denial of service conditions. If the CONTENT_LENGTH of + a message-body is larger than resource considerations allow, scripts + should respond with an error status appropriate for the protocol + version; potentially applicable status codes include 503 'Service + Unavailable' (HTTP/1.0 and HTTP/1.1), 413 'Request Entity Too Large' + (HTTP/1.1), and 414 'Request-URI Too Large' (HTTP/1.1). + + Similar considerations apply to the server's handling of the CGI + response from the script. There is no limit on the length of the + header or message-body returned by the script; the server should not + assume that statically allocated buffers of any size are sufficient + to contain the entire response. + +9.7. Stateless Processing + + The stateless nature of the Web makes each script execution and + resource retrieval independent of all others even when multiple + requests constitute a single conceptual Web transaction. Because of + this, a script should not make any assumptions about the context of + the user-agent submitting a request. In particular, scripts should + examine data obtained from the client and verify that they are valid, + both in form and content, before allowing them to be used for + sensitive purposes such as input to other applications, commands, or + operating system services. These uses include (but are not limited + to) system call arguments, database writes, dynamically evaluated + source code, and input to billing or other secure processes. It is + important that applications be protected from invalid input + regardless of whether the invalidity is the result of user error, + logic error, or malicious action. + + Authors of scripts involved in multi-request transactions should be + particularly cautious about validating the state information; + undesirable effects may result from the substitution of dangerous + values for portions of the submission which might otherwise be + presumed safe. Subversion of this type occurs when alterations are + made to data from a prior stage of the transaction that were not + meant to be controlled by the client (e.g., hidden HTML form + elements, cookies, embedded URLs, etc.). + + + +Robinson & Coar Informational [Page 32] + +RFC 3875 CGI Version 1.1 October 2004 + + +9.8. Relative Paths + + The server should be careful of ".." path segments in the request + URI. These should be removed or resolved in the request URI before + it is split into the script-path and extra-path. Alternatively, when + the extra-path is used to find the PATH_TRANSLATED, care should be + taken to avoid the path resolution from providing translated paths + outside an expected path hierarchy. + +9.9. Non-parsed Header Output + + If a script returns a non-parsed header output, to be interpreted by + the client in its native protocol, then the script must address all + security considerations relating to that protocol. + +10. Acknowledgements + + This work is based on the original CGI interface that arose out of + discussions on the 'www-talk' mailing list. In particular, Rob + McCool, John Franks, Ari Luotonen, George Phillips and Tony Sanders + deserve special recognition for their efforts in defining and + implementing the early versions of this interface. + + This document has also greatly benefited from the comments and + suggestions made Chris Adie, Dave Kristol and Mike Meyer; also David + Morris, Jeremy Madea, Patrick McManus, Adam Donahue, Ross Patterson + and Harald Alvestrand. + +11. References + +11.1 Normative References + + [1] Berners-Lee, T., Fielding, R. and H. Frystyk, "Hypertext + Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996. + + [2] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource + Identifiers (URI) : Generic Syntax", RFC 2396, August 1998. + + [3] Bradner, S., "Key words for use in RFCs to Indicate Requirements + Levels", BCP 14, RFC 2119, March 1997. + + [4] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., + Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- + HTTP/1.1", RFC 2616, June 1999. + + [5] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., + Leach, P., Luotonen, A., and L. Stewart, "HTTP Authentication: + Basic and Digest Access Authentication", RFC 2617, June 1999. + + + +Robinson & Coar Informational [Page 33] + +RFC 3875 CGI Version 1.1 October 2004 + + + [6] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types", RFC 2046, November + 1996. + + [7] Hinden, R., Carpenter, B., and L. Masinter, "Format for Literal + IPv6 Addresses in URL's", RFC 2732, December 1999. + + [8] "HTTP Status Code Registry", + http://www.iana.org/assignments/http-status-codes, IANA. + + [9] "Information Systems -- Coded Character Sets -- 7-bit American + Standard Code for Information Interchange (7-Bit ASCII)", ANSI + INCITS.4-1986 (R2002). + + [10] "Information technology -- 8-bit single-byte coded graphic + character sets -- Part 1: Latin alphabet No. 1", ISO/IEC + 8859-1:1998. + +11.2. Informative References + + [11] Berners-Lee, T., "Universal Resource Identifiers in WWW: A + Unifying Syntax for the Expression of Names and Addresses of + Objects on the Network as used in the World-Wide Web", RFC 1630, + June 1994. + + [12] Braden, R., Ed., "Requirements for Internet Hosts -- Application + and Support", STD 3, RFC 1123, October 1989. + + [13] Crocker, D., "Standard for the Format of ARPA Internet Text + Messages", STD 11, RFC 822, August 1982. + + [14] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC + 2246, January 1999. + + [15] Hinden R. and S. Deering, "Internet Protocol Version 6 (IPv6) + Addressing Architecture", RFC 3513, April 2003. + + [16] Masinter, L., "Returning Values from Forms: + multipart/form-data", RFC 2388, August 1998. + + [17] Mockapetris, P., "Domain Names - Concepts and Facilities", STD + 13, RFC 1034, November 1987. + + [18] Raggett, D., Le Hors, A., and I. Jacobs, Eds., "HTML 4.01 + Specification", W3C Recommendation December 1999, + http://www.w3.org/TR/html401/. + + [19] Rescola, E. "HTTP Over TLS", RFC 2818, May 2000. + + + +Robinson & Coar Informational [Page 34] + +RFC 3875 CGI Version 1.1 October 2004 + + + [20] St. Johns, M., "Identification Protocol", RFC 1413, February + 1993. + + [21] IBM National Language Support Reference Manual Volume 2, + SE09-8002-01, March 1990. + + [22] "The Common Gateway Interface", + http://hoohoo.ncsa.uiuc.edu/cgi/, NCSA, University of Illinois. + +12. Authors' Addresses + + David Robinson + The Apache Software Foundation + + EMail: drtr@apache.org + + + Ken A. L. Coar + The Apache Software Foundation + + EMail: coar@apache.org + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Robinson & Coar Informational [Page 35] + +RFC 3875 CGI Version 1.1 October 2004 + + +13. Full Copyright Statement + + Copyright (C) The Internet Society (2004). This document is subject + to the rights, licenses and restrictions contained in BCP 78 and at + www.rfc-editor.org, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + + Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the ISOC's procedures with respect to rights in ISOC Documents can + be found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + +Robinson & Coar Informational [Page 36] + diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl index 76ca4924f..948cd213b 100644 --- a/templates/jobs.tmpl +++ b/templates/jobs.tmpl @@ -19,7 +19,8 @@ {job_media_sheets_completed=0?Unknown:{?job_media_sheets_completed}}  {job_state=3?pending since
{time_at_creation}:{job_state=4?held since
{time_at_creation}: {job_state=5?processing since
{time_at_processing}:{job_state=6?stopped: -{job_state=7?canceled at
{time_at_completed}:{job_state=8?aborted:completed at
{time_at_completed}}}}}}}  +{job_state=7?canceled at
{time_at_completed}:{job_state=8?aborted:completed at
{time_at_completed}}}}}}} {job_printer_state_message?
+"{job_printer_state_message}":} {job_preserved>0?
diff --git a/test/4.3-job-ops.test b/test/4.3-job-ops.test index 0d3a42cf8..44a275fb0 100644 --- a/test/4.3-job-ops.test +++ b/test/4.3-job-ops.test @@ -3,6 +3,27 @@ # # Verify that the IPP job operations work. # +{ + # The name of the test... + NAME "Print PostScript Job with bad job-sheets value to Test1" + + # The operation to use + OPERATION print-job + RESOURCE /printers/Test1 + + # The attributes to send + GROUP operation + ATTR charset attributes-charset utf-8 + ATTR language attributes-natural-language en + ATTR uri printer-uri $method://$hostname:$port/printers/Test1 + ATTR name requesting-user-name $user + ATTR name job-sheets "none\,none" + + FILE testfile.ps + + # What statuses are OK? + STATUS client-error-bad-request +} { # The name of the test... NAME "Print PostScript Job to Test1" @@ -69,7 +90,7 @@ ATTR name requesting-user-name $user GROUP subscription - ATTR uri notify-recipient-uri testnotify + ATTR uri notify-recipient-uri testnotify:/// FILE testfile.jpg -- 2.39.2