diff options
author | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2013-01-10 17:01:44 +0000 |
---|---|---|
committer | msweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be> | 2013-01-10 17:01:44 +0000 |
commit | 0fa6c7fa54164ee70ee9ccfa936b889a637d5ecd (patch) | |
tree | d84095ec3813ddd6d09ac71499ab00df3f9450f2 /cups | |
parent | c1420c8744235de1249c34b956b7c11ccafd659d (diff) |
Merge changes from CUPS 1.7svn-r10791.
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@4120 a1ca3aef-8c08-0410-bb20-df032aa958be
Diffstat (limited to 'cups')
-rw-r--r-- | cups/dest-options.c | 2 | ||||
-rw-r--r-- | cups/http-private.h | 28 | ||||
-rw-r--r-- | cups/http-support.c | 34 | ||||
-rw-r--r-- | cups/http.c | 833 | ||||
-rw-r--r-- | cups/http.h | 4 | ||||
-rw-r--r-- | cups/ipp-support.c | 20 | ||||
-rw-r--r-- | cups/ipp.c | 8 | ||||
-rw-r--r-- | cups/request.c | 19 | ||||
-rw-r--r-- | cups/versioning.h | 85 |
9 files changed, 575 insertions, 458 deletions
diff --git a/cups/dest-options.c b/cups/dest-options.c index d8eff72e5..8477ab30a 100644 --- a/cups/dest-options.c +++ b/cups/dest-options.c @@ -485,7 +485,7 @@ cupsCopyDestConflicts( active = NULL; } - if (tries >= 0) + if (tries >= 100) { DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve after 100 tries."); have_conflicts = -1; diff --git a/cups/http-private.h b/cups/http-private.h index a789917de..9259b1f4a 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -3,7 +3,7 @@ * * Private HTTP definitions for CUPS. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -44,29 +44,14 @@ # ifdef HAVE_GSSAPI # ifdef HAVE_GSS_GSSAPI_H # include <GSS/gssapi.h> -# ifdef HAVE_GSSAPI_GENERIC_H -# include <GSS/gssapi_generic.h> -# endif /* HAVE_GSSAPI_GENERIC_H */ -# ifdef HAVE_GSSAPI_KRB5_H -# include <GSS/gssapi_krb5.h> -# endif /* HAVE_GSSAPI_KRB5_H */ # elif defined(HAVE_GSSAPI_GSSAPI_H) # include <gssapi/gssapi.h> -# ifdef HAVE_GSSAPI_GENERIC_H -# include <gssapi/gssapi_generic.h> -# endif /* HAVE_GSSAPI_GENERIC_H */ -# ifdef HAVE_GSSAPI_KRB5_H -# include <gssapi/gssapi_krb5.h> -# endif /* HAVE_GSSAPI_KRB5_H */ # elif defined(HAVE_GSSAPI_H) # include <gssapi.h> # endif /* HAVE_GSS_GSSAPI_H */ # ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE # define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name # endif /* !HAVE_GSS_C_NT_HOSTBASED_SERVICE */ -# ifdef HAVE_KRB5_H -# include <krb5.h> -# endif /* HAVE_KRB5_H */ # endif /* HAVE_GSSAPI */ # ifdef HAVE_AUTHORIZATION_H @@ -341,6 +326,7 @@ struct _http_s /**** HTTP connection structure ****/ # ifdef HAVE_LIBZ _http_coding_t coding; /* _HTTP_CODING_xxx */ z_stream stream; /* (De)compression stream */ + Bytef *dbuffer; /* Decompression buffer */ # endif /* HAVE_LIBZ */ }; @@ -407,14 +393,18 @@ extern void _cups_freeifaddrs(struct ifaddrs *addrs); */ #define _httpAddrFamily(addrp) (addrp)->addr.sa_family +extern int _httpAddrPort(http_addr_t *addr) + _CUPS_INTERNAL_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, - char *buffer, size_t bufsize); + char *buffer, size_t bufsize) + _CUPS_INTERNAL_MSG("Use httpAssembleUUID instead."); extern http_t *_httpCreate(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, - int blocking, _http_mode_t mode); + int blocking, _http_mode_t mode) + _CUPS_INTERNAL_MSG("Use httpConnect2 or httpAccept instead."); extern http_tls_credentials_t _httpCreateCredentials(cups_array_t *credentials); extern char *_httpDecodeURI(char *dst, const char *src, @@ -423,6 +413,8 @@ extern void _httpDisconnect(http_t *http); 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_INTERNAL_MSG("Use httpPeek instead."); extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), diff --git a/cups/http-support.c b/cups/http-support.c index d0f36c3e1..cd1565ded 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -3,7 +3,7 @@ * * HTTP support routines for CUPS. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -20,7 +20,8 @@ * components. * httpAssembleURIf() - Assemble a uniform resource identifier from its * components with a formatted resource. - * _httpAssembleUUID() - Make a UUID URI conforming to RFC 4122. + * httpAssembleUUID() - Assemble a name-based UUID URN conforming to RFC + * 4122. * httpDecode64() - Base64-decode a string. * httpDecode64_2() - Base64-decode a string. * httpEncode64() - Base64-encode a string. @@ -466,18 +467,22 @@ httpAssembleURIf( /* - * '_httpAssembleUUID()' - Make a UUID URI conforming to RFC 4122. + * 'httpAssembleUUID()' - Assemble a name-based UUID URN conforming to RFC 4122. + * + * This function creates a unique 128-bit identifying number using the server + * name, port number, random data, and optionally an object name and/or object + * number. The result is formatted as a UUID URN as defined in RFC 4122. * * The buffer needs to be at least 46 bytes in size. */ char * /* I - UUID string */ -_httpAssembleUUID(const char *server, /* I - Server name */ - int port, /* I - Port number */ - const char *name, /* I - Object name or NULL */ - int number, /* I - Object number or 0 */ - char *buffer, /* I - String buffer */ - size_t bufsize) /* I - Size of buffer */ +httpAssembleUUID(const char *server, /* I - Server name */ + int port, /* I - Port number */ + const char *name, /* I - Object name or NULL */ + int number, /* I - Object number or 0 */ + char *buffer, /* I - String buffer */ + size_t bufsize) /* I - Size of buffer */ { char data[1024]; /* Source string for MD5 */ _cups_md5_state_t md5state; /* MD5 state */ @@ -514,6 +519,13 @@ _httpAssembleUUID(const char *server, /* I - Server name */ return (buffer); } +/* For OS X 10.8 and earlier */ +char *_httpAssembleUUID(const char *server, int port, const char *name, + int number, char *buffer, size_t bufsize) +{ + return (httpAssembleUUID(server, port, name, number, buffer, bufsize)); +} + /* * 'httpDecode64()' - Base64-decode a string. @@ -2064,6 +2076,8 @@ http_resolve_cb( error)); #endif /* DEBUG */ } + + httpAddrFreeList(addrlist); } } @@ -2279,6 +2293,8 @@ http_resolve_cb( error)); #endif /* DEBUG */ } + + httpAddrFreeList(addrlist); } } diff --git a/cups/http.c b/cups/http.c index 12e7338ad..35b2799dd 100644 --- a/cups/http.c +++ b/cups/http.c @@ -48,13 +48,13 @@ * _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. + * 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. * httpGetCookie() - Get any cookie data from the response. - * httpGetExpect() - Get the value of the Expect header, if any. + * httpGetExpect() - Get the value of the Expect header, if any. * httpGetFd() - Get the file descriptor associated with a * connection. * httpGetField() - Get a field value from a request/response. @@ -89,6 +89,7 @@ * httpSetCredentials() - Set the credentials associated with an * encrypted connection. * httpSetCookie() - Set the cookie value(s). + * httpSetDefaultField() - Set the default value of an HTTP header. * httpSetExpect() - Set the Expect: header in a request. * httpSetField() - Set the value of an HTTP header. * httpSetLength() - Set the content-length and @@ -119,12 +120,15 @@ * http_content_coding_start() - Start doing content encoding. * http_debug_hex() - Do a hex dump of a buffer. * http_field() - Return the field index for a field name. + * http_read() - Read a buffer from a HTTP connection. + * http_read_buffered() - Do a buffered read from a HTTP connection. + * http_read_chunk() - Read a chunk from a HTTP connection. * http_read_ssl() - Read from a SSL/TLS connection. * http_send() - Send a request with all fields and the * trailing blank line. * http_set_credentials() - Set the SSL/TLS credentials. - * http_set_length() - Set the data_encoding and data_remaining - * values. + * http_set_length() - Set the data_encoding and data_remaining + * values. * http_set_timeout() - Set the socket timeout values. * http_set_wait() - Set the default wait value for reads. * http_setup_ssl() - Set up SSL/TLS support on a connection. @@ -168,12 +172,15 @@ static void http_debug_hex(const char *prefix, const char *buffer, int bytes); #endif /* DEBUG */ static http_field_t http_field(const char *name); +static ssize_t http_read(http_t *http, char *buffer, size_t length); +static ssize_t http_read_buffered(http_t *http, char *buffer, size_t length); +static ssize_t http_read_chunk(http_t *http, char *buffer, size_t length); static int http_send(http_t *http, http_state_t request, const char *uri); -static int http_write(http_t *http, const char *buffer, - int length); -static int http_write_chunk(http_t *http, const char *buffer, - int length); +static ssize_t http_write(http_t *http, const char *buffer, + size_t length); +static ssize_t http_write_chunk(http_t *http, const char *buffer, + size_t length); #ifdef HAVE_SSL static int http_read_ssl(http_t *http, char *buf, int len); # ifdef HAVE_CDSASSL @@ -1449,7 +1456,7 @@ httpGets(char *line, /* I - Line to read into */ DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", line, length, http)); - if (http == NULL || line == NULL) + if (!http || !line || length <= 1) return (NULL); /* @@ -1493,20 +1500,10 @@ httpGets(char *line, /* I - Line to read into */ return (NULL); } -#ifdef HAVE_SSL - if (http->tls) - bytes = http_read_ssl(http, http->buffer + http->used, - HTTP_MAX_BUFFER - http->used); - else -#endif /* HAVE_SSL */ - bytes = recv(http->fd, http->buffer + http->used, - HTTP_MAX_BUFFER - http->used, 0); + bytes = http_read(http, http->buffer + http->used, + HTTP_MAX_BUFFER - http->used); - DEBUG_printf(("4httpGets: read %d bytes...", bytes)); - -#ifdef DEBUG - http_debug_hex("httpGets", http->buffer + http->used, bytes); -#endif /* DEBUG */ + DEBUG_printf(("4httpGets: read %d bytes.", bytes)); if (bytes < 0) { @@ -1918,8 +1915,8 @@ httpOptions(http_t *http, /* I - Connection to server */ ssize_t /* O - Number of bytes copied */ httpPeek(http_t *http, /* I - Connection to server */ - char *buffer, /* I - Buffer for data */ - size_t length) /* I - Maximum number of bytes */ + char *buffer, /* I - Buffer for data */ + size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ char len[32]; /* Length string */ @@ -1959,21 +1956,21 @@ httpPeek(http_t *http, /* I - Connection to server */ DEBUG_printf(("2httpPeek: data_remaining=" CUPS_LLFMT, CUPS_LLCAST http->data_remaining)); - if (http->data_remaining <= 0) + if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS) { /* * A zero-length chunk ends a transfer; unless we are reading POST * data, go idle... */ - if (http->data_encoding == HTTP_ENCODING_CHUNKED) - httpGets(len, sizeof(len), http); - #ifdef HAVE_LIBZ if (http->coding) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ + if (http->data_encoding == HTTP_ENCODING_CHUNKED) + httpGets(len, sizeof(len), http); + if (http->state == HTTP_STATE_POST_RECV) http->state ++; else @@ -1990,12 +1987,15 @@ httpPeek(http_t *http, /* I - Connection to server */ return (0); } - else if ((http->data_encoding == HTTP_ENCODING_LENGTH || - http->coding == _HTTP_CODING_IDENTITY) && - length > (size_t)http->data_remaining) + else if (length > (size_t)http->data_remaining) length = (size_t)http->data_remaining; +#ifdef HAVE_LIBZ + if (http->used == 0 && + (http->coding == _HTTP_CODING_IDENTITY || http->stream.avail_in == 0)) +#else if (http->used == 0) +#endif /* HAVE_LIBZ */ { /* * Buffer small reads for better performance... @@ -2084,16 +2084,39 @@ httpPeek(http_t *http, /* I - Connection to server */ if (http->coding) { int zerr; /* Decompressor error */ - off_t comp_avail; /* Maximum bytes for decompression */ z_stream stream; /* Copy of decompressor stream */ - if (http->used > http->data_remaining) - comp_avail = http->data_remaining; - else - comp_avail = http->used; + if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER) + { + size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in; + /* Number of bytes to copy */ + + if (http->stream.avail_in > 0 && + http->stream.next_in > http->dbuffer) + memmove(http->dbuffer, http->stream.next_in, http->stream.avail_in); + + http->stream.next_in = http->dbuffer; + + if (buflen > http->data_remaining) + buflen = http->data_remaining; + + if (buflen > http->used) + buflen = http->used; + + DEBUG_printf(("1httpPeek: Copying %d more bytes of data into " + "decompression buffer.", (int)buflen)); + + memcpy(http->dbuffer + http->stream.avail_in, http->buffer, buflen); + http->stream.avail_in += buflen; + http->used -= buflen; + http->data_remaining -= buflen; + + if (http->used > 0) + memmove(http->buffer, http->buffer + buflen, http->used); + } DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length, - (int)comp_avail)); + (int)http->stream.avail_in)); if (inflateCopy(&stream, &(http->stream)) != Z_OK) { @@ -2102,8 +2125,6 @@ httpPeek(http_t *http, /* I - Connection to server */ return (-1); } - stream.next_in = (Bytef *)http->buffer; - stream.avail_in = comp_avail; stream.next_out = (Bytef *)buffer; stream.avail_out = length; @@ -2113,6 +2134,11 @@ httpPeek(http_t *http, /* I - Connection to server */ if (zerr < Z_OK) { DEBUG_printf(("2httpPeek: zerr=%d", zerr)); +#ifdef DEBUG + http_debug_hex("2httpPeek", (char *)http->dbuffer, + http->stream.avail_in); +#endif /* DEBUG */ + http->error = EIO; return (-1); } @@ -2264,12 +2290,12 @@ httpRead2(http_t *http, /* I - Connection to server */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ - char len[32]; /* Length string */ DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT - ") coding=%d", http, buffer, CUPS_LLCAST length, - http->coding)); + ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, + http, buffer, CUPS_LLCAST length, http->coding, + http->data_encoding, CUPS_LLCAST http->data_remaining)); if (http == NULL || buffer == NULL) return (-1); @@ -2280,371 +2306,135 @@ httpRead2(http_t *http, /* I - Connection to server */ if (length <= 0) return (0); - if (http->data_encoding == HTTP_ENCODING_CHUNKED && - http->data_remaining <= 0) - { - if (!httpGets(len, sizeof(len), http)) - { - DEBUG_puts("1httpRead2: Could not get chunk length."); - return (0); - } - - if (!len[0]) - { - DEBUG_puts("1httpRead2: Blank chunk length, trying again..."); - if (!httpGets(len, sizeof(len), http)) - { - DEBUG_puts("1httpRead2: Could not get chunk length."); - return (0); - } - } - - http->data_remaining = strtoll(len, NULL, 16); - - if (http->data_remaining < 0) - { - DEBUG_printf(("1httpRead2: Negative chunk length \"%s\" (" CUPS_LLFMT ")", - len, CUPS_LLCAST http->data_remaining)); - return (0); - } - - DEBUG_printf(("2httpRead2: Got chunk length \"%s\" (" CUPS_LLFMT ")", len, - CUPS_LLCAST http->data_remaining)); - } - - DEBUG_printf(("2httpRead2: data_remaining=" CUPS_LLFMT ", used=%d", - CUPS_LLCAST http->data_remaining, http->used)); - - if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS) - { - /* - * A zero-length chunk ends a transfer; unless we are reading POST - * data, go idle... - */ - #ifdef HAVE_LIBZ - if (http->coding) - http_content_coding_finish(http); -#endif /* HAVE_LIBZ */ - - if (http->data_encoding == HTTP_ENCODING_CHUNKED) - httpGets(len, sizeof(len), http); - - if (http->state == HTTP_STATE_POST_RECV) - http->state ++; - else - http->state = HTTP_STATE_WAITING; - - DEBUG_printf(("1httpRead2: 0-length chunk, set state to %s.", - http_states[http->state + 1])); - - /* - * Prevent future reads for this request... - */ - - http->data_encoding = HTTP_ENCODING_FIELDS; - - return (0); - } - else if ((http->data_encoding == HTTP_ENCODING_LENGTH || - http->coding == _HTTP_CODING_IDENTITY) && - length > (size_t)http->data_remaining) - length = (size_t)http->data_remaining; - -#ifdef HAVE_LIBZ - if (http->used == 0 && (length <= 256 || http->coding)) -#else - if (http->used == 0 && length <= 256) -#endif /* HAVE_LIBZ */ + if (http->coding) { - /* - * Buffer small/compressed reads for better performance... - */ - - ssize_t buflen; /* Length of read for buffer */ - - if (!http->blocking) + do { - while (!httpWait(http, http->wait_value)) + if (http->stream.avail_in > 0) { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; + int zerr; /* Decompressor error */ - return (0); - } - } + DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d", + (int)http->stream.avail_in, (int)length)); - if (http->data_remaining > sizeof(http->buffer)) - buflen = sizeof(http->buffer); - else - buflen = http->data_remaining; - - DEBUG_printf(("2httpRead2: Reading %d bytes into buffer.", (int)buflen)); + http->stream.next_out = (Bytef *)buffer; + http->stream.avail_out = length; - do - { -#ifdef HAVE_SSL - if (http->tls) - bytes = http_read_ssl(http, http->buffer, buflen); - else -#endif /* HAVE_SSL */ - bytes = recv(http->fd, http->buffer, buflen, 0); - - if (bytes < 0) - { -#ifdef WIN32 - if (WSAGetLastError() != WSAEINTR) - { - http->error = WSAGetLastError(); - return (-1); - } - else if (WSAGetLastError() == WSAEWOULDBLOCK) + if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) { - if (!http->timeout_cb || - !(*http->timeout_cb)(http, http->timeout_data)) - { - http->error = WSAEWOULDBLOCK; - return (-1); - } - } -#else - if (errno == EWOULDBLOCK || errno == EAGAIN) - { - if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) - { - http->error = errno; - return (-1); - } - else if (!http->timeout_cb && errno != EAGAIN) - { - http->error = errno; - return (-1); - } - } - else if (errno != EINTR) - { - http->error = errno; - return (-1); - } -#endif /* WIN32 */ - } - } - while (bytes < 0); - - DEBUG_printf(("2httpRead2: Read " CUPS_LLFMT " bytes into buffer.", - CUPS_LLCAST bytes)); + DEBUG_printf(("2httpRead2: zerr=%d", zerr)); #ifdef DEBUG - http_debug_hex("httpRead2", http->buffer, (int)bytes); + http_debug_hex("2httpRead2", (char *)http->dbuffer, + http->stream.avail_in); #endif /* DEBUG */ - http->used = bytes; - } - -#ifdef HAVE_LIBZ - if (http->coding) - { - int zerr; /* Decompressor error */ - off_t comp_avail, /* Maximum bytes for decompression */ - comp_bytes; /* Compressed bytes "used" */ - - if (http->used > http->data_remaining) - comp_avail = http->data_remaining; - else - comp_avail = http->used; - - DEBUG_printf(("2httpRead2: length=%d, avail_in=%d", (int)length, - (int)comp_avail)); + http->error = EIO; + return (-1); + } - http->stream.next_in = (Bytef *)http->buffer; - http->stream.avail_in = comp_avail; - http->stream.next_out = (Bytef *)buffer; - http->stream.avail_out = length; + bytes = length - http->stream.avail_out; - if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) - { - DEBUG_printf(("2httpRead2: zerr=%d", zerr)); - http->error = EIO; - return (-1); - } - - bytes = length - http->stream.avail_out; - comp_bytes = comp_avail - http->stream.avail_in; + DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", + http->stream.avail_in, http->stream.avail_out, + (int)bytes)); + } + else + bytes = 0; - DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d, " - "comp_bytes=%d", http->stream.avail_in, - http->stream.avail_out, (int)bytes, (int)comp_bytes)); + if (bytes == 0) + { + ssize_t buflen = HTTP_MAX_BUFFER - http->stream.avail_in; + /* Additional bytes for buffer */ - if ((http->used - comp_bytes) > 0) - { - http->used -= comp_bytes; - memmove(http->buffer, http->stream.next_in, http->used); + if (buflen > 0) + { + if (http->stream.avail_in > 0 && + http->stream.next_in > http->dbuffer) + memmove(http->dbuffer, http->stream.next_in, http->stream.avail_in); + + http->stream.next_in = http->dbuffer; + + DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into " + "decompression buffer.", (int)buflen)); + + if (http->data_remaining > 0) + { + if (buflen > http->data_remaining) + buflen = http->data_remaining; + + bytes = http_read_buffered(http, + (char *)http->dbuffer + + http->stream.avail_in, buflen); + } + else if (http->data_encoding == HTTP_ENCODING_CHUNKED) + bytes = http_read_chunk(http, + (char *)http->dbuffer + + http->stream.avail_in, buflen); + else + bytes = 0; + + if (bytes < 0) + return (bytes); + else if (bytes == 0) + break; + + http->data_remaining -= bytes; + http->stream.avail_in += bytes; + } + else + return (0); + } } - else - http->used = 0; - - /* - * Adjust remaining bytes since chunk/content lengths are compressed while - * CUPS HTTP APIs return uncompressed sizes... - */ - - http->data_remaining += bytes - comp_bytes; + while (bytes == 0); } else #endif /* HAVE_LIBZ */ - if (http->used > 0) + if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { - if (length > (size_t)http->used) - length = (size_t)http->used; - - bytes = (ssize_t)length; - - DEBUG_printf(("2httpRead2: grabbing %d bytes from input buffer...", - (int)bytes)); - - memcpy(buffer, http->buffer, length); - http->used -= (int)length; - - if (http->used > 0) - memmove(http->buffer, http->buffer + length, http->used); + if ((bytes = http_read_chunk(http, buffer, length)) > 0) + http->data_remaining -= bytes; } -#ifdef HAVE_SSL - else if (http->tls) + else if (http->data_remaining <= 0) { - if (!http->blocking) - { - while (!httpWait(http, http->wait_value)) - { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; - - return (0); - } - } + /* + * No more data to read... + */ - while ((bytes = (ssize_t)http_read_ssl(http, buffer, (int)length)) < 0) - { -#ifdef WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) - { - if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) - break; - } - else if (WSAGetLastError() != WSAEINTR) - break; -#else - if (errno == EWOULDBLOCK || errno == EAGAIN) - { - if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) - break; - else if (!http->timeout_cb && errno != EAGAIN) - break; - } - else if (errno != EINTR) - break; -#endif /* WIN32 */ - } + return (0); } -#endif /* HAVE_SSL */ else { - if (!http->blocking) - { - while (!httpWait(http, http->wait_value)) - { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; - - return (0); - } - } - - DEBUG_printf(("2httpRead2: reading " CUPS_LLFMT " bytes from socket...", - CUPS_LLCAST length)); - -#ifdef WIN32 - while ((bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0)) < 0) - { - if (WSAGetLastError() == WSAEWOULDBLOCK) - { - if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)) - break; - } - else if (WSAGetLastError() != WSAEINTR) - break; - } -#else - while ((bytes = recv(http->fd, buffer, length, 0)) < 0) - { - if (errno == EWOULDBLOCK || errno == EAGAIN) - { - if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) - break; - else if (!http->timeout_cb && errno != EAGAIN) - break; - } - else if (errno != EINTR) - break; - } -#endif /* WIN32 */ - - DEBUG_printf(("2httpRead2: read " CUPS_LLFMT " bytes from socket...", - CUPS_LLCAST bytes)); -#ifdef DEBUG - http_debug_hex("httpRead2", buffer, (int)bytes); -#endif /* DEBUG */ - } + DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.", + (int)length)); - if (bytes > 0) - { - http->data_remaining -= bytes; + if (length > http->data_remaining) + length = http->data_remaining; - if (http->data_remaining <= INT_MAX) - http->_data_remaining = (int)http->data_remaining; - else - http->_data_remaining = INT_MAX; - } - else if (bytes < 0) - { -#ifdef WIN32 - if (WSAGetLastError() == WSAEINTR) - bytes = 0; - else - http->error = WSAGetLastError(); -#else - if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb)) - bytes = 0; - else - http->error = errno; -#endif /* WIN32 */ - } - else - { - http->error = EPIPE; - return (0); + if ((bytes = http_read_buffered(http, buffer, length)) > 0) + http->data_remaining -= bytes; } - if (http->data_remaining <= 0) + if ( +#ifdef HAVE_LIBZ + (http->coding == _HTTP_CODING_IDENTITY || http->stream.avail_in == 0) && +#endif /* HAVE_LIBZ */ + ((http->data_remaining <= 0 && + http->data_encoding == HTTP_ENCODING_LENGTH) || + (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0))) { - if (http->data_encoding == HTTP_ENCODING_CHUNKED) - { - DEBUG_puts("1httpRead2: Reading trailing line for chunk."); - httpGets(len, sizeof(len), http); - } - else - { #ifdef HAVE_LIBZ - if (http->coding) - http_content_coding_finish(http); + if (http->coding) + http_content_coding_finish(http); #endif /* HAVE_LIBZ */ - if (http->state == HTTP_STATE_POST_RECV) - http->state ++; - else - http->state = HTTP_STATE_WAITING; + if (http->state == HTTP_STATE_POST_RECV) + http->state ++; + else + http->state = HTTP_STATE_WAITING; - DEBUG_printf(("1httpRead2: End of content, set state to %s.", - http_states[http->state + 1])); - } + DEBUG_printf(("1httpRead2: End of content, set state to %s.", + http_states[http->state + 1])); } return (bytes); @@ -3809,6 +3599,14 @@ httpWait(http_t *http, /* I - Connection to server */ return (1); } +#ifdef HAVE_LIBZ + if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0) + { + DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); + return (1); + } +#endif /* HAVE_LIBZ */ + /* * Flush pending data, if any... */ @@ -4475,6 +4273,8 @@ http_content_coding_finish( case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : inflateEnd(&(http->stream)); + free(http->dbuffer); + http->dbuffer = NULL; break; default : @@ -4563,12 +4363,26 @@ http_content_coding_start( case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : - if ((zerr = inflateInit2(&(http->stream), 32 + 15)) < Z_OK) + if ((http->dbuffer = malloc(HTTP_MAX_BUFFER)) == NULL) { http->status = HTTP_ERROR; - http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; + http->error = errno; return; } + + if ((zerr = inflateInit2(&(http->stream), + coding == _HTTP_CODING_INFLATE ? 15 : 31)) + < Z_OK) + { + free(http->dbuffer); + http->dbuffer = NULL; + http->status = HTTP_ERROR; + http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; + return; + } + + http->stream.avail_in = 0; + http->stream.next_in = http->dbuffer; break; default : @@ -4658,6 +4472,231 @@ http_field(const char *name) /* I - String name */ } +/* + * 'http_read()' - Read a buffer from a HTTP connection. + * + * This function does the low-level read from the socket, retrying and timing + * out as needed. + */ + +static ssize_t /* O - Number of bytes read or -1 on error */ +http_read(http_t *http, /* I - Connection to server */ + char *buffer, /* I - Buffer */ + size_t length) /* I - Maximum bytes to read */ +{ + ssize_t bytes; /* Bytes read */ + + + DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http, + buffer, CUPS_LLCAST length)); + + if (!http->blocking) + { + while (!httpWait(http, http->wait_value)) + { + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) + continue; + + DEBUG_puts("2http_read: Timeout."); + return (0); + } + } + + DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length)); + + do + { +#ifdef HAVE_SSL + if (http->tls) + bytes = http_read_ssl(http, buffer, length); + else +#endif /* HAVE_SSL */ + bytes = recv(http->fd, buffer, length, 0); + + if (bytes < 0) + { +#ifdef WIN32 + if (WSAGetLastError() != WSAEINTR) + { + http->error = WSAGetLastError(); + return (-1); + } + else if (WSAGetLastError() == WSAEWOULDBLOCK) + { + if (!http->timeout_cb || + !(*http->timeout_cb)(http, http->timeout_data)) + { + http->error = WSAEWOULDBLOCK; + return (-1); + } + } +#else + DEBUG_printf(("2http_read: %s", strerror(errno))); + + if (errno == EWOULDBLOCK || errno == EAGAIN) + { + if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data)) + { + http->error = errno; + return (-1); + } + else if (!http->timeout_cb && errno != EAGAIN) + { + http->error = errno; + return (-1); + } + } + else if (errno != EINTR) + { + http->error = errno; + return (-1); + } +#endif /* WIN32 */ + } + } + while (bytes < 0); + + DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.", + CUPS_LLCAST bytes)); +#ifdef DEBUG + if (bytes > 0) + http_debug_hex("http_read", http->buffer, (int)bytes); +#endif /* DEBUG */ + + if (bytes < 0) + { +#ifdef WIN32 + if (WSAGetLastError() == WSAEINTR) + bytes = 0; + else + http->error = WSAGetLastError(); +#else + if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb)) + bytes = 0; + else + http->error = errno; +#endif /* WIN32 */ + } + else if (bytes == 0) + { + http->error = EPIPE; + return (0); + } + + return (bytes); +} + + +/* + * 'http_read_buffered()' - Do a buffered read from a HTTP connection. + * + * This function reads data from the HTTP buffer or from the socket, as needed. + */ + +static ssize_t /* O - Number of bytes read or -1 on error */ +http_read_buffered(http_t *http, /* I - Connection to server */ + char *buffer, /* I - Buffer */ + size_t length) /* I - Maximum bytes to read */ +{ + ssize_t bytes; /* Bytes read */ + + + DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT + ") used=%d", + http, buffer, CUPS_LLCAST length, http->used)); + + if (http->used > 0) + { + if (length > (size_t)http->used) + bytes = (size_t)http->used; + else + bytes = length; + + DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.", + (int)bytes)); + + memcpy(buffer, http->buffer, bytes); + http->used -= (int)bytes; + + if (http->used > 0) + memmove(http->buffer, http->buffer + bytes, http->used); + } + else + bytes = http_read(http, buffer, length); + + return (bytes); +} + + +/* + * 'http_read_chunk()' - Read a chunk from a HTTP connection. + * + * This function reads and validates the chunk length, then does a buffered read + * returning the number of bytes placed in the buffer. + */ + +static ssize_t /* O - Number of bytes read or -1 on error */ +http_read_chunk(http_t *http, /* I - Connection to server */ + char *buffer, /* I - Buffer */ + size_t length) /* I - Maximum bytes to read */ +{ + DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", + http, buffer, CUPS_LLCAST length)); + + if (http->data_remaining <= 0) + { + char len[32]; /* Length string */ + + if (!httpGets(len, sizeof(len), http)) + { + DEBUG_puts("1http_read_chunk: Could not get chunk length."); + return (0); + } + + if (!len[0]) + { + DEBUG_puts("1http_read_chunk: Blank chunk length, trying again..."); + if (!httpGets(len, sizeof(len), http)) + { + DEBUG_puts("1http_read_chunk: Could not get chunk length."); + return (0); + } + } + + http->data_remaining = strtoll(len, NULL, 16); + + if (http->data_remaining < 0) + { + DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" (" + CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining)); + return (0); + } + + DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")", + len, CUPS_LLCAST http->data_remaining)); + + if (http->data_remaining == 0) + { + /* + * 0-length chunk, grab trailing blank line... + */ + + httpGets(len, sizeof(len), http); + } + } + + DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT, + CUPS_LLCAST http->data_remaining)); + + if (http->data_remaining <= 0) + return (0); + else if (length > (size_t)http->data_remaining) + length = (size_t)http->data_remaining; + + return (http_read_buffered(http, buffer, length)); +} + + #ifdef HAVE_SSL /* * 'http_read_ssl()' - Read from a SSL/TLS connection. @@ -5124,8 +5163,6 @@ http_set_wait(http_t *http) /* I - Connection to server */ static int /* O - 0 on success, -1 on failure */ http_setup_ssl(http_t *http) /* I - Connection to server */ { - _cups_globals_t *cg = _cupsGlobals(); - /* Pointer to library globals */ char hostname[256], /* Hostname */ *hostptr; /* Pointer into hostname */ @@ -5138,6 +5175,8 @@ http_setup_ssl(http_t *http) /* I - Connection to server */ gnutls_certificate_client_credentials *credentials; /* TLS credentials */ # elif defined(HAVE_CDSASSL) + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ OSStatus error; /* Error code */ const char *message = NULL;/* Error message */ cups_array_t *credentials; /* Credentials array */ @@ -5667,17 +5706,17 @@ http_upgrade(http_t *http) /* I - Connection to server */ * 'http_write()' - Write a buffer to a HTTP connection. */ -static int /* O - Number of bytes written */ +static ssize_t /* O - Number of bytes written */ http_write(http_t *http, /* I - Connection to server */ const char *buffer, /* I - Buffer for data */ - int length) /* I - Number of bytes to write */ + size_t length) /* I - Number of bytes to write */ { - int tbytes, /* Total bytes sent */ - bytes; /* Bytes sent */ + ssize_t tbytes, /* Total bytes sent */ + bytes; /* Bytes sent */ - DEBUG_printf(("2http_write(http=%p, buffer=%p, length=%d)", http, buffer, - length)); + DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http, + buffer, CUPS_LLCAST length)); http->error = 0; tbytes = 0; @@ -5749,8 +5788,8 @@ http_write(http_t *http, /* I - Connection to server */ #endif /* HAVE_SSL */ bytes = send(http->fd, buffer, length, 0); - DEBUG_printf(("3http_write: Write of %d bytes returned %d.", (int)length, - (int)bytes)); + DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned " + CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes)); if (bytes < 0) { @@ -5805,7 +5844,7 @@ http_write(http_t *http, /* I - Connection to server */ http_debug_hex("http_write", buffer - tbytes, tbytes); #endif /* DEBUG */ - DEBUG_printf(("3http_write: Returning %d.", tbytes)); + DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes)); return (tbytes); } @@ -5815,38 +5854,38 @@ http_write(http_t *http, /* I - Connection to server */ * 'http_write_chunk()' - Write a chunked buffer. */ -static int /* O - Number bytes written */ +static ssize_t /* O - Number bytes written */ http_write_chunk(http_t *http, /* I - Connection to server */ const char *buffer, /* I - Buffer to write */ - int length) /* I - Length of buffer */ + size_t length) /* I - Length of buffer */ { - char header[255]; /* Chunk header */ - int bytes; /* Bytes written */ + char header[16]; /* Chunk header */ + ssize_t bytes; /* Bytes written */ - DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=%d)", - http, buffer, length)); + DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", + http, buffer, CUPS_LLCAST length)); /* * Write the chunk header, data, and trailer. */ - sprintf(header, "%x\r\n", length); - if (http_write(http, header, (int)strlen(header)) < 0) + snprintf(header, sizeof(header), "%x\r\n", (unsigned)length); + if (http_write(http, header, strlen(header)) < 0) { - DEBUG_puts("8http_write_chunk: http_write of length failed!"); + DEBUG_puts("8http_write_chunk: http_write of length failed."); return (-1); } if ((bytes = http_write(http, buffer, length)) < 0) { - DEBUG_puts("8http_write_chunk: http_write of buffer failed!"); + DEBUG_puts("8http_write_chunk: http_write of buffer failed."); return (-1); } if (http_write(http, "\r\n", 2) < 0) { - DEBUG_puts("8http_write_chunk: http_write of CR LF failed!"); + DEBUG_puts("8http_write_chunk: http_write of CR LF failed."); return (-1); } diff --git a/cups/http.h b/cups/http.h index de782aaa3..345bf27f9 100644 --- a/cups/http.h +++ b/cups/http.h @@ -591,6 +591,10 @@ extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7; extern int httpAddrListen(http_addr_t *addr, int port) _CUPS_API_1_7; extern int httpAddrPort(http_addr_t *addr) _CUPS_API_1_7; +extern char *httpAssembleUUID(const char *server, int port, + const char *name, int number, + char *buffer, size_t bufsize) + _CUPS_API_1_7; extern http_t *httpConnect2(const char *host, int port, http_addrlist_t *addrlist, int family, http_encryption_t encryption, diff --git a/cups/ipp-support.c b/cups/ipp-support.c index dfe610352..28abbba00 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -777,8 +777,8 @@ ippEnumString(const char *attrname, /* I - Attribute name */ if (!strcmp(attrname, "document-state") && enumvalue >= 3 && - enumvalue <= (3 + (int)(sizeof(ipp_document_states) / - sizeof(ipp_document_states[0])))) + enumvalue < (3 + (int)(sizeof(ipp_document_states) / + sizeof(ipp_document_states[0])))) return (ipp_document_states[enumvalue - 3]); else if (!strcmp(attrname, "finishings") || !strcmp(attrname, "finishings-actual") || @@ -787,8 +787,8 @@ ippEnumString(const char *attrname, /* I - Attribute name */ !strcmp(attrname, "finishings-supported")) { if (enumvalue >= 3 && - enumvalue <= (3 + (int)(sizeof(ipp_finishings) / - sizeof(ipp_finishings[0])))) + enumvalue < (3 + (int)(sizeof(ipp_finishings) / + sizeof(ipp_finishings[0])))) return (ipp_finishings[enumvalue - 3]); else if (enumvalue >= 0x40000000 && enumvalue <= (0x40000000 + (int)(sizeof(ipp_finishings_vendor) / @@ -798,8 +798,8 @@ ippEnumString(const char *attrname, /* I - Attribute name */ else if ((!strcmp(attrname, "job-collation-type") || !strcmp(attrname, "job-collation-type-actual")) && enumvalue >= 3 && - enumvalue <= (3 + (int)(sizeof(ipp_job_collation_types) / - sizeof(ipp_job_collation_types[0])))) + enumvalue < (3 + (int)(sizeof(ipp_job_collation_types) / + sizeof(ipp_job_collation_types[0])))) return (ipp_job_collation_types[enumvalue - 3]); else if (!strcmp(attrname, "job-state") && enumvalue >= IPP_JOB_PENDING && enumvalue <= IPP_JOB_COMPLETED) @@ -811,16 +811,16 @@ ippEnumString(const char *attrname, /* I - Attribute name */ !strcmp(attrname, "orientation-requested-default") || !strcmp(attrname, "orientation-requested-supported")) && enumvalue >= 3 && - enumvalue <= (3 + (int)(sizeof(ipp_orientation_requesteds) / - sizeof(ipp_orientation_requesteds[0])))) + enumvalue < (3 + (int)(sizeof(ipp_orientation_requesteds) / + sizeof(ipp_orientation_requesteds[0])))) return (ipp_orientation_requesteds[enumvalue - 3]); else if ((!strcmp(attrname, "print-quality") || !strcmp(attrname, "print-quality-actual") || !strcmp(attrname, "print-quality-default") || !strcmp(attrname, "print-quality-supported")) && enumvalue >= 3 && - enumvalue <= (3 + (int)(sizeof(ipp_print_qualities) / - sizeof(ipp_print_qualities[0])))) + enumvalue < (3 + (int)(sizeof(ipp_print_qualities) / + sizeof(ipp_print_qualities[0])))) return (ipp_print_qualities[enumvalue - 3]); else if (!strcmp(attrname, "printer-state") && enumvalue >= IPP_PRINTER_IDLE && enumvalue <= IPP_PRINTER_STOPPED) diff --git a/cups/ipp.c b/cups/ipp.c index 76ee409d3..28b8961d7 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -3239,6 +3239,13 @@ ippReadIO(void *src, /* I - Data source */ ipp->prev = ipp->current; attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1); + if (!attr) + { + _cupsSetHTTPError(HTTP_ERROR); + DEBUG_puts("1ippReadIO: unable to allocate attribute."); + _cupsBufferRelease((char *)buffer); + return (IPP_ERROR); + } DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", ipp->current, ipp->prev)); @@ -6364,6 +6371,7 @@ ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */ _cupsStrFree(attr->values[0].string.language); attr->values[0].string.language = NULL; } + /* Fall through to other string values */ case IPP_TAG_TEXT : case IPP_TAG_NAME : diff --git a/cups/request.c b/cups/request.c index 01b8764ef..c1fbb5a04 100644 --- a/cups/request.c +++ b/cups/request.c @@ -1007,6 +1007,25 @@ _cupsConnect(void) httpClose(cg->http); cg->http = NULL; } + else + { + /* + * Same server, see if the connection is still established... + */ + + char ch; /* Connection check byte */ + + if (recv(cg->http->fd, &ch, 1, MSG_PEEK | MSG_DONTWAIT) < 0 && + errno != EWOULDBLOCK) + { + /* + * Nope, close the connection... + */ + + httpClose(cg->http); + cg->http = NULL; + } + } } /* diff --git a/cups/versioning.h b/cups/versioning.h index 808a10c2e..a9aab7246 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -3,7 +3,7 @@ * * API versioning definitions for CUPS. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2013 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -19,10 +19,11 @@ /* * This header defines several constants - _CUPS_DEPRECATED, - * _CUPS_API_1_1, _CUPS_API_1_1_19, _CUPS_API_1_1_20, _CUPS_API_1_1_21, - * _CUPS_API_1_2, _CUPS_API_1_3, _CUPS_API_1_4, _CUPS_API_1_5, _CUPS_API_1_6, - * and _CUPS_API_1_7 - which add compiler-specific attributes that flag - * functions that are deprecated or added in particular releases. + * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_1_1, _CUPS_API_1_1_19, + * _CUPS_API_1_1_20, _CUPS_API_1_1_21, _CUPS_API_1_2, _CUPS_API_1_3, + * _CUPS_API_1_4, _CUPS_API_1_5, _CUPS_API_1_6, and _CUPS_API_1_7 - which add + * compiler-specific attributes that flag functions that are deprecated, added + * in particular releases, or internal to CUPS. * * On OS X, the _CUPS_API_* constants are defined based on the values of * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants @@ -74,28 +75,66 @@ # endif /* __APPLE__ && !_CUPS_SOURCE */ /* - * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get - * a warning at compile-time. + * With GCC and Clang we can mark old APIs as "deprecated" or "unavailable" with + * messages so you get warnings/errors are compile-time... */ -# if defined(__GNUC__) && __GNUC__ > 2 -# ifndef __has_extension -# define __has_extension(x) 0 -# endif /* !__has_extension */ -# if __has_extension(attribute_unavailable_with_message) && defined(_CUPS_NO_DEPRECATED) -# define _CUPS_DEPRECATED __attribute__ ((unavailable)) -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) -# elif !defined(_CUPS_SOURCE) || defined(_CUPS_NO_DEPRECATED) -# define _CUPS_DEPRECATED __attribute__ ((deprecated)) -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) -# else -# define _CUPS_DEPRECATED -# define _CUPS_DEPRECATED_MSG(m) -# endif /* !_CUPS_SOURCE || _CUPS_NO_DEPRECATED */ -# else +# ifdef __has_extension /* Clang */ +# define _CUPS_HAS_DEPRECATED +# if __has_extension(attribute_deprecated_with_message) +# define _CUPS_HAS_DEPRECATED_WITH_MESSAGE +# endif +# if __has_extension(attribute_unavailable_with_message) +# define _CUPS_HAS_UNAVAILABLE_WITH_MESSAGE +# endif +# elif defined(__GNUC__) /* GCC and compatible */ +# if __GNUC__ >= 3 /* GCC 3.0 or higher */ +# define _CUPS_HAS_DEPRECATED +# endif /* __GNUC__ >= 3 */ +# if __GNUC__ >= 5 /* GCC 5.x */ +# define _CUPS_HAS_DEPRECATED_WITH_MESSAGE +# elif __GNUC__ == 4 && __GNUC_MINOR__ >= 5 + /* GCC 4.5 or higher */ +# define _CUPS_HAS_DEPRECATED_WITH_MESSAGE +# endif /* __GNUC__ >= 5 */ +# endif /* __has_extension */ + +# if !defined(_CUPS_HAS_DEPRECATED) || (defined(_CUPS_SOURCE) && !defined(_CUPS_NO_DEPRECATED)) + /* + * Don't mark functions deprecated if the compiler doesn't support it + * or we are building CUPS source that doesn't care. + */ # define _CUPS_DEPRECATED # define _CUPS_DEPRECATED_MSG(m) -# endif /* __GNUC__ && __GNUC__ > 2 */ +# define _CUPS_INTERNAL_MSG(m) +# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) && defined(_CUPS_NO_DEPRECATED) + /* + * Compiler supports the unsupported attribute, so use it when the code + * wants to exclude the use of deprecated API. + */ +# define _CUPS_DEPRECATED __attribute__ ((unavailable)) +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) +# else + /* + * Compiler supports the deprecated attribute, so use it. + */ +# define _CUPS_DEPRECATED __attribute__ ((deprecated)) +# ifdef _CUPS_HAS_DEPRECATED_WITH_MESSAGE +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) +# else +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) +# endif /* _CUPS_HAS_DEPRECATED_WITH_MESSAGE */ +# ifdef _CUPS_SOURCE +# define _CUPS_INTERNAL_MSG(m) +# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) +# elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) +# else +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) +# endif /* _CUPS_SOURCE */ +# endif /* !_CUPS_HAS_DEPRECATED || (_CUPS_SOURCE && !_CUPS_NO_DEPRECATED) */ # ifndef __GNUC__ # define __attribute__(x) |