]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/client.c
Update svn:keyword properties.
[thirdparty/cups.git] / scheduler / client.c
index 18d45ade9eba614ec17d0c1d324cd7233444d7e8..b5cf43319d6fac644f7db238e8de5d6edaed3c75 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: client.c 7950 2008-09-17 00:21:59Z mike $"
+ * "$Id$"
  *
  *   Client routines for the CUPS scheduler.
  *
- *   Copyright 2007-2012 by Apple Inc.
+ *   Copyright 2007-2013 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   This file contains Kerberos support code, copyright 2006 by
@@ -32,7 +32,7 @@
  *   compare_clients()     - Compare two client connections.
  *   data_ready()          - Check whether data is available from a client.
  *   get_file()            - Get a filename and state info.
- *   install_conf_file()    - Install a configuration file.
+ *   install_cupsd_conf()    - Install a configuration file.
  *   is_cgi()              - Is the resource a CGI script/program?
  *   is_path_absolute()     - Is a path absolute and free of relative elements
  *                           (i.e. "..").
@@ -49,6 +49,9 @@
 
 #include "cupsd.h"
 
+#ifdef __APPLE__
+#  include <libproc.h>
+#endif /* __APPLE__ */
 #ifdef HAVE_TCPD_H
 #  include <tcpd.h>
 #endif /* HAVE_TCPD_H */
 
 static const char      * const http_states[] =
                        {               /* HTTP state strings */
-                         "HTTP_WAITING",
-                         "HTTP_OPTIONS",
-                         "HTTP_GET",
-                         "HTTP_GET_SEND",
-                         "HTTP_HEAD",
-                         "HTTP_POST",
-                         "HTTP_POST_RECV",
-                         "HTTP_POST_SEND",
-                         "HTTP_PUT",
-                         "HTTP_PUT_RECV",
-                         "HTTP_DELETE",
-                         "HTTP_TRACE",
-                         "HTTP_CLOSE",
-                         "HTTP_STATUS"
+                         "HTTP_STATE_ERROR",
+                         "HTTP_STATE_WAITING",
+                         "HTTP_STATE_OPTIONS",
+                         "HTTP_STATE_GET",
+                         "HTTP_STATE_GET_SEND",
+                         "HTTP_STATE_HEAD",
+                         "HTTP_STATE_POST",
+                         "HTTP_STATE_POST_RECV",
+                         "HTTP_STATE_POST_SEND",
+                         "HTTP_STATE_PUT",
+                         "HTTP_STATE_PUT_RECV",
+                         "HTTP_STATE_DELETE",
+                         "HTTP_STATE_TRACE",
+                         "HTTP_STATE_CONNECT",
+                         "HTTP_STATE_STATUS",
+                         "HTTP_STATE_UNKNOWN_METHOD",
+                         "HTTP_STATE_UNKNOWN_VERSION"
                        };
 static const char      * const ipp_states[] =
                        {               /* IPP state strings */
@@ -95,7 +101,7 @@ static int           compare_clients(cupsd_client_t *a, cupsd_client_t *b,
 static int             data_ready(cupsd_client_t *con);
 static char            *get_file(cupsd_client_t *con, struct stat *filestats,
                                  char *filename, int len);
-static http_status_t   install_conf_file(cupsd_client_t *con);
+static http_status_t   install_cupsd_conf(cupsd_client_t *con);
 static int             is_cgi(cupsd_client_t *con, const char *filename,
                               struct stat *filestats, mime_type_t *type);
 static int             is_path_absolute(const char *path);
@@ -178,6 +184,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   con->http.activity   = time(NULL);
   con->http.hostaddr   = &(con->clientaddr);
   con->http.wait_value = 10000;
+  con->http.mode       = _HTTP_MODE_SERVER;
 
  /*
   * Accept the client and get the remote address...
@@ -202,7 +209,7 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   * Save the connected port number...
   */
 
-  _httpAddrSetPort(con->http.hostaddr, _httpAddrPort(&(lis->address)));
+  _httpAddrSetPort(con->http.hostaddr, httpAddrPort(&(lis->address)));
 
 #ifdef AF_INET6
  /*
@@ -373,13 +380,36 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
 
 #ifdef AF_LOCAL
   if (con->http.hostaddr->addr.sa_family == AF_LOCAL)
+  {
+#  ifdef __APPLE__
+    socklen_t  peersize;               /* Size of peer credentials */
+    pid_t      peerpid;                /* Peer process ID */
+    char       name[256];              /* Name of process */
+
+    peersize = sizeof(peerpid);
+    if (!getsockopt(con->http.fd, SOL_LOCAL, LOCAL_PEERPID, &peerpid,
+        &peersize))
+    {
+      if (!proc_name(peerpid, name, sizeof(name)))
+       cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "[Client %d] Accepted from %s (Domain ???[%d])",
+                       con->http.fd, con->http.hostname, (int)peerpid);
+      else
+       cupsdLogMessage(CUPSD_LOG_DEBUG,
+                       "[Client %d] Accepted from %s (Domain %s[%d])",
+                       con->http.fd, con->http.hostname, name, (int)peerpid);
+    }
+    else
+#  endif /* __APPLE__ */
+
     cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s (Domain)",
                     con->http.fd, con->http.hostname);
