]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add new httpGetContentEncoding API.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Tue, 13 Nov 2012 19:22:57 +0000 (19:22 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Tue, 13 Nov 2012 19:22:57 +0000 (19:22 +0000)
Support Accept-Encoding in ippserver.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10694 7a7537e8-13f0-0310-91df-b6672ffda945

cups/http-private.h
cups/http.c
cups/http.h
test/ippserver.c

index f8a1e38ddfc8503843b2fc8189df8987dc2a8816..af6b3a47ad725365c6234704307892974b2ffa48 100644 (file)
@@ -403,7 +403,9 @@ extern void _cups_freeifaddrs(struct ifaddrs *addrs);
  */
 
 #define                        _httpAddrFamily(addrp) (addrp)->addr.sa_family
-extern int             _httpAddrPort(http_addr_t *addr) _CUPS_DEPRECATED_MSG("Use httpAddrPort instead.");
+extern int             _httpAddrPort(http_addr_t *addr)
+                                     _CUPS_DEPRECATED_MSG("Use httpAddrPort "
+                                                          "instead.");
 extern void            _httpAddrSetPort(http_addr_t *addr, int port);
 extern char            *_httpAssembleUUID(const char *server, int port,
                                           const char *name, int number,
@@ -421,7 +423,7 @@ extern char         *_httpEncodeURI(char *dst, const char *src,
                                        size_t dstsize);
 extern void            _httpFreeCredentials(http_tls_credentials_t credentials);
 extern ssize_t         _httpPeek(http_t *http, char *buffer, size_t length)
-                                 _CUPS_DEPRECATED;
+                                 _CUPS_DEPRECATED_MSG("Use httpPeek instead.");
 extern const char      *_httpResolveURI(const char *uri, char *resolved_uri,
                                         size_t resolved_size, int options,
                                         int (*cb)(void *context),
index f4d48b8ad378d0fc4ffd6b6fcf186400580b0d06..80d687d4a5029414df8a7ddf2c82308654cba878 100644 (file)
@@ -48,6 +48,8 @@
  *   _httpFreeCredentials()      - Free internal credentials.
  *   httpFreeCredentials()       - Free an array of credentials.
  *   httpGet()                   - Send a GET request to the server.
+ *   httpGetContentEncoding()     - Get a common content encoding, if any,
+ *                                  between the client and server.
  *   httpGetAuthString()         - Get the current authorization string.
  *   httpGetBlocking()           - Get the blocking/non-block state of a
  *                                 connection.
@@ -1021,7 +1023,8 @@ httpFlushWrite(http_t *http)              /* I - Connection to server */
   int  bytes;                          /* Bytes written */
 
 
-  DEBUG_printf(("httpFlushWrite(http=%p)", http));
+  DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", http,
+                http ? http->data_encoding : -1));
 
   if (!http || !http->wused)
   {
@@ -1106,6 +1109,94 @@ httpGet(http_t     *http,                /* I - Connection to server */
 }
 
 
+/*
+ * 'httpGetContentEncoding()' - Get a common content encoding, if any, between
+ *                              the client and server.
+ *
+ * This function uses the value of the Accepts-Encoding HTTP header and must be
+ * called after receiving a response from the server or a request from the
+ * client.  The value returned can be use in subsequent requests (for clients)
+ * or in the response (for servers) in order to compress the content stream.
+ *
+ * @since CUPS 1.7@
+ */
+
+const char *                           /* O - Content-Coding value or
+                                              @code NULL@ for the identity
+                                              coding. */
+httpGetContentEncoding(http_t *http)   /* I - Connection to client/server */
+{
+#ifdef HAVE_LIBZ
+  if (http && http->accept_encoding)
+  {
+    int                i;                      /* Looping var */
+    char       temp[HTTP_MAX_VALUE],   /* Copy of Accepts-Encoding value */
+               *start,                 /* Start of coding value */
+               *end;                   /* End of coding value */
+    double     qvalue;                 /* "qvalue" for coding */
+    struct lconv *loc = localeconv();  /* Locale data */
+    static const char * const codings[] =
+    {                                  /* Supported content codings */
+      "deflate",
+      "gzip",
+      "x-deflate",
+      "x-gzip"
+    };
+
+    strlcpy(temp, http->accept_encoding, sizeof(temp));
+
+    for (start = temp; *start; start = end)
+    {
+     /*
+      * Find the end of the coding name...
+      */
+
+      qvalue = 1.0;
+      end    = start;
+      while (*end && *end != ';' && *end != ',' && !isspace(*end & 255))
+        end ++;
+
+      if (*end == ';')
+      {
+       /*
+        * Grab the qvalue as needed...
+        */
+
+        if (!strncmp(end, ";q=", 3))
+          qvalue = _cupsStrScand(end + 3, NULL, loc);
+
+       /*
+        * Skip past all attributes...
+        */
+
+        *end++ = '\0';
+        while (*end && *end != ',' && !isspace(*end & 255))
+          end ++;
+      }
+      else if (*end)
+        *end++ = '\0';
+
+      while (*end && isspace(*end & 255))
+       end ++;
+
+     /*
+      * Check value if it matches something we support...
+      */
+
+      if (qvalue <= 0.0)
+        continue;
+
+      for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++)
+        if (!strcmp(start, codings[i]))
+          return (codings[i]);
+    }
+  }
+#endif /* HAVE_LIBZ */
+
+  return (NULL);
+}
+
+
 /*
  * 'httpGetAuthString()' - Get the current authorization string.
  *
@@ -1265,6 +1356,10 @@ httpGetLength(http_t *http)              /* I - Connection to server */
 off_t                                  /* O - Content length */
 httpGetLength2(http_t *http)           /* I - Connection to server */
 {
+  http_encoding_t      encoding;       /* Data encoding */
+  off_t                        remaining;      /* Remaining length */
+
+
   DEBUG_printf(("2httpGetLength2(http=%p), state=%s", http,
                 http_states[http->state + 1]));
 
@@ -1275,12 +1370,12 @@ httpGetLength2(http_t *http)            /* I - Connection to server */
   {
     DEBUG_puts("4httpGetLength2: chunked request!");
 
-    http->data_encoding  = HTTP_ENCODING_CHUNKED;
-    http->data_remaining = 0;
+    encoding  = HTTP_ENCODING_CHUNKED;
+    remaining = 0;
   }
   else
   {
-    http->data_encoding = HTTP_ENCODING_LENGTH;
+    encoding = HTTP_ENCODING_LENGTH;
 
    /*
     * The following is a hack for HTTP servers that don't send a
@@ -1298,25 +1393,35 @@ httpGetLength2(http_t *http)            /* I - Connection to server */
       */
 
       if (http->status >= HTTP_MULTIPLE_CHOICES)
-        http->data_remaining = 0;
+        remaining = 0;
       else
-        http->data_remaining = 2147483647;
+        remaining = 2147483647;
     }
-    else if ((http->data_remaining =
-                  strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
-                         NULL, 10)) < 0)
+    else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
+                                 NULL, 10)) < 0)
       return (-1);
 
     DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT,
