]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http.c
Merge pull request #5913 from apple/bug-fix-rollup-1
[thirdparty/cups.git] / cups / http.c
index 794a213b2f030de9a386f65a0e72781ff16d30d4..43ace18f4428f7313809e644dead8b4af81a677a 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * HTTP routines for CUPS.
  *
- * Copyright 2007-2018 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright © 2007-2021 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
  *
  * This file contains Kerberos support code, copyright 2006 by
  * Jelmer Vernooij.
@@ -16,6 +16,7 @@
  */
 
 #include "cups-private.h"
+#include "debug-internal.h"
 #include <fcntl.h>
 #include <math.h>
 #ifdef _WIN32
@@ -28,6 +29,9 @@
 #ifdef HAVE_POLL
 #  include <poll.h>
 #endif /* HAVE_POLL */
+#  ifdef HAVE_LIBZ
+#    include <zlib.h>
+#  endif /* HAVE_LIBZ */
 
 
 /*
@@ -1341,8 +1345,11 @@ httpGetSubField2(http_t       *http,     /* I - HTTP connection */
 
   DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen));
 
+  if (value)
+    *value = '\0';
+
   if (!http || !name || !value || valuelen < 2 ||
-      field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
+      field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !http->fields[field])
     return (NULL);
 
   end = value + valuelen - 1;
@@ -1675,7 +1682,7 @@ httpPeek(http_t *http,                    /* I - HTTP connection */
 #ifdef HAVE_LIBZ
   if (http->used == 0 &&
       (http->coding == _HTTP_CODING_IDENTITY ||
-       (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)))
+       (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)))
 #else
   if (http->used == 0)
 #endif /* HAVE_LIBZ */
@@ -1724,16 +1731,16 @@ httpPeek(http_t *http,                  /* I - HTTP connection */
     int                zerr;                   /* Decompressor error */
     z_stream   stream;                 /* Copy of decompressor stream */
 
-    if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER)
+    if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER)
     {
-      size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in;
+      size_t buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
                                        /* Number of bytes to copy */
 
-      if (http->stream.avail_in > 0 &&
-         http->stream.next_in > http->sbuffer)
-        memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in);
+      if (((z_stream *)http->stream)->avail_in > 0 &&
+         ((z_stream *)http->stream)->next_in > http->sbuffer)
+        memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
 
-      http->stream.next_in = http->sbuffer;
+      ((z_stream *)http->stream)->next_in = http->sbuffer;
 
       if (buflen > (size_t)http->data_remaining)
         buflen = (size_t)http->data_remaining;
@@ -1744,8 +1751,8 @@ httpPeek(http_t *http,                    /* I - HTTP connection */
       DEBUG_printf(("1httpPeek: Copying %d more bytes of data into "
                    "decompression buffer.", (int)buflen));
 
-      memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen);
-      http->stream.avail_in += buflen;
+      memcpy(http->sbuffer + ((z_stream *)http->stream)->avail_in, http->buffer, buflen);
+      ((z_stream *)http->stream)->avail_in += buflen;
       http->used            -= (int)buflen;
       http->data_remaining  -= (off_t)buflen;
 
@@ -1754,9 +1761,9 @@ httpPeek(http_t *http,                    /* I - HTTP connection */
     }
 
     DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length,
-                  (int)http->stream.avail_in));
+                  (int)((z_stream *)http->stream)->avail_in));
 
-    if (inflateCopy(&stream, &(http->stream)) != Z_OK)
+    if (inflateCopy(&stream, (z_stream *)http->stream) != Z_OK)
     {
       DEBUG_puts("2httpPeek: Unable to copy decompressor stream.");
       http->error = ENOMEM;
@@ -1773,14 +1780,14 @@ httpPeek(http_t *http,                  /* I - HTTP connection */
     {
       DEBUG_printf(("2httpPeek: zerr=%d", zerr));
 #ifdef DEBUG
-      http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in);
+      http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
 #endif /* DEBUG */
 
       http->error = EIO;
       return (-1);
     }
 
-    bytes = (ssize_t)(length - http->stream.avail_out);
+    bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
 
 #  else
     DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not "
@@ -1853,7 +1860,7 @@ httpPrintf(http_t     *http,              /* I - HTTP connection */
           ...)                         /* I - Additional args as needed */
 {
   ssize_t      bytes;                  /* Number of bytes to write */
-  char         buf[16384];             /* Buffer for formatted string */
+  char         buf[65536];             /* Buffer for formatted string */
   va_list      ap;                     /* Variable argument pointer */
 
 
@@ -1865,7 +1872,12 @@ httpPrintf(http_t     *http,             /* I - HTTP connection */
 
   DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf));
 
-  if (http->data_encoding == HTTP_ENCODING_FIELDS)
+  if (bytes > (ssize_t)(sizeof(buf) - 1))
+  {
+    http->error = ENOMEM;
+    return (-1);
+  }
+  else if (http->data_encoding == HTTP_ENCODING_FIELDS)
     return ((int)httpWrite2(http, buf, (size_t)bytes));
   else
   {
@@ -1947,31 +1959,31 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
   {
     do
     {
-      if (http->stream.avail_in > 0)
+      if (((z_stream *)http->stream)->avail_in > 0)
       {
        int     zerr;                   /* Decompressor error */
 
        DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d",
-                     (int)http->stream.avail_in, (int)length));
+                     (int)((z_stream *)http->stream)->avail_in, (int)length));
 
-       http->stream.next_out  = (Bytef *)buffer;
-       http->stream.avail_out = (uInt)length;
+       ((z_stream *)http->stream)->next_out  = (Bytef *)buffer;
+       ((z_stream *)http->stream)->avail_out = (uInt)length;
 
-       if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK)
+       if ((zerr = inflate((z_stream *)http->stream, Z_SYNC_FLUSH)) < Z_OK)
        {
          DEBUG_printf(("2httpRead2: zerr=%d", zerr));
 #ifdef DEBUG
-          http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in);
+          http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
 #endif /* DEBUG */
 
          http->error = EIO;
          return (-1);
        }
 