+  }
   else
 #endif /* AF_LOCAL */
   cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Accepted from %s:%d (IPv%d)",
                   con->http.fd, con->http.hostname,
-                 _httpAddrPort(con->http.hostaddr),
+                 httpAddrPort(con->http.hostaddr),
                  _httpAddrFamily(con->http.hostaddr) == AF_INET ? 4 : 6);
 
  /*
@@ -392,13 +422,13 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get local address - %s",
                     strerror(errno));
 
-    strcpy(con->servername, "localhost");
+    strlcpy(con->servername, "localhost", sizeof(con->servername));
     con->serverport = LocalPort;
   }
 #ifdef AF_LOCAL
   else if (_httpAddrFamily(&temp) == AF_LOCAL)
   {
-    strcpy(con->servername, "localhost");
+    strlcpy(con->servername, "localhost", sizeof(con->servername));
     con->serverport = LocalPort;
   }
 #endif /* AF_LOCAL */
@@ -406,12 +436,12 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   {
     if (httpAddrLocalhost(&temp))
       strlcpy(con->servername, "localhost", sizeof(con->servername));
-    else if (HostNameLookups || RemotePort)
+    else if (HostNameLookups)
       httpAddrLookup(&temp, con->servername, sizeof(con->servername));
     else
       httpAddrString(&temp, con->servername, sizeof(con->servername));
 
-    con->serverport = _httpAddrPort(&(lis->address));
+    con->serverport = httpAddrPort(&(lis->address));
   }
 
  /*
@@ -650,7 +680,7 @@ cupsdFlushHeader(cupsd_client_t *con)       /* I - Client to flush to */
 {
   int bytes = httpFlushWrite(HTTP(con));
 
-  con->http.data_encoding = HTTP_ENCODE_LENGTH;
+  con->http.data_encoding = HTTP_ENCODING_LENGTH;
 
   return (bytes);
 }
@@ -687,13 +717,13 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                  "error=%d, "
                  "used=%d, "
                  "state=%s, "
-                 "data_encoding=HTTP_ENCODE_%s, "
+                 "data_encoding=HTTP_ENCODING_%s, "
                  "data_remaining=" CUPS_LLFMT ", "
                  "request=%p(%s), "
                  "file=%d",
                  con->http.fd, con->http.error, con->http.used,
-                 http_states[con->http.state],
-                 con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
+                 http_states[con->http.state + 1],
+                 con->http.data_encoding == HTTP_ENCODING_CHUNKED ?
                      "CHUNKED" : "LENGTH",
                  CUPS_LLCAST con->http.data_remaining,
                  con->request,
