/*
* 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.
*/
#include "cups-private.h"
+#include "debug-internal.h"
#include <fcntl.h>
#include <math.h>
-#ifdef WIN32
+#ifdef _WIN32
# include <tchar.h>
#else
# include <signal.h>
# include <sys/time.h>
# include <sys/resource.h>
-#endif /* WIN32 */
+#endif /* _WIN32 */
#ifdef HAVE_POLL
# include <poll.h>
#endif /* HAVE_POLL */
+# ifdef HAVE_LIBZ
+# include <zlib.h>
+# endif /* HAVE_LIBZ */
/*
"WWW-Authenticate",
"Accept-Encoding",
"Allow",
- "Server"
+ "Server",
+ "Authentication-Info"
};
* Pre-load the buffer as needed...
*/
-#ifdef WIN32
+#ifdef _WIN32
WSASetLastError(0);
#else
errno = 0;
-#endif /* WIN32 */
+#endif /* _WIN32 */
while (http->used == 0)
{
continue;
DEBUG_puts("3httpGets: Timed out!");
-#ifdef WIN32
+#ifdef _WIN32
http->error = WSAETIMEDOUT;
#else
http->error = ETIMEDOUT;
-#endif /* WIN32 */
+#endif /* _WIN32 */
return (NULL);
}
* Nope, can't get a line this time...
*/
-#ifdef WIN32
+#ifdef _WIN32
DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
if (WSAGetLastError() == WSAEINTR)
http->error = errno;
continue;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
return (NULL);
}
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;
httpInitialize(void)
{
static int initialized = 0; /* Have we been called before? */
-#ifdef WIN32
+#ifdef _WIN32
WSADATA winsockdata; /* WinSock data */
-#endif /* WIN32 */
+#endif /* _WIN32 */
_cupsGlobalLock();
return;
}
-#ifdef WIN32
+#ifdef _WIN32
WSAStartup(MAKEWORD(2,2), &winsockdata);
#elif !defined(SO_NOSIGPIPE)
# else
signal(SIGPIPE, SIG_IGN);
# endif /* !SO_NOSIGPIPE */
-#endif /* WIN32 */
+#endif /* _WIN32 */
# ifdef HAVE_SSL
_httpTLSInitialize();
#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 */
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;
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;
}
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;
{
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 "
if (bytes < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
bytes = 0;
else
bytes = 0;
else
http->error = errno;
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
else if (bytes == 0)
{
...) /* 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 */
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
{
{
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
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));
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;
"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)
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) ||
* Unable to connect...
*/
-#ifdef WIN32
+#ifdef _WIN32
http->error = WSAGetLastError();
#else
http->error = errno;
-#endif /* WIN32 */
+#endif /* _WIN32 */
http->status = HTTP_STATUS_ERROR;
DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s",
if (_httpTLSStart(http) != 0)
{
httpAddrClose(NULL, http->fd);
+ http->fd = -1;
return (-1);
}
_httpTLSStop(http);
#endif /* HAVE_SSL */
-#ifdef WIN32
+#ifdef _WIN32
shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */
#else
shutdown(http->fd, SHUT_RD);
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
if (_httpTLSStart(http) != 0)
{
httpAddrClose(NULL, http->fd);
+ http->fd = -1;
*status = http->status = HTTP_STATUS_ERROR;
return (0);
httpSetCookie(http, value);
}
else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
+ {
http_add_field(http, field, value, 1);
+
+ if (field == HTTP_FIELD_AUTHENTICATION_INFO)
+ httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
+ }
#ifdef DEBUG
else
DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
}
-# ifdef WIN32
+# ifdef _WIN32
while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEWOULDBLOCK));
# else
while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
-# endif /* WIN32 */
+# endif /* _WIN32 */
#endif /* HAVE_POLL */
DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
}
#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);
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));
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;
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);
{
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)
{
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);
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 :
return;
}
- memset(&(http->stream), 0, sizeof(http->stream));
-
switch (coding)
{
case _HTTP_CODING_DEFLATE :
* 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 :
* -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 :
if (bytes < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
if (WSAGetLastError() != WSAEINTR)
{
http->error = WSAGetLastError();
http->error = errno;
return (-1);
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
}
while (bytes < 0);
if (bytes < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
if (WSAGetLastError() == WSAEINTR)
bytes = 0;
else
bytes = 0;
else
http->error = errno;
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
else if (bytes == 0)
{
http_set_timeout(int fd, /* I - File descriptor */
double timeout) /* I - Timeout in seconds */
{
-#ifdef WIN32
+#ifdef _WIN32
DWORD tv = (DWORD)(timeout * 1000);
/* Timeout in milliseconds */
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
}
-# ifdef WIN32
+# ifdef _WIN32
while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEWOULDBLOCK));
# else
while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
-# endif /* WIN32 */
+# endif /* _WIN32 */
#endif /* HAVE_POLL */
if (nfds < 0)
}
else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
{
-#ifdef WIN32
+#ifdef _WIN32
http->error = WSAEWOULDBLOCK;
#else
http->error = EWOULDBLOCK;
-#endif /* WIN32 */
+#endif /* _WIN32 */
return (-1);
}
}
if (bytes < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
if (WSAGetLastError() == WSAEINTR)
continue;
else if (WSAGetLastError() == WSAEWOULDBLOCK)
http->error = errno;
continue;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
DEBUG_printf(("3http_write: error writing data (%s).",
strerror(http->error)));