-       bytes = (ssize_t)(length - http->stream.avail_out);
+       bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
 
        DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d",
-                     http->stream.avail_in, http->stream.avail_out,
+                     ((z_stream *)http->stream)->avail_in, ((z_stream *)http->stream)->avail_out,
                      (int)bytes));
       }
       else
@@ -1979,16 +1991,16 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
 
       if (bytes == 0)
       {
-        ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in;
+        ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
                                        /* Additional bytes for buffer */
 
         if (buflen > 0)
         {
-          if (http->stream.avail_in > 0 &&
-              http->stream.next_in > http->sbuffer)
-            memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in);
+          if (((z_stream *)http->stream)->avail_in > 0 &&
+              ((z_stream *)http->stream)->next_in > http->sbuffer)
+            memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
 
-         http->stream.next_in = http->sbuffer;
+         ((z_stream *)http->stream)->next_in = http->sbuffer;
 
           DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into "
                         "decompression buffer.", (int)buflen));
@@ -1998,10 +2010,10 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
            if (buflen > http->data_remaining)
              buflen = (ssize_t)http->data_remaining;
 
-           bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen);
+           bytes = http_read_buffered(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
           }
           else if (http->data_encoding == HTTP_ENCODING_CHUNKED)
-            bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen);
+            bytes = http_read_chunk(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
           else
             bytes = 0;
 
@@ -2014,7 +2026,7 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
                         "decompression buffer.", CUPS_LLCAST bytes));
 
           http->data_remaining  -= bytes;
-          http->stream.avail_in += (uInt)bytes;
+          ((z_stream *)http->stream)->avail_in += (uInt)bytes;
 
          if (http->data_remaining <= 0 &&
              http->data_encoding == HTTP_ENCODING_CHUNKED)