@@ -730,7 +760,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
 
   switch (con->http.state)
   {
-    case HTTP_WAITING :
+    case HTTP_STATE_WAITING :
        /*
         * See if we've received a request line...
        */
@@ -739,12 +769,12 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        {
          if (con->http.error && con->http.error != EPIPE)
            cupsdLogMessage(CUPSD_LOG_DEBUG,
-                           "[Client %d] HTTP_WAITING Closing for error %d "
+                           "[Client %d] HTTP_STATE_WAITING Closing for error %d "
                            "(%s)", con->http.fd, con->http.error,
                            strerror(con->http.error));
          else
            cupsdLogMessage(CUPSD_LOG_DEBUG,
-                           "[Client %d] HTTP_WAITING Closing on EOF",
+                           "[Client %d] HTTP_STATE_WAITING Closing on EOF",
                            con->http.fd);
 
          cupsdCloseClient(con);
@@ -767,10 +797,10 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         con->http.activity        = time(NULL);
         con->http.version         = HTTP_1_0;
        con->http.keep_alive      = HTTP_KEEPALIVE_OFF;
-       con->http.data_encoding   = HTTP_ENCODE_LENGTH;
+       con->http.data_encoding   = HTTP_ENCODING_LENGTH;
        con->http.data_remaining  = 0;
        con->http._data_remaining = 0;
-       con->operation            = HTTP_WAITING;
+       con->operation            = HTTP_STATE_WAITING;
        con->bytes                = 0;
        con->file                 = -1;
        con->file_ready           = 0;
@@ -912,7 +942,7 @@ cupsdReadClient(cupsd_client_t *con)        /* I - Client to read from */
          * con->uri are HTTP_MAX_URI bytes in size...
          */
 
-          strcpy(con->uri, resource);
+          strlcpy(con->uri, resource, sizeof(con->uri));
        }
 
        /*
@@ -920,19 +950,19 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        */
 
         if (!strcmp(operation, "GET"))
-         con->http.state = HTTP_GET;
+         con->http.state = HTTP_STATE_GET;
         else if (!strcmp(operation, "PUT"))
-         con->http.state = HTTP_PUT;
+         con->http.state = HTTP_STATE_PUT;
         else if (!strcmp(operation, "POST"))
-         con->http.state = HTTP_POST;
+         con->http.state = HTTP_STATE_POST;
         else if (!strcmp(operation, "DELETE"))
-         con->http.state = HTTP_DELETE;
+         con->http.state = HTTP_STATE_DELETE;
         else if (!strcmp(operation, "TRACE"))
-         con->http.state = HTTP_TRACE;
+         con->http.state = HTTP_STATE_TRACE;
         else if (!strcmp(operation, "OPTIONS"))
-         con->http.state = HTTP_OPTIONS;
+         con->http.state = HTTP_STATE_OPTIONS;
         else if (!strcmp(operation, "HEAD"))
-         con->http.state = HTTP_HEAD;
+         con->http.state = HTTP_STATE_HEAD;
        else
        {
          cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -958,13 +988,13 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
           cupsdSetBusyState();
         }
 
-    case HTTP_OPTIONS :
-    case HTTP_DELETE :
-    case HTTP_GET :
-    case HTTP_HEAD :
-    case HTTP_POST :
-    case HTTP_PUT :
-    case HTTP_TRACE :
+    case HTTP_STATE_OPTIONS :
+    case HTTP_STATE_DELETE :
+    case HTTP_STATE_GET :
+    case HTTP_STATE_HEAD :
+    case HTTP_STATE_POST :
+    case HTTP_STATE_PUT :
+    case HTTP_STATE_TRACE :
        /*
         * Parse incoming parameters until the status changes...
        */
@@ -1094,7 +1124,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        return;
       }
     }
-    else if (con->operation == HTTP_OPTIONS)
+    else if (con->operation == HTTP_STATE_OPTIONS)
     {
      /*
       * Do OPTIONS command...
@@ -1124,7 +1154,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
-       httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+       httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n");
        httpPrintf(HTTP(con), "Content-Length: 0\r\n");
        httpPrintf(HTTP(con), "\r\n");
 
@@ -1198,7 +1228,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        }
 
        httpPrintf(HTTP(con), "Connection: Upgrade\r\n");
-       httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n");
+       httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n");
        httpPrintf(HTTP(con), "Content-Length: 0\r\n");
        httpPrintf(HTTP(con), "\r\n");
 
@@ -1230,7 +1260,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
       }
 
       if (con->http.expect &&
-          (con->operation == HTTP_POST || con->operation == HTTP_PUT))
+          (con->operation == HTTP_STATE_POST || con->operation == HTTP_STATE_PUT))
       {
         if (con->http.expect == HTTP_CONTINUE)
        {
@@ -1270,8 +1300,10 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
 
       switch (con->http.state)
       {
-       case HTTP_GET_SEND :
-            if (!strncmp(con->uri, "/printers/", 10) &&
+       case HTTP_STATE_GET_SEND :
+            if ((!strncmp(con->uri, "/ppd/", 5) ||
+                !strncmp(con->uri, "/printers/", 10) ||
+                !strncmp(con->uri, "/classes/", 9)) &&
                !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
            {
             /*
@@ -1281,8 +1313,43 @@ cupsdReadClient(cupsd_client_t *con)     /* I - Client to read from */
 
               con->uri[strlen(con->uri) - 4] = '\0';   /* Drop ".ppd" */
 
-              if ((p = cupsdFindPrinter(con->uri + 10)) != NULL)
+             if (!strncmp(con->uri, "/ppd/", 5))
+               p = cupsdFindPrinter(con->uri + 5);
+             else if (!strncmp(con->uri, "/printers/", 10))
+               p = cupsdFindPrinter(con->uri + 10);
+             else
+             {
+               p = cupsdFindClass(con->uri + 9);
+
+               if (p)
+               {
+                 int i;                /* Looping var */
+
+                 for (i = 0; i < p->num_printers; i ++)
+                 {
+                   if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
+                   {
+                     char ppdname[1024];/* PPD filename */
+
+                     snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd",
+                              ServerRoot, p->printers[i]->name);
+                     if (!access(ppdname, 0))
+                     {
+                       p = p->printers[i];
+                       break;
+                     }
+                   }
+                 }
+
+                  if (i >= p->num_printers)
+                    p = NULL;
+               }
+             }
+
+             if (p)
+             {
                snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name);