-                  CUPS_LLCAST http->data_remaining));
+                  CUPS_LLCAST remaining));
   }
 
-  if (http->data_remaining <= INT_MAX)
-    http->_data_remaining = (int)http->data_remaining;
-  else
-    http->_data_remaining = INT_MAX;
+  if ((http->mode == _HTTP_MODE_CLIENT &&
+       (http->state == HTTP_STATE_GET || http->state == HTTP_STATE_POST ||
+        http->state == HTTP_STATE_PUT)) ||
+      (http->mode == _HTTP_MODE_SERVER &&
+       (http->state == HTTP_STATE_GET_SEND ||
+        http->state == HTTP_STATE_POST_SEND)))
+  {
+    http->data_encoding  = encoding;
+    http->data_remaining = remaining;
+
+    if (remaining <= INT_MAX)
+      http->_data_remaining = (int)remaining;
+    else
+      http->_data_remaining = INT_MAX;
+  }
 
-  return (http->data_remaining);
+  return (remaining);
 }
 
 
@@ -3309,6 +3414,8 @@ _httpUpdate(http_t        *http,  /* I - Connection to server */
     while (_cups_isspace(*value))
       value ++;
 
+    DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
+
    /*
     * Be tolerants of servers that send unknown attribute fields...
     */
@@ -3953,6 +4060,11 @@ httpWriteResponse(http_t        *http,   /* I - HTTP connection */
     return (-1);
   }
 
+ /*
+  * Force data_encoding and data_length to be set according to the response
+  * headers...
+  */
+
   (void)httpGetLength2(http);
 
   http_content_coding_start(http,
index f2ce0dde1140aab605067bba2eae85f430feb9e8..53dcffea769c4b3b456535a98236ae6e98905a38 100644 (file)
@@ -585,8 +585,6 @@ extern int          httpReconnect2(http_t *http, int msec, int *cancel)
 
 
 /**** New in CUPS 1.7 ****/
-//extern int           httpAcceptsEncoding(http_t *http, const char *coding)
-//                                         _CUPS_API_1_7;
 extern http_t          *httpAcceptConnection(int fd, int blocking)
                                              _CUPS_API_1_7;
 extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7;
@@ -598,6 +596,7 @@ extern http_t               *httpConnect2(const char *host, int port,
                                      int family, http_encryption_t encryption,
                                      int blocking, int msec, int *cancel)
                                      _CUPS_API_1_7;
+extern const char      *httpGetContentEncoding(http_t *http) _CUPS_API_1_7;
 extern http_status_t   httpGetExpect(http_t *http) _CUPS_API_1_7;
 extern ssize_t         httpPeek(http_t *http, char *buffer, size_t length)
                                 _CUPS_API_1_7;
index e4bd264c228343b0c9fe4ec0b2c6dbcaa7fc5920..2c8fc84e8a01445767f05f8fdf6df494b0fd0ebb 100644 (file)
@@ -334,6 +334,7 @@ static int          register_printer(_ipp_printer_t *printer,
                                         int duplex, const char *regtype);
 #endif /* HAVE_DNSSD */
 static int             respond_http(_ipp_client_t *client, http_status_t code,
+                                    const char *content_coding,
                                     const char *type, size_t length);
 static void            respond_ipp(_ipp_client_t *client, ipp_status_t status,
                                    const char *message, ...)
@@ -3922,6 +3923,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
                        hostname[HTTP_MAX_HOST];
                                        /* Hostname */
   int                  port;           /* Port number */
+  const char           *encoding;      /* Content-Encoding value */
 
 
  /*
@@ -3952,19 +3954,19 @@ process_http(_ipp_client_t *client)     /* I - Client connection */
   if (http_state == HTTP_STATE_ERROR)
   {
     fprintf(stderr, "%s Bad request line.\n", client->hostname);
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
   else if (http_state == HTTP_STATE_UNKNOWN_METHOD)
   {
     fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname);
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
   else if (http_state == HTTP_STATE_UNKNOWN_VERSION)
   {
     fprintf(stderr, "%s Bad HTTP version.\n", client->hostname);
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
 
@@ -3978,7 +3980,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
                      client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK)
   {
     fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri);
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
 
@@ -3997,7 +3999,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
 
   if (http_status != HTTP_STATUS_OK)
   {
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
 
@@ -4008,7 +4010,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
     * HTTP/1.1 and higher require the "Host:" field...
     */
 
-    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+    respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
     return (0);
   }
 
@@ -4019,7 +4021,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
   if (!_cups_strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION),
                         "Upgrade"))
   {
-    if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, 0))
+    if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0))
       return (0);
   }
 