@@ -2093,7 +2105,7 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
   if (
 #ifdef HAVE_LIBZ
       (http->coding == _HTTP_CODING_IDENTITY ||
-       (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)) &&
+       (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)) &&
 #endif /* HAVE_LIBZ */
       ((http->data_remaining <= 0 &&
         http->data_encoding == HTTP_ENCODING_LENGTH) ||
@@ -2409,6 +2421,7 @@ httpReconnect2(http_t *http,              /* I - HTTP connection */
     if (_httpTLSStart(http) != 0)
     {
       httpAddrClose(NULL, http->fd);
+      http->fd = -1;
 
       return (-1);
     }
@@ -2774,6 +2787,7 @@ _httpUpdate(http_t        *http,  /* I - HTTP connection */
       if (_httpTLSStart(http) != 0)
       {
         httpAddrClose(NULL, http->fd);
+        http->fd = -1;
 
        *status = http->status = HTTP_STATUS_ERROR;
        return (0);
@@ -3074,7 +3088,7 @@ httpWait(http_t *http,                    /* I - HTTP connection */
   }
 
 #ifdef HAVE_LIBZ
-  if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0)
+  if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
   {
     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
     return (1);
@@ -3170,17 +3184,17 @@ httpWrite2(http_t     *http,            /* I - HTTP connection */
       size_t   slen;                   /* Bytes to write */
       ssize_t  sret;                   /* Bytes written */
 
-      http->stream.next_in   = (Bytef *)buffer;
-      http->stream.avail_in  = (uInt)length;
+      ((z_stream *)http->stream)->next_in   = (Bytef *)buffer;
+      ((z_stream *)http->stream)->avail_in  = (uInt)length;
 
-      while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK)
+      while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK)
       {
-        DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out));
+        DEBUG_printf(("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out));
 
-        if (http->stream.avail_out > 0)
+        if (((z_stream *)http->stream)->avail_out > 0)
          continue;
 
-       slen = _HTTP_MAX_SBUFFER - http->stream.avail_out;
+       slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
 
         DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
 
@@ -3197,8 +3211,8 @@ httpWrite2(http_t     *http,              /* I - HTTP connection */
          return (-1);
        }
 
-       http->stream.next_out  = (Bytef *)http->sbuffer;
-       http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
+       ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
+       ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
       }
 
       bytes = (ssize_t)length;
@@ -3640,7 +3654,15 @@ http_add_field(http_t       *http,       /* I - HTTP connection */
 
     char       *combined;              /* New value string */
 
-    if ((combined = realloc(http->fields[field], total + 1)) != NULL)
+    if (http->fields[field] == http->_fields[field])
+    {
+      if ((combined = malloc(total + 1)) != NULL)
+      {
+       http->fields[field] = combined;
+       snprintf(combined, total + 1, "%s, %s", http->_fields[field], value);
+      }
+    }
+    else if ((combined = realloc(http->fields[field], total + 1)) != NULL)
     {
       http->fields[field] = combined;
       strlcat(combined, ", ", total + 1);
@@ -3687,13 +3709,13 @@ http_content_coding_finish(
   {
     case _HTTP_CODING_DEFLATE :
     case _HTTP_CODING_GZIP :
-        http->stream.next_in  = dummy;
-        http->stream.avail_in = 0;
+        ((z_stream *)http->stream)->next_in  = dummy;
+        ((z_stream *)http->stream)->avail_in = 0;
 
         do
         {
-          zerr  = deflate(&(http->stream), Z_FINISH);
-         bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out;
+          zerr  = deflate((z_stream *)http->stream, Z_FINISH);
+         bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
 
           if (bytes > 0)
          {
@@ -3705,15 +3727,18 @@ http_content_coding_finish(
              http_write(http, (char *)http->sbuffer, bytes);
           }
 
-          http->stream.next_out  = (Bytef *)http->sbuffer;
-          http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
+          ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
+          ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
        }
         while (zerr == Z_OK);
 
-        deflateEnd(&(http->stream));
+        deflateEnd((z_stream *)http->stream);
 
         free(http->sbuffer);
+        free(http->stream);
+
         http->sbuffer = NULL;
+        http->stream  = NULL;
 
         if (http->wused)
           httpFlushWrite(http);
@@ -3721,9 +3746,13 @@ http_content_coding_finish(
 
     case _HTTP_CODING_INFLATE :
     case _HTTP_CODING_GUNZIP :
-        inflateEnd(&(http->stream));
+        inflateEnd((z_stream *)http->stream);
+
         free(http->sbuffer);
+        free(http->stream);
+
         http->sbuffer = NULL;
+        http->stream  = NULL;
         break;
 
     default :
@@ -3793,8 +3822,6 @@ http_content_coding_start(
     return;
   }
 
-  memset(&(http->stream), 0, sizeof(http->stream));
-
   switch (coding)
   {
     case _HTTP_CODING_DEFLATE :
@@ -3815,18 +3842,30 @@ http_content_coding_start(
         * documentation.
         */
 
-        if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION,
-                                 Z_DEFLATED,
-                                coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7,
-                                Z_DEFAULT_STRATEGY)) < Z_OK)
+       if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
+       {
+          free(http->sbuffer);
+
+          http->sbuffer = NULL;
+          http->status  = HTTP_STATUS_ERROR;
+          http->error   = errno;
+          return;
+       }
+
+        if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK)
         {
-          http->status = HTTP_STATUS_ERROR;
-          http->error  = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
+          free(http->sbuffer);
+          free(http->stream);
+
+          http->sbuffer = NULL;
+          http->stream  = NULL;
+          http->status  = HTTP_STATUS_ERROR;
+          http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
           return;
         }
 
-       http->stream.next_out  = (Bytef *)http->sbuffer;
-       http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
+       ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
+       ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
         break;
 
     case _HTTP_CODING_INFLATE :
@@ -3843,19 +3882,30 @@ http_content_coding_start(
         * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
         */
 
-        if ((zerr = inflateInit2(&(http->stream),
-                                 coding == _HTTP_CODING_INFLATE ? -15 : 31))
-               < Z_OK)
+       if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
+       {
+          free(http->sbuffer);
+
+          http->sbuffer = NULL;
+          http->status  = HTTP_STATUS_ERROR;
+          http->error   = errno;
+          return;
+       }
+
+        if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK)
         {
           free(http->sbuffer);
+          free(http->stream);
+
           http->sbuffer = NULL;
+          http->stream  = NULL;
           http->status  = HTTP_STATUS_ERROR;
           http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
           return;
         }
 
-        http->stream.avail_in = 0;
-        http->stream.next_in  = http->sbuffer;
+        ((z_stream *)http->stream)->avail_in = 0;
+        ((z_stream *)http->stream)->next_in  = http->sbuffer;
         break;
 
     default :