+             }
              else
              {
                if (!cupsdSendError(con, HTTP_NOT_FOUND, CUPSD_AUTH_NONE))
@@ -1294,7 +1361,8 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                break;
              }
            }
-            else if ((!strncmp(con->uri, "/printers/", 10) ||
+            else if ((!strncmp(con->uri, "/icons/", 7) ||
+                     !strncmp(con->uri, "/printers/", 10) ||
                      !strncmp(con->uri, "/classes/", 9)) &&
                     !strcmp(con->uri + strlen(con->uri) - 4, ".png"))
            {
@@ -1305,10 +1373,38 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
 
              con->uri[strlen(con->uri) - 4] = '\0';    /* Drop ".png" */
 
-              if (!strncmp(con->uri, "/printers/", 10))
+              if (!strncmp(con->uri, "/icons/", 7))
+                p = cupsdFindPrinter(con->uri + 7);
+              else if (!strncmp(con->uri, "/printers/", 10))
                 p = cupsdFindPrinter(con->uri + 10);
               else
-                p = cupsdFindClass(con->uri + 9);
+              {
+               p = cupsdFindClass(con->uri + 9);
+
+               if (p)
+               {
+                 int i;                /* Looping var */
+
+                 for (i = 0; i < p->num_printers; i ++)
+                 {
+                   if (!(p->printers[i]->type & CUPS_PRINTER_CLASS))
+                   {
+                     char ppdname[1024];/* PPD filename */
+
+                     snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd",
+                              ServerRoot, p->printers[i]->name);
+                     if (!access(ppdname, 0))
+                     {
+                       p = p->printers[i];
+                       break;
+                     }
+                   }
+                 }
+
+                  if (i >= p->num_printers)
+                    p = NULL;
+               }
+             }
 
               if (p)
                snprintf(con->uri, sizeof(con->uri), "/icons/%s.png", p->name);
@@ -1489,7 +1585,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              else
               {
                if (type == NULL)
-                 strcpy(line, "text/plain");
+                 strlcpy(line, "text/plain", sizeof(line));
                else
                  snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
@@ -1502,7 +1598,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
             break;
 
-       case HTTP_POST_RECV :
+       case HTTP_STATE_POST_RECV :
            /*
            * See if the POST request includes a Content-Length field, and if
            * so check the length against any limits that are set...
@@ -1526,7 +1622,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
             }
            else if (con->http.data_remaining < 0 ||
                     (!con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
-                     con->http.data_encoding == HTTP_ENCODE_LENGTH))
+                     con->http.data_encoding == HTTP_ENCODING_LENGTH))
            {
             /*
              * Negative content lengths are invalid!
@@ -1661,22 +1757,19 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
            }
            break;
 
-       case HTTP_PUT_RECV :
+       case HTTP_STATE_PUT_RECV :
           /*
            * Validate the resource name...
            */
 
-            if (strncmp(con->uri, "/admin/conf/", 12) ||
-               strchr(con->uri + 12, '/') ||
-               strlen(con->uri) == 12)
+            if (strcmp(con->uri, "/admin/conf/cupsd.conf"))
            {
             /*
-             * PUT can only be done to configuration files under
-             * /admin/conf...
+             * PUT can only be done to the cupsd.conf file...
              */
 
              cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "[Client %d] Request for subdirectory \"%s\".",
+                             "[Client %d] Disallowed PUT request for \"%s\".",
                              con->http.fd, con->uri);
 
              if (!cupsdSendError(con, HTTP_FORBIDDEN, CUPSD_AUTH_NONE))
@@ -1751,13 +1844,13 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
            fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
            break;
 
-       case HTTP_DELETE :
-       case HTTP_TRACE :
+       case HTTP_STATE_DELETE :
+       case HTTP_STATE_TRACE :
             cupsdSendError(con, HTTP_NOT_IMPLEMENTED, CUPSD_AUTH_NONE);
            cupsdCloseClient(con);
            return;
 
-       case HTTP_HEAD :
+       case HTTP_STATE_HEAD :
             if (!strncmp(con->uri, "/printers/", 10) &&
                !strcmp(con->uri + strlen(con->uri) - 4, ".ppd"))
            {
@@ -1824,7 +1917,9 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
                return;
              }
 
-             con->http.state = HTTP_WAITING;
+             con->http.state = HTTP_STATE_WAITING;
+             DEBUG_puts("cupsdReadClient: Set state to HTTP_STATE_WAITING "
+                        "after HEAD.");
              break;
            }
 
@@ -1914,7 +2009,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
 
              type = mimeFileType(MimeDatabase, filename, NULL, NULL);
              if (type == NULL)
-               strcpy(line, "text/plain");
+               strlcpy(line, "text/plain", sizeof(line));
              else
                snprintf(line, sizeof(line), "%s/%s", type->super, type->type);
 
@@ -1953,7 +2048,9 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
              return;
            }
 
-            con->http.state = HTTP_WAITING;
+            con->http.state = HTTP_STATE_WAITING;
+           DEBUG_puts("cupsdReadClient: Set state to HTTP_STATE_WAITING "
+                      "after HEAD.");
             break;
 
        default :
@@ -1968,19 +2065,19 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
 
   switch (con->http.state)
   {
-    case HTTP_PUT_RECV :
+    case HTTP_STATE_PUT_RECV :
         do
        {
           if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
          {
            if (con->http.error && con->http.error != EPIPE)
              cupsdLogMessage(CUPSD_LOG_DEBUG,
-                             "[Client %d] HTTP_PUT_RECV Closing for error "
+                             "[Client %d] HTTP_STATE_PUT_RECV Closing for error "
                              "%d (%s)", con->http.fd, con->http.error,
                              strerror(con->http.error));
            else
              cupsdLogMessage(CUPSD_LOG_DEBUG,
-                             "[Client %d] HTTP_PUT_RECV Closing on EOF",
+                             "[Client %d] HTTP_STATE_PUT_RECV Closing on EOF",
                              con->http.fd);
 
            cupsdCloseClient(con);
@@ -2010,9 +2107,9 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
          }
         }
-       while (con->http.state == HTTP_PUT_RECV && data_ready(con));
+       while (con->http.state == HTTP_STATE_PUT_RECV && data_ready(con));
 
-        if (con->http.state == HTTP_WAITING)
+        if (con->http.state == HTTP_STATE_STATUS)
        {
         /*
          * End of file, see how big it is...
@@ -2044,7 +2141,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
          * Install the configuration file...
          */
 
-          status = install_conf_file(con);
+          status = install_cupsd_conf(con);
 
          /*
          * Return the status to the client...
@@ -2058,7 +2155,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
        }
         break;
 
-    case HTTP_POST_RECV :
+    case HTTP_STATE_POST_RECV :
         do
        {
           if (con->request && con->file < 0)
@@ -2079,13 +2176,15 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
            }
            else if (ipp_state != IPP_DATA)
            {
-              if (con->http.state == HTTP_POST_SEND)
+              if (con->http.state == HTTP_STATE_POST_SEND)
              {
                cupsdSendError(con, HTTP_BAD_REQUEST, CUPSD_AUTH_NONE);
                cupsdCloseClient(con);
                return;
              }
 
+             if (data_ready(con))
+               continue;
              break;
             }
            else
@@ -2099,7 +2198,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
            }
          }
 
-          if (con->file < 0 && con->http.state != HTTP_POST_SEND)
+          if (con->file < 0 && con->http.state != HTTP_STATE_POST_SEND)
          {
            /*
            * Create a file as needed for the request data...
@@ -2128,18 +2227,20 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
             fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
          }
 
-         if (con->http.state != HTTP_POST_SEND)
+         if (con->http.state != HTTP_STATE_POST_SEND)
          {
-            if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
+           if (!httpWait(HTTP(con), 0))
+             return;
+            else if ((bytes = httpRead2(HTTP(con), line, sizeof(line))) < 0)
            {
              if (con->http.error && con->http.error != EPIPE)
                cupsdLogMessage(CUPSD_LOG_DEBUG,
-                               "[Client %d] HTTP_POST_SEND Closing for "
+                               "[Client %d] HTTP_STATE_POST_SEND Closing for "
                                "error %d (%s)", con->http.fd, con->http.error,
                                strerror(con->http.error));
              else
                cupsdLogMessage(CUPSD_LOG_DEBUG,
-                               "[Client %d] HTTP_POST_SEND Closing on EOF",
+                               "[Client %d] HTTP_STATE_POST_SEND Closing on EOF",
                                con->http.fd);
 
              cupsdCloseClient(con);
@@ -2169,21 +2270,21 @@ cupsdReadClient(cupsd_client_t *con)    /* I - Client to read from */
                }
              }
            }