@@ -4037,7 +4039,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
       * Send 100-continue header...
       */
 
-      if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, 0))
+      if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0))
        return (0);
     }
     else
@@ -4046,7 +4048,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
       * Send 417-expectation-failed header...
       */
 
-      if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, 0))
+      if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0))
        return (0);
     }
   }
@@ -4055,6 +4057,8 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
   * Handle new transfers...
   */
 
+  encoding = httpGetContentEncoding(client->http);
+
   switch (client->operation)
   {
     case HTTP_STATE_OPTIONS :
@@ -4062,15 +4066,15 @@ process_http(_ipp_client_t *client)     /* I - Client connection */
        * Do HEAD/OPTIONS command...
        */
 
-       return (respond_http(client, HTTP_STATUS_OK, NULL, 0));
+       return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0));
 
     case HTTP_STATE_HEAD :
         if (!strcmp(client->uri, "/icon.png"))
-         return (respond_http(client, HTTP_STATUS_OK, "image/png", 0));
+         return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0));
        else if (!strcmp(client->uri, "/"))
-         return (respond_http(client, HTTP_STATUS_OK, "text/html", 0));
+         return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0));
        else
-         return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+         return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
        break;
 
     case HTTP_STATE_GET :
@@ -4090,7 +4094,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
           if (!stat(client->printer->icon, &fileinfo) &&
              (fd = open(client->printer->icon, O_RDONLY)) >= 0)
          {
-           if (!respond_http(client, HTTP_STATUS_OK, "image/png",
+           if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png",
                              fileinfo.st_size))
            {
              close(fd);
@@ -4105,7 +4109,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
            close(fd);
          }
          else
-           return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+           return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
        }
        else if (!strcmp(client->uri, "/"))
        {
@@ -4113,7 +4117,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
          * Show web status page...
          */
 
-          if (!respond_http(client, HTTP_STATUS_OK, "text/html", 0))
+          if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0))
            return (0);
 
           html_printf(client,
@@ -4141,7 +4145,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
          return (1);
        }
        else