-           else if (con->http.state == HTTP_POST_RECV)
+           else if (con->http.state == HTTP_STATE_POST_RECV)
               return;
-           else if (con->http.state != HTTP_POST_SEND)
+           else if (con->http.state != HTTP_STATE_POST_SEND)
            {
              cupsdLogMessage(CUPSD_LOG_DEBUG,
                              "[Client %d] Closing on unexpected state %s.",
-                             con->http.fd, http_states[con->http.state]);
+                             con->http.fd, http_states[con->http.state + 1]);
              cupsdCloseClient(con);
              return;
            }
          }
         }
-       while (con->http.state == HTTP_POST_RECV && data_ready(con));
+       while (con->http.state == HTTP_STATE_POST_RECV && data_ready(con));
 
-       if (con->http.state == HTTP_POST_SEND)
+       if (con->http.state == HTTP_STATE_POST_SEND)
        {
          if (con->file >= 0)
          {
@@ -2262,7 +2363,7 @@ cupsdReadClient(cupsd_client_t *con)      /* I - Client to read from */
         break; /* Anti-compiler-warning-code */
   }
 
-  if (con->http.state == HTTP_WAITING)
+  if (con->http.state == HTTP_STATE_WAITING)
   {
     if (!con->http.keep_alive)
     {
@@ -2397,7 +2498,7 @@ cupsdSendError(cupsd_client_t *con,       /* I - Connection */
     if (httpPrintf(HTTP(con), "Connection: Upgrade\r\n") < 0)
       return (0);
 
-  if (httpPrintf(HTTP(con), "Upgrade: TLS/1.0,HTTP/1.1\r\n") < 0)
+  if (httpPrintf(HTTP(con), "Upgrade: TLS/1.2,TLS/1.1,TLS/1.0\r\n") < 0)
     return (0);
 #endif /* HAVE_SSL */
 
@@ -2487,7 +2588,9 @@ cupsdSendError(cupsd_client_t *con,       /* I - Connection */
   if (cupsdFlushHeader(con) < 0)
     return (0);
 
-  con->http.state = HTTP_WAITING;
+  con->http.state = HTTP_STATE_WAITING;
+
+  DEBUG_puts("cupsdSendError: Set state to HTTP_STATE_WAITING.");
 
   return (1);
 }
@@ -2532,7 +2635,7 @@ cupsdSendHeader(
 
   httpFlushWrite(HTTP(con));
 
-  con->http.data_encoding = HTTP_ENCODE_FIELDS;
+  con->http.data_encoding = HTTP_ENCODING_FIELDS;
 
   if (httpPrintf(HTTP(con), "HTTP/%d.%d %d %s\r\n", con->http.version / 100,
                  con->http.version % 100, code, httpStatus(code)) < 0)
@@ -2714,27 +2817,27 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
   ipp_state_t  ipp_state;              /* IPP state value */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
                  "[Client %d] cupsdWriteClient "
                  "error=%d, "
                  "used=%d, "
                  "state=%s, "
-                 "data_encoding=HTTP_ENCODE_%s, "
+                 "data_encoding=HTTP_ENCODING_%s, "
                  "data_remaining=" CUPS_LLFMT ", "
                  "response=%p(%s), "
                  "pipe_pid=%d, "
                  "file=%d",
                  con->http.fd, con->http.error, con->http.used,
-                 http_states[con->http.state],
-                 con->http.data_encoding == HTTP_ENCODE_CHUNKED ?
+                 http_states[con->http.state + 1],
+                 con->http.data_encoding == HTTP_ENCODING_CHUNKED ?
                      "CHUNKED" : "LENGTH",
                  CUPS_LLCAST con->http.data_remaining,
                  con->response,
                  con->response ? ipp_states[con->response->state] : "",
                  con->pipe_pid, con->file);
 
-  if (con->http.state != HTTP_GET_SEND &&
-      con->http.state != HTTP_POST_SEND)
+  if (con->http.state != HTTP_STATE_GET_SEND &&
+      con->http.state != HTTP_STATE_POST_SEND)
   {
    /*
     * If we get called in the wrong state, then something went wrong with the
@@ -2743,7 +2846,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
 
     cupsdLogMessage(CUPSD_LOG_DEBUG,
                    "[Client %d] Closing on unexpected HTTP state %s.",
-                   con->http.fd, http_states[con->http.state]);
+                   con->http.fd, http_states[con->http.state + 1]);
     cupsdCloseClient(con);
     return;
   }
@@ -2771,9 +2874,37 @@ cupsdWriteClient(cupsd_client_t *con)    /* I - Client connection */
 
   if (con->response && con->response->state != IPP_DATA)
   {
-    ipp_state = ippWrite(HTTP(con), con->response);
-    bytes     = ipp_state != IPP_ERROR &&
-                (con->file >= 0 || ipp_state != IPP_DATA);
+    int wused = con->http.wused;       /* Previous write buffer use */
+
+    do
+    {
+     /*
+      * Write a single attribute or the IPP message header...
+      */
+
+//      ipp_state = ippWrite(HTTP(con), con->response);
+      ipp_state = ippWriteIO(HTTP(con), (ipp_iocb_t)httpWrite2, 1, NULL,
+                             con->response);
+
+     /*
+      * If the write buffer has been flushed, stop buffering up attributes...
+      */
+
+      if (con->http.wused <= wused)
+        break;
+    }
+    while (ipp_state != IPP_STATE_DATA && ipp_state != IPP_STATE_ERROR);
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                    "[Client %d] Writing IPP response, ipp_state=%d, old "
+                    "wused=%d, new wused=%d", con->http.fd, ipp_state, wused,
+                    con->http.wused);
+
+    if (con->http.wused > 0)
+      httpFlushWrite(HTTP(con));
+
+    bytes = ipp_state != IPP_STATE_ERROR &&
+           (con->file >= 0 || ipp_state != IPP_STATE_DATA);
   }
   else if ((bytes = read(con->file, con->header + con->header_used,
                         sizeof(con->header) - con->header_used)) > 0)
@@ -2875,7 +3006,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
            }
 
            if (con->http.version == HTTP_1_1)
-             con->http.data_encoding = HTTP_ENCODE_CHUNKED;
+             con->http.data_encoding = HTTP_ENCODING_CHUNKED;
           }
          else
            field_col = 0;
@@ -2903,12 +3034,12 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
        return;
       }
 
-      if (con->http.data_encoding == HTTP_ENCODE_CHUNKED)
+      if (con->http.data_encoding == HTTP_ENCODING_CHUNKED)
         httpFlushWrite(HTTP(con));
 
       con->bytes += con->header_used;
 
-      if (con->http.state == HTTP_WAITING)
+      if (con->http.state == HTTP_STATE_WAITING)
        bytes = 0;
       else
         bytes = con->header_used;
@@ -2918,7 +3049,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
   }
 
   if (bytes <= 0 ||
-      (con->http.state != HTTP_GET_SEND && con->http.state != HTTP_POST_SEND))
+      (con->http.state != HTTP_STATE_GET_SEND && con->http.state != HTTP_STATE_POST_SEND))
   {
     if (!con->sent_header && con->pipe_pid)
       cupsdSendError(con, HTTP_SERVER_ERROR, CUPSD_AUTH_NONE);
@@ -2928,7 +3059,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
 
       httpFlushWrite(HTTP(con));
 
-      if (con->http.data_encoding == HTTP_ENCODE_CHUNKED && con->sent_header == 1)
+      if (con->http.data_encoding == HTTP_ENCODING_CHUNKED && con->sent_header == 1)
       {
        if (httpWrite2(HTTP(con), "", 0) < 0)
        {
@@ -2942,7 +3073,7 @@ cupsdWriteClient(cupsd_client_t *con)     /* I - Client connection */
       }
     }
 
-    con->http.state = HTTP_WAITING;
+    con->http.state = HTTP_STATE_WAITING;
 
     cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, NULL, con);
 
@@ -3301,14 +3432,13 @@ get_file(cupsd_client_t *con,           /* I  - Client connection */
 
 
 /*
- * 'install_conf_file()' - Install a configuration file.
+ * 'install_cupsd_conf()' - Install a configuration file.
  */
 
 static http_status_t                   /* O - Status */
-install_conf_file(cupsd_client_t *con) /* I - Connection */
+install_cupsd_conf(cupsd_client_t *con)        /* I - Connection */
 {
   char         filename[1024];         /* Configuration filename */
-  mode_t       mode;                   /* Permissions */
   cups_file_t  *in,                    /* Input file */
                *out;                   /* Output file */
   char         buffer[16384];          /* Copy buffer */
@@ -3330,19 +3460,14 @@ install_conf_file(cupsd_client_t *con)  /* I - Connection */
   * Open the new config file...
   */
 
-  snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
-  if (!strcmp(con->uri, "/admin/conf/printers.conf"))
-    mode = ConfigFilePerm & 0600;
-  else
-    mode = ConfigFilePerm;
-
-  if ((out = cupsdCreateConfFile(filename, mode)) == NULL)
+  if ((out = cupsdCreateConfFile(ConfigurationFile, ConfigFilePerm)) == NULL)
   {
     cupsFileClose(in);
     return (HTTP_SERVER_ERROR);
   }
 
-  cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...", filename);
+  cupsdLogMessage(CUPSD_LOG_INFO, "Installing config file \"%s\"...",
+                  ConfigurationFile);
 
  /*
   * Copy from the request to the new config file...
@@ -3353,13 +3478,13 @@ install_conf_file(cupsd_client_t *con)  /* I - Connection */
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Unable to copy to config file \"%s\": %s",
-                     filename, strerror(errno));
+                     ConfigurationFile, strerror(errno));
 
       cupsFileClose(in);
       cupsFileClose(out);
 