-         return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+         return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
        break;
 
     case HTTP_STATE_POST :
@@ -4152,7 +4156,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
          * Not an IPP request...
          */
 
-         return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0));
+         return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0));
        }
 
        /*
@@ -4168,7 +4172,7 @@ process_http(_ipp_client_t *client)       /* I - Client connection */
          {
             fprintf(stderr, "%s IPP read error (%s).\n", client->hostname,
                    cupsLastErrorString());
-           respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+           respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
            return (0);
          }
        }
@@ -4336,7 +4340,7 @@ process_ipp(_ipp_client_t *client)        /* I - Client */
          * Send 100-continue header...
          */
 
-         if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, 0))
+         if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0))
            return (0);
        }
 
@@ -4398,7 +4402,7 @@ process_ipp(_ipp_client_t *client)        /* I - Client */
   if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
     httpFlush(client->http);           /* Flush trailing (junk) data */
 
-  return (respond_http(client, HTTP_STATUS_OK, "application/ipp",
+  return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp",
                        ippLength(client->response)));
 }
 
@@ -4597,10 +4601,12 @@ register_printer(
  */
 
 int                                    /* O - 1 on success, 0 on failure */
-respond_http(_ipp_client_t *client,    /* I - Client */
-            http_status_t code,        /* I - HTTP status of response */
-            const char    *type,       /* I - MIME type of response */
-            size_t        length)      /* I - Length of response */
+respond_http(
+    _ipp_client_t *client,             /* I - Client */
+    http_status_t code,                        /* I - HTTP status of response */
+    const char    *content_encoding,   /* I - Content-Encoding of response */
+    const char    *type,               /* I - MIME media type of response */
+    size_t        length)              /* I - Length of response */
 {
   char message[1024];                  /* Text message */
 
@@ -4647,6 +4653,9 @@ respond_http(_ipp_client_t *client,       /* I - Client */
                    "text/html; charset=utf-8");
     else
       httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type);
+
+    if (content_encoding)
+      httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding);
   }
 
   httpSetLength(client->http, length);