-      snprintf(filename, sizeof(filename), "%s%s.N", ServerRoot, con->uri + 11);
-      cupsdRemoveFile(filename);
+      snprintf(filename, sizeof(filename), "%s.N", ConfigurationFile);
+      cupsdUnlinkOrRemoveFile(filename);
 
       return (HTTP_SERVER_ERROR);
     }
@@ -3370,25 +3495,21 @@ install_conf_file(cupsd_client_t *con)  /* I - Connection */
 
   cupsFileClose(in);
 
-  if (cupsdCloseCreatedConfFile(out, filename))
+  if (cupsdCloseCreatedConfFile(out, ConfigurationFile))
     return (HTTP_SERVER_ERROR);
 
  /*
   * Remove the request file...
   */
 
-  cupsdRemoveFile(con->filename);
+  cupsdUnlinkOrRemoveFile(con->filename);
   cupsdClearString(&con->filename);
 
  /*
-  * If the cupsd.conf file was updated, set the NeedReload flag...
+  * Set the NeedReload flag...
   */
 
-  if (!strcmp(con->uri, "/admin/conf/cupsd.conf"))
-    NeedReload = RELOAD_CUPSD;
-  else
-    NeedReload = RELOAD_ALL;
-
+  NeedReload = RELOAD_CUPSD;
   ReloadTime = time(NULL);
 
  /*
@@ -3621,7 +3742,6 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
                server_name[1024],      /* SERVER_NAME environment variable */
                server_port[1024];      /* SERVER_PORT environment variable */
   ipp_attribute_t *attr;               /* attributes-natural-language attribute */
-  void         *ccache = NULL;         /* Kerberos credentials */
 
 
  /*
@@ -3683,7 +3803,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
       commptr ++;
   }
 
-  if (*commptr == '?' && con->operation == HTTP_GET && !con->query_string)
+  if (*commptr == '?' && con->operation == HTTP_STATE_GET && !con->query_string)
   {
     commptr ++;
     cupsdSetStringf(&(con->query_string), "QUERY_STRING=%s", commptr);
@@ -3776,7 +3896,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
          * the POSIX locale...
          */
 
-         strcpy(lang, "LANG=C");
+         strlcpy(lang, "LANG=C", sizeof(lang));
          break;
 
       case 2 :
@@ -3804,9 +3924,9 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   else if (con->language)
     snprintf(lang, sizeof(lang), "LANG=%s.UTF8", con->language->language);
   else
-    strcpy(lang, "LANG=C");
+    strlcpy(lang, "LANG=C", sizeof(lang));
 
-  strcpy(remote_addr, "REMOTE_ADDR=");
+  strlcpy(remote_addr, "REMOTE_ADDR=", sizeof(remote_addr));
   httpAddrString(con->http.hostaddr, remote_addr + 12,
                  sizeof(remote_addr) - 12);
 
@@ -3888,7 +4008,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
     envp[envc ++] = http_referer;
   }
 
-  if (con->operation == HTTP_GET)
+  if (con->operation == HTTP_STATE_GET)
   {
     envp[envc ++] = "REQUEST_METHOD=GET";
 
@@ -3973,7 +4093,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
     */
 
     if (con->username[0])
-      cupsdAddCert(pid, con->username, ccache);
+      cupsdAddCert(pid, con->username, con->type);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG, "[CGI] Started %s (PID %d)", command, pid);
 
@@ -4194,7 +4314,7 @@ write_file(cupsd_client_t *con,           /* I - Client connection */
   if (cupsdFlushHeader(con) < 0)
     return (0);
 
-  con->http.data_encoding  = HTTP_ENCODE_LENGTH;
+  con->http.data_encoding  = HTTP_ENCODING_LENGTH;
   con->http.data_remaining = filestats->st_size;
 
   if (con->http.data_remaining <= INT_MAX)
@@ -4228,5 +4348,5 @@ write_pipe(cupsd_client_t *con)           /* I - Client connection */
 
 
 /*
- * End of "$Id: client.c 7950 2008-09-17 00:21:59Z mike $".
+ * End of "$Id$".
  */