X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=cups%2Fhttp.c;h=b3abbe73e0d02e9951599dfc3a5bcd72a5053692;hp=35b2799dd26d6a633e7d846c40329a22f032968f;hb=8072030b3c862315c367c73663b27f0427325919;hpb=0fa6c7fa54164ee70ee9ccfa936b889a637d5ecd diff --git a/cups/http.c b/cups/http.c index 35b2799dd..b3abbe73e 100644 --- a/cups/http.c +++ b/cups/http.c @@ -1,142 +1,19 @@ /* - * "$Id: http.c 7850 2008-08-20 00:07:25Z mike $" + * HTTP routines for CUPS. * - * HTTP routines for CUPS. + * Copyright 2007-2015 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2012 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * - * This file contains Kerberos support code, copyright 2006 by - * Jelmer Vernooij. + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * This file is subject to the Apple OS-Developed Software exception. - * - * Contents: - * - * httpAcceptConnection() - Accept a new HTTP client connection from - * the specified listening socket. - * httpAddCredential() - Allocates and adds a single credential to - * an array. - * _httpBIOMethods() - Get the OpenSSL BIO methods for HTTP - * connections. - * httpBlocking() - Set blocking/non-blocking behavior on a - * connection. - * httpCheck() - Check to see if there is a pending response - * from the server. - * httpClearCookie() - Clear the cookie value(s). - * httpClearFields() - Clear HTTP request fields. - * httpClose() - Close an HTTP connection. - * httpConnect() - Connect to a HTTP server. - * httpConnect2() - Connect to a HTTP server. - * httpConnectEncrypt() - Connect to a HTTP server using encryption. - * httpCopyCredentials() - Copy the credentials associated with an - * encrypted connection. - * _httpCreate() - Create an unconnected HTTP connection. - * _httpCreateCredentials() - Create credentials in the internal format. - * httpDelete() - Send a DELETE request to the server. - * _httpDisconnect() - Disconnect a HTTP connection. - * httpEncryption() - Set the required encryption on the link. - * httpError() - Get the last error on a connection. - * httpFlush() - Flush data from a HTTP connection. - * httpFlushWrite() - Flush data in write buffer. - * _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. - * httpGetCookie() - Get any cookie data from the response. - * 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. - * httpGetLength() - Get the amount of data remaining from the - * content-length or transfer-encoding fields. - * httpGetLength2() - Get the amount of data remaining from the - * content-length or transfer-encoding fields. - * httpGets() - Get a line of text from a HTTP connection. - * httpGetState() - Get the current state of the HTTP request. - * httpGetStatus() - Get the status of the last HTTP request. - * httpGetSubField() - Get a sub-field value. - * httpGetSubField2() - Get a sub-field value. - * httpGetVersion() - Get the HTTP version at the other end. - * httpHead() - Send a HEAD request to the server. - * httpInitialize() - Initialize the HTTP interface library and - * set the default HTTP proxy (if any). - * httpOptions() - Send an OPTIONS request to the server. - * httpPeek() - Peek at data from a HTTP connection. - * httpPost() - Send a POST request to the server. - * httpPrintf() - Print a formatted string to a HTTP - * connection. - * httpPut() - Send a PUT request to the server. - * httpRead() - Read data from a HTTP connection. - * httpRead2() - Read data from a HTTP connection. - * _httpReadCDSA() - Read function for the CDSA library. - * _httpReadGNUTLS() - Read function for the GNU TLS library. - * httpReadRequest() - Read a HTTP request from a connection. - * httpReconnect() - Reconnect to a HTTP server. - * httpReconnect2() - Reconnect to a HTTP server with timeout and - * optional cancel. - * httpSetAuthString() - Set the current authorization string. - * 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 - * content-encoding. - * httpSetTimeout() - Set read/write timeouts and an optional - * callback. - * httpTrace() - Send an TRACE request to the server. - * _httpUpdate() - Update the current HTTP status for incoming - * data. - * httpUpdate() - Update the current HTTP state for incoming - * data. - * _httpWait() - Wait for data available on a connection (no - * flush). - * httpWait() - Wait for data available on a connection. - * httpWrite() - Write data to a HTTP connection. - * httpWrite2() - Write data to a HTTP connection. - * _httpWriteCDSA() - Write function for the CDSA library. - * _httpWriteGNUTLS() - Write function for the GNU TLS library. - * httpWriteResponse() - Write a HTTP response to a client - * connection. - * http_bio_ctrl() - Control the HTTP connection. - * http_bio_free() - Free OpenSSL data. - * http_bio_new() - Initialize an OpenSSL BIO structure. - * http_bio_puts() - Send a string for OpenSSL. - * http_bio_read() - Read data for OpenSSL. - * http_bio_write() - Write data for OpenSSL. - * http_content_coding_finish() - Finish doing any content encoding. - * 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_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. - * http_shutdown_ssl() - Shut down SSL/TLS on a connection. - * http_upgrade() - Force upgrade to TLS encryption. - * http_write() - Write a buffer to a HTTP connection. - * http_write_chunk() - Write a chunked buffer. - * http_write_ssl() - Write to a SSL/TLS connection. + * This file is subject to the Apple OS-Developed Software exception. */ /* @@ -167,11 +44,14 @@ static void http_content_coding_finish(http_t *http); static void http_content_coding_start(http_t *http, const char *value); #endif /* HAVE_LIBZ */ +static http_t *http_create(const char *host, int port, + http_addrlist_t *addrlist, int family, + http_encryption_t encryption, + int blocking, _http_mode_t mode); #ifdef DEBUG 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); @@ -181,20 +61,12 @@ 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 -static int http_set_credentials(http_t *http); -# endif /* HAVE_CDSASSL */ -#endif /* HAVE_SSL */ static off_t http_set_length(http_t *http); static void http_set_timeout(int fd, double timeout); static void http_set_wait(http_t *http); + #ifdef HAVE_SSL -static int http_setup_ssl(http_t *http); -static void http_shutdown_ssl(http_t *http); -static int http_upgrade(http_t *http); -static int http_write_ssl(http_t *http, const char *buf, int len); +static int http_tls_upgrade(http_t *http); #endif /* HAVE_SSL */ @@ -235,63 +107,13 @@ static const char * const http_fields[] = "Allow", "Server" }; -#ifdef DEBUG -static const char * const http_states[] = - { - "HTTP_STATE_ERROR", - "HTTP_STATE_WAITING", - "HTTP_STATE_OPTIONS", - "HTTP_STATE_GET", - "HTTP_STATE_GET_SEND", - "HTTP_STATE_HEAD", - "HTTP_STATE_POST", - "HTTP_STATE_POST_RECV", - "HTTP_STATE_POST_SEND", - "HTTP_STATE_PUT", - "HTTP_STATE_PUT_RECV", - "HTTP_STATE_DELETE", - "HTTP_STATE_TRACE", - "HTTP_STATE_CONNECT", - "HTTP_STATE_STATUS", - "HTTP_STATE_UNKNOWN_METHOD", - "HTTP_STATE_UNKNOWN_VERSION" - }; -#endif /* DEBUG */ - - -#if defined(HAVE_SSL) && defined(HAVE_LIBSSL) -/* - * BIO methods for OpenSSL... - */ - -static int http_bio_write(BIO *h, const char *buf, int num); -static int http_bio_read(BIO *h, char *buf, int size); -static int http_bio_puts(BIO *h, const char *str); -static long http_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int http_bio_new(BIO *h); -static int http_bio_free(BIO *data); - -static BIO_METHOD http_bio_methods = - { - BIO_TYPE_SOCKET, - "http", - http_bio_write, - http_bio_read, - http_bio_puts, - NULL, /* http_bio_gets, */ - http_bio_ctrl, - http_bio_new, - http_bio_free, - NULL, - }; -#endif /* HAVE_SSL && HAVE_LIBSSL */ /* * 'httpAcceptConnection()' - Accept a new HTTP client connection from the * specified listening socket. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - HTTP connection or @code NULL@ */ @@ -318,7 +140,7 @@ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ memset(&addrlist, 0, sizeof(addrlist)); - if ((http = _httpCreate(NULL, 0, &addrlist, AF_UNSPEC, + if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, blocking, _HTTP_MODE_SERVER)) == NULL) return (NULL); @@ -338,8 +160,12 @@ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ return (NULL); } - httpAddrString(&(http->addrlist->addr), http->hostname, - sizeof(http->hostname)); + http->hostaddr = &(http->addrlist->addr); + + if (httpAddrLocalhost(http->hostaddr)) + strlcpy(http->hostname, "localhost", sizeof(http->hostname)); + else + httpAddrString(http->hostaddr, http->hostname, sizeof(http->hostname)); #ifdef SO_NOSIGPIPE /* @@ -347,7 +173,7 @@ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ */ val = 1; - setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)); + setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val)); #endif /* SO_NOSIGPIPE */ /* @@ -358,7 +184,7 @@ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ */ val = 1; - setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val)); #ifdef FD_CLOEXEC /* @@ -377,7 +203,7 @@ httpAcceptConnection(int fd, /* I - Listen socket file descriptor */ * * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array. * - * @since CUPS 1.5/OS X 10.7@ + * @since CUPS 1.5/macOS 10.7@ */ int /* O - 0 on success, -1 on error */ @@ -407,25 +233,12 @@ httpAddCredential( } -#if defined(HAVE_SSL) && defined(HAVE_LIBSSL) -/* - * '_httpBIOMethods()' - Get the OpenSSL BIO methods for HTTP connections. - */ - -BIO_METHOD * /* O - BIO methods for OpenSSL */ -_httpBIOMethods(void) -{ - return (&http_bio_methods); -} -#endif /* HAVE_SSL && HAVE_LIBSSL */ - - /* * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection. */ void -httpBlocking(http_t *http, /* I - Connection to server */ +httpBlocking(http_t *http, /* I - HTTP connection */ int b) /* I - 1 = blocking, 0 = non-blocking */ { if (http) @@ -441,7 +254,7 @@ httpBlocking(http_t *http, /* I - Connection to server */ */ int /* O - 0 = no data, 1 = data available */ -httpCheck(http_t *http) /* I - Connection to server */ +httpCheck(http_t *http) /* I - HTTP connection */ { return (httpWait(http, 0)); } @@ -450,11 +263,11 @@ httpCheck(http_t *http) /* I - Connection to server */ /* * 'httpClearCookie()' - Clear the cookie value(s). * - * @since CUPS 1.1.19/OS X 10.3@ + * @since CUPS 1.1.19/macOS 10.3@ */ void -httpClearCookie(http_t *http) /* I - Connection to server */ +httpClearCookie(http_t *http) /* I - HTTP connection */ { if (!http) return; @@ -472,9 +285,9 @@ httpClearCookie(http_t *http) /* I - Connection to server */ */ void -httpClearFields(http_t *http) /* I - Connection to server */ +httpClearFields(http_t *http) /* I - HTTP connection */ { - DEBUG_printf(("httpClearFields(http=%p)", http)); + DEBUG_printf(("httpClearFields(http=%p)", (void *)http)); if (http) { @@ -522,14 +335,14 @@ httpClearFields(http_t *http) /* I - Connection to server */ */ void -httpClose(http_t *http) /* I - Connection to server */ +httpClose(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_GSSAPI OM_uint32 minor_status; /* Minor status code */ #endif /* HAVE_GSSAPI */ - DEBUG_printf(("httpClose(http=%p)", http)); + DEBUG_printf(("httpClose(http=%p)", (void *)http)); /* * Range check input... @@ -575,6 +388,30 @@ httpClose(http_t *http) /* I - Connection to server */ } +/* + * 'httpCompareCredentials()' - Compare two sets of X.509 credentials. + * + * @since CUPS 2.0/OS 10.10@ + */ + +int /* O - 1 if they match, 0 if they do not */ +httpCompareCredentials( + cups_array_t *cred1, /* I - First set of X.509 credentials */ + cups_array_t *cred2) /* I - Second set of X.509 credentials */ +{ + http_credential_t *temp1, *temp2; /* Temporary credentials */ + + + for (temp1 = (http_credential_t *)cupsArrayFirst(cred1), temp2 = (http_credential_t *)cupsArrayFirst(cred2); temp1 && temp2; temp1 = (http_credential_t *)cupsArrayNext(cred1), temp2 = (http_credential_t *)cupsArrayNext(cred2)) + if (temp1->datalen != temp2->datalen) + return (0); + else if (memcmp(temp1->data, temp2->data, temp1->datalen)) + return (0); + + return (temp1 == temp2); +} + + /* * 'httpConnect()' - Connect to a HTTP server. * @@ -587,15 +424,15 @@ http_t * /* O - New HTTP connection */ httpConnect(const char *host, /* I - Host to connect to */ int port) /* I - Port number */ { - return (httpConnect2(host, port, NULL, AF_UNSPEC, HTTP_ENCRYPT_IF_REQUESTED, - 1, 30000, NULL)); + return (httpConnect2(host, port, NULL, AF_UNSPEC, + HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL)); } /* * 'httpConnect2()' - Connect to a HTTP server. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ http_t * /* O - New HTTP connection */ @@ -606,29 +443,27 @@ httpConnect2( int family, /* I - Address family to use or @code AF_UNSPEC@ for any */ http_encryption_t encryption, /* I - Type of encryption to use */ int blocking, /* I - 1 for blocking connection, 0 for non-blocking */ - int msec, /* I - Connection timeout in milliseconds */ + int msec, /* I - Connection timeout in milliseconds, 0 means don't connect */ int *cancel) /* I - Pointer to "cancel" variable */ { http_t *http; /* New HTTP connection */ - DEBUG_printf(("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, " - "encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, - addrlist, family, encryption, blocking, msec, cancel)); + DEBUG_printf(("httpConnect2(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, msec=%d, cancel=%p)", host, port, (void *)addrlist, family, encryption, blocking, msec, (void *)cancel)); /* * Create the HTTP structure... */ - if ((http = _httpCreate(host, port, addrlist, family, encryption, blocking, + if ((http = http_create(host, port, addrlist, family, encryption, blocking, _HTTP_MODE_CLIENT)) == NULL) return (NULL); /* - * Connect to the remote system... + * Optionally connect to the remote system... */ - if (!httpReconnect2(http, msec, cancel)) + if (msec == 0 || !httpReconnect2(http, msec, cancel)) return (http); /* @@ -664,233 +499,15 @@ httpConnectEncrypt( } -/* - * 'httpCopyCredentials()' - Copy the credentials associated with an encrypted - * connection. - * - * @since CUPS 1.5/OS X 10.7@ - */ - -int /* O - Status of call (0 = success) */ -httpCopyCredentials( - http_t *http, /* I - Connection to server */ - cups_array_t **credentials) /* O - Array of credentials */ -{ -# ifdef HAVE_LIBSSL -# elif defined(HAVE_GNUTLS) -# elif defined(HAVE_CDSASSL) - OSStatus error; /* Error code */ - SecTrustRef peerTrust; /* Peer trust reference */ - CFIndex count; /* Number of credentials */ - SecCertificateRef secCert; /* Certificate reference */ - CFDataRef data; /* Certificate data */ - int i; /* Looping var */ -# elif defined(HAVE_SSPISSL) -# endif /* HAVE_LIBSSL */ - - - if (credentials) - *credentials = NULL; - - if (!http || !http->tls || !credentials) - return (-1); - -# ifdef HAVE_LIBSSL - return (-1); - -# elif defined(HAVE_GNUTLS) - return (-1); - -# elif defined(HAVE_CDSASSL) - if (!(error = SSLCopyPeerTrust(http->tls, &peerTrust)) && peerTrust) - { - if ((*credentials = cupsArrayNew(NULL, NULL)) != NULL) - { - count = SecTrustGetCertificateCount(peerTrust); - - for (i = 0; i < count; i ++) - { - secCert = SecTrustGetCertificateAtIndex(peerTrust, i); - if ((data = SecCertificateCopyData(secCert))) - { - httpAddCredential(*credentials, CFDataGetBytePtr(data), - CFDataGetLength(data)); - CFRelease(data); - } - } - } - - CFRelease(peerTrust); - } - - return (error); - -# elif defined(HAVE_SSPISSL) - return (-1); - -# else - return (-1); -# endif /* HAVE_LIBSSL */ -} - - -/* - * '_httpCreate()' - Create an unconnected HTTP connection. - */ - -http_t * /* O - HTTP connection */ -_httpCreate( - const char *host, /* I - Hostname */ - int port, /* I - Port number */ - http_addrlist_t *addrlist, /* I - Address list or NULL */ - int family, /* I - Address family or AF_UNSPEC */ - http_encryption_t encryption, /* I - Encryption to use */ - int blocking, /* I - 1 for blocking mode */ - _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */ -{ - http_t *http; /* New HTTP connection */ - char service[255]; /* Service name */ - http_addrlist_t *myaddrlist = NULL; /* My address list */ - - - DEBUG_printf(("4_httpCreate(host=\"%s\", port=%d, addrlist=%p, family=%d, " - "encryption=%d, blocking=%d, mode=%d)", host, port, addrlist, - family, encryption, blocking, mode)); - - if (!host && mode == _HTTP_MODE_CLIENT) - return (NULL); - - httpInitialize(); - - /* - * Lookup the host... - */ - - if (addrlist) - { - myaddrlist = httpAddrCopyList(addrlist); - } - else - { - snprintf(service, sizeof(service), "%d", port); - - myaddrlist = httpAddrGetList(host, family, service); - } - - if (!myaddrlist) - return (NULL); - - /* - * Allocate memory for the structure... - */ - - if ((http = calloc(sizeof(http_t), 1)) == NULL) - { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0); - httpAddrFreeList(addrlist); - return (NULL); - } - - /* - * Initialize the HTTP data... - */ - - http->mode = mode; - http->activity = time(NULL); - http->addrlist = myaddrlist; - http->blocking = blocking; - http->fd = -1; -#ifdef HAVE_GSSAPI - http->gssctx = GSS_C_NO_CONTEXT; - http->gssname = GSS_C_NO_NAME; -#endif /* HAVE_GSSAPI */ - http->version = HTTP_VERSION_1_1; - - if (host) - strlcpy(http->hostname, host, sizeof(http->hostname)); - - if (port == 443) /* Always use encryption for https */ - http->encryption = HTTP_ENCRYPTION_ALWAYS; - else - http->encryption = encryption; - - http_set_wait(http); - - /* - * Return the new structure... - */ - - return (http); -} - - -/* - * '_httpCreateCredentials()' - Create credentials in the internal format. - */ - -http_tls_credentials_t /* O - Internal credentials */ -_httpCreateCredentials( - cups_array_t *credentials) /* I - Array of credentials */ -{ - if (!credentials) - return (NULL); - -# ifdef HAVE_LIBSSL - return (NULL); - -# elif defined(HAVE_GNUTLS) - return (NULL); - -# elif defined(HAVE_CDSASSL) - CFMutableArrayRef peerCerts; /* Peer credentials reference */ - SecCertificateRef secCert; /* Certificate reference */ - CFDataRef data; /* Credential data reference */ - http_credential_t *credential; /* Credential data */ - - - if ((peerCerts = CFArrayCreateMutable(kCFAllocatorDefault, - cupsArrayCount(credentials), - &kCFTypeArrayCallBacks)) == NULL) - return (NULL); - - for (credential = (http_credential_t *)cupsArrayFirst(credentials); - credential; - credential = (http_credential_t *)cupsArrayNext(credentials)) - { - if ((data = CFDataCreate(kCFAllocatorDefault, credential->data, - credential->datalen))) - { - if ((secCert = SecCertificateCreateWithData(kCFAllocatorDefault, data)) - != NULL) - { - CFArrayAppendValue(peerCerts, secCert); - CFRelease(secCert); - } - - CFRelease(data); - } - } - - return (peerCerts); - -# elif defined(HAVE_SSPISSL) - return (NULL); - -# else - return (NULL); -# endif /* HAVE_LIBSSL */ -} - - /* * 'httpDelete()' - Send a DELETE request to the server. */ int /* O - Status of call (0 = success) */ -httpDelete(http_t *http, /* I - Connection to server */ +httpDelete(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to delete */ { - return (http_send(http, HTTP_DELETE, uri)); + return (http_send(http, HTTP_STATE_DELETE, uri)); } @@ -899,18 +516,14 @@ httpDelete(http_t *http, /* I - Connection to server */ */ void -_httpDisconnect(http_t *http) /* I - Connection to server */ +_httpDisconnect(http_t *http) /* I - HTTP connection */ { #ifdef HAVE_SSL if (http->tls) - http_shutdown_ssl(http); + _httpTLSStop(http); #endif /* HAVE_SSL */ -#ifdef WIN32 - closesocket(http->fd); -#else - close(http->fd); -#endif /* WIN32 */ + httpAddrClose(NULL, http->fd); http->fd = -1; } @@ -921,26 +534,40 @@ _httpDisconnect(http_t *http) /* I - Connection to server */ */ int /* O - -1 on error, 0 on success */ -httpEncryption(http_t *http, /* I - Connection to server */ +httpEncryption(http_t *http, /* I - HTTP connection */ http_encryption_t e) /* I - New encryption preference */ { - DEBUG_printf(("httpEncryption(http=%p, e=%d)", http, e)); + DEBUG_printf(("httpEncryption(http=%p, e=%d)", (void *)http, e)); #ifdef HAVE_SSL if (!http) return (0); - http->encryption = e; + if (http->mode == _HTTP_MODE_CLIENT) + { + http->encryption = e; - if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) || - (http->encryption == HTTP_ENCRYPT_NEVER && http->tls)) - return (httpReconnect(http)); - else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) - return (http_upgrade(http)); + if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) || + (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls)) + return (httpReconnect2(http, 30000, NULL)); + else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) + return (http_tls_upgrade(http)); + else + return (0); + } else - return (0); + { + if (e == HTTP_ENCRYPTION_NEVER && http->tls) + return (-1); + + http->encryption = e; + if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls) + return (_httpTLSStart(http)); + else + return (0); + } #else - if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED) + if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED) return (-1); else return (0); @@ -953,7 +580,7 @@ httpEncryption(http_t *http, /* I - Connection to server */ */ int /* O - Error code (errno) value */ -httpError(http_t *http) /* I - Connection to server */ +httpError(http_t *http) /* I - HTTP connection */ { if (http) return (http->error); @@ -962,20 +589,38 @@ httpError(http_t *http) /* I - Connection to server */ } +/* + * 'httpFieldValue()' - Return the HTTP field enumeration value for a field + * name. + */ + +http_field_t /* O - Field index */ +httpFieldValue(const char *name) /* I - String name */ +{ + int i; /* Looping var */ + + + for (i = 0; i < HTTP_FIELD_MAX; i ++) + if (!_cups_strcasecmp(name, http_fields[i])) + return ((http_field_t)i); + + return (HTTP_FIELD_UNKNOWN); +} + + /* * 'httpFlush()' - Flush data from a HTTP connection. */ void -httpFlush(http_t *http) /* I - Connection to server */ +httpFlush(http_t *http) /* I - HTTP connection */ { char buffer[8192]; /* Junk buffer */ int blocking; /* To block or not to block */ http_state_t oldstate; /* Old state */ - DEBUG_printf(("httpFlush(http=%p), state=%s", http, - http_states[http->state + 1])); + DEBUG_printf(("httpFlush(http=%p), state=%s", (void *)http, httpStateString(http->state))); /* * Nothing to do if we are in the "waiting" state... @@ -1023,14 +668,10 @@ httpFlush(http_t *http) /* I - Connection to server */ #ifdef HAVE_SSL if (http->tls) - http_shutdown_ssl(http); + _httpTLSStop(http); #endif /* HAVE_SSL */ -#ifdef WIN32 - closesocket(http->fd); -#else - close(http->fd); -#endif /* WIN32 */ + httpAddrClose(NULL, http->fd); http->fd = -1; } @@ -1040,17 +681,16 @@ httpFlush(http_t *http) /* I - Connection to server */ /* * 'httpFlushWrite()' - Flush data in write buffer. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ int /* O - Bytes written or -1 on error */ -httpFlushWrite(http_t *http) /* I - Connection to server */ +httpFlushWrite(http_t *http) /* I - HTTP connection */ { - int bytes; /* Bytes written */ + ssize_t bytes; /* Bytes written */ - DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", http, - http ? http->data_encoding : -1)); + DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", (void *)http, http ? http->data_encoding : 100)); if (!http || !http->wused) { @@ -1060,42 +700,15 @@ httpFlushWrite(http_t *http) /* I - Connection to server */ } if (http->data_encoding == HTTP_ENCODING_CHUNKED) - bytes = http_write_chunk(http, http->wbuffer, http->wused); + bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused); else - bytes = http_write(http, http->wbuffer, http->wused); + bytes = http_write(http, http->wbuffer, (size_t)http->wused); http->wused = 0; - DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", bytes, errno)); - - return (bytes); -} - - -/* - * '_httpFreeCredentials()' - Free internal credentials. - */ - -void -_httpFreeCredentials( - http_tls_credentials_t credentials) /* I - Internal credentials */ -{ - if (!credentials) - return; - -#ifdef HAVE_LIBSSL - (void)credentials; - -#elif defined(HAVE_GNUTLS) - (void)credentials; - -#elif defined(HAVE_CDSASSL) - CFRelease(credentials); + DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno)); -#elif defined(HAVE_SSPISSL) - (void)credentials; - -#endif /* HAVE_LIBSSL */ + return ((int)bytes); } @@ -1128,40 +741,89 @@ httpFreeCredentials( */ int /* O - Status of call (0 = success) */ -httpGet(http_t *http, /* I - Connection to server */ +httpGet(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to get */ { - return (http_send(http, HTTP_GET, uri)); + return (http_send(http, HTTP_STATE_GET, uri)); } /* - * 'httpGetContentEncoding()' - Get a common content encoding, if any, between - * the client and server. + * 'httpGetActivity()' - Get the most recent activity for a connection. * - * 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. + * The return value is the UNIX time of the last read or write. * - * @since CUPS 1.7@ + * @since CUPS 2.0/OS 10.10@ */ -const char * /* O - Content-Coding value or - @code NULL@ for the identity - coding. */ -httpGetContentEncoding(http_t *http) /* I - Connection to client/server */ +time_t /* O - Time of last read or write */ +httpGetActivity(http_t *http) /* I - HTTP connection */ { -#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[] = + return (http ? http->activity : 0); +} + + +/* + * 'httpGetAuthString()' - Get the current authorization string. + * + * The authorization string is set by cupsDoAuthentication() and + * httpSetAuthString(). Use httpGetAuthString() to retrieve the + * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION + * value. + * + * @since CUPS 1.3/macOS 10.5@ + */ + +char * /* O - Authorization string */ +httpGetAuthString(http_t *http) /* I - HTTP connection */ +{ + if (http) + return (http->authstring); + else + return (NULL); +} + + +/* + * 'httpGetBlocking()' - Get the blocking/non-block state of a connection. + * + * @since CUPS 1.2/macOS 10.5@ + */ + +int /* O - 1 if blocking, 0 if non-blocking */ +httpGetBlocking(http_t *http) /* I - HTTP connection */ +{ + return (http ? http->blocking : 0); +} + + +/* + * '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/macOS 10.9@ + */ + +const char * /* O - Content-Coding value or + @code NULL@ for the identity + coding. */ +httpGetContentEncoding(http_t *http) /* I - HTTP connection */ +{ +#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", @@ -1224,49 +886,32 @@ httpGetContentEncoding(http_t *http) /* I - Connection to client/server */ /* - * 'httpGetAuthString()' - Get the current authorization string. - * - * The authorization string is set by cupsDoAuthentication() and - * httpSetAuthString(). Use httpGetAuthString() to retrieve the - * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION - * value. + * 'httpGetCookie()' - Get any cookie data from the response. * - * @since CUPS 1.3/OS X 10.5@ + * @since CUPS 1.1.19/macOS 10.3@ */ -char * /* O - Authorization string */ -httpGetAuthString(http_t *http) /* I - Connection to server */ +const char * /* O - Cookie data or NULL */ +httpGetCookie(http_t *http) /* I - HTTP connection */ { - if (http) - return (http->authstring); - else - return (NULL); + return (http ? http->cookie : NULL); } /* - * 'httpGetBlocking()' - Get the blocking/non-block state of a connection. + * 'httpGetEncryption()' - Get the current encryption mode of a connection. * - * @since CUPS 1.2/OS X 10.5@ - */ - -int /* O - 1 if blocking, 0 if non-blocking */ -httpGetBlocking(http_t *http) /* I - Connection to server */ -{ - return (http ? http->blocking : 0); -} - - -/* - * 'httpGetCookie()' - Get any cookie data from the response. + * This function returns the encryption mode for the connection. Use the + * @link httpIsEncrypted@ function to determine whether a TLS session has + * been established. * - * @since CUPS 1.1.19/OS X 10.3@ + * @since CUPS 2.0/OS 10.10@ */ -const char * /* O - Cookie data or NULL */ -httpGetCookie(http_t *http) /* I - HTTP connecion */ +http_encryption_t /* O - Current encryption mode */ +httpGetEncryption(http_t *http) /* I - HTTP connection */ { - return (http ? http->cookie : NULL); + return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED); } @@ -1276,11 +921,11 @@ httpGetCookie(http_t *http) /* I - HTTP connecion */ * Returns @code HTTP_STATUS_NONE@ if there is no Expect header, otherwise * returns the expected HTTP status code, typically @code HTTP_STATUS_CONTINUE@. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ http_status_t /* O - Expect: status, if any */ -httpGetExpect(http_t *http) /* I - Connection to client */ +httpGetExpect(http_t *http) /* I - HTTP connection */ { if (!http) return (HTTP_STATUS_ERROR); @@ -1292,11 +937,11 @@ httpGetExpect(http_t *http) /* I - Connection to client */ /* * 'httpGetFd()' - Get the file descriptor associated with a connection. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ int /* O - File descriptor or -1 if none */ -httpGetFd(http_t *http) /* I - Connection to server */ +httpGetFd(http_t *http) /* I - HTTP connection */ { return (http ? http->fd : -1); } @@ -1307,7 +952,7 @@ httpGetFd(http_t *http) /* I - Connection to server */ */ const char * /* O - Field value */ -httpGetField(http_t *http, /* I - Connection to server */ +httpGetField(http_t *http, /* I - HTTP connection */ http_field_t field) /* I - Field to get */ { if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) @@ -1341,6 +986,19 @@ httpGetField(http_t *http, /* I - Connection to server */ } +/* + * 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection. + * + * @since CUPS 2.0/OS 10.10@ + */ + +http_keepalive_t /* O - Keep-Alive state */ +httpGetKeepAlive(http_t *http) /* I - HTTP connection */ +{ + return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF); +} + + /* * 'httpGetLength()' - Get the amount of data remaining from the * content-length or transfer-encoding fields. @@ -1352,7 +1010,7 @@ httpGetField(http_t *http, /* I - Connection to server */ */ int /* O - Content length */ -httpGetLength(http_t *http) /* I - Connection to server */ +httpGetLength(http_t *http) /* I - HTTP connection */ { /* * Get the read content length and return the 32-bit value. @@ -1376,17 +1034,16 @@ httpGetLength(http_t *http) /* I - Connection to server */ * This function returns the complete content length, even for * content larger than 2^31 - 1. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ off_t /* O - Content length */ -httpGetLength2(http_t *http) /* I - Connection to server */ +httpGetLength2(http_t *http) /* I - HTTP connection */ { off_t remaining; /* Remaining length */ - DEBUG_printf(("2httpGetLength2(http=%p), state=%s", http, - http_states[http->state + 1])); + DEBUG_printf(("2httpGetLength2(http=%p), state=%s", (void *)http, httpStateString(http->state))); if (!http) return (-1); @@ -1413,7 +1070,7 @@ httpGetLength2(http_t *http) /* I - Connection to server */ * and 2^31-1 for other successful requests... */ - if (http->status >= HTTP_MULTIPLE_CHOICES || + if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES || http->state == HTTP_STATE_OPTIONS || (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) || http->state == HTTP_STATE_HEAD || @@ -1437,6 +1094,58 @@ httpGetLength2(http_t *http) /* I - Connection to server */ } +/* + * 'httpGetPending()' - Get the number of bytes that are buffered for writing. + * + * @since CUPS 2.0/OS 10.10@ + */ + +size_t /* O - Number of bytes buffered */ +httpGetPending(http_t *http) /* I - HTTP connection */ +{ + return (http ? (size_t)http->wused : 0); +} + + +/* + * 'httpGetReady()' - Get the number of bytes that can be read without blocking. + * + * @since CUPS 2.0/OS 10.10@ + */ + +size_t /* O - Number of bytes available */ +httpGetReady(http_t *http) /* I - HTTP connection */ +{ + if (!http) + return (0); + else if (http->used > 0) + return ((size_t)http->used); +#ifdef HAVE_SSL + else if (http->tls) + return (_httpTLSPending(http)); +#endif /* HAVE_SSL */ + + return (0); +} + + +/* + * 'httpGetRemaining()' - Get the number of remaining bytes in the message + * body or current chunk. + * + * The @link httpIsChunked@ function can be used to determine whether the + * message body is chunked or fixed-length. + * + * @since CUPS 2.0/OS 10.10@ + */ + +size_t /* O - Remaining bytes */ +httpGetRemaining(http_t *http) /* I - HTTP connection */ +{ + return (http ? (size_t)http->data_remaining : 0); +} + + /* * 'httpGets()' - Get a line of text from a HTTP connection. */ @@ -1444,17 +1153,17 @@ httpGetLength2(http_t *http) /* I - Connection to server */ char * /* O - Line or NULL */ httpGets(char *line, /* I - Line to read into */ int length, /* I - Max length of buffer */ - http_t *http) /* I - Connection to server */ + http_t *http) /* I - HTTP connection */ { - char *lineptr, /* Pointer into line */ - *lineend, /* End of line */ - *bufptr, /* Pointer into input buffer */ - *bufend; /* Pointer to end of buffer */ - int bytes, /* Number of bytes read */ - eol; /* End-of-line? */ + char *lineptr, /* Pointer into line */ + *lineend, /* End of line */ + *bufptr, /* Pointer into input buffer */ + *bufend; /* Pointer to end of buffer */ + ssize_t bytes; /* Number of bytes read */ + int eol; /* End-of-line? */ - DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", line, length, http)); + DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", (void *)line, length, (void *)http)); if (!http || !line || length <= 1) return (NULL); @@ -1500,10 +1209,9 @@ httpGets(char *line, /* I - Line to read into */ return (NULL); } - bytes = http_read(http, http->buffer + http->used, - HTTP_MAX_BUFFER - http->used); + bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used)); - DEBUG_printf(("4httpGets: read %d bytes.", bytes)); + DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes)); if (bytes < 0) { @@ -1563,7 +1271,7 @@ httpGets(char *line, /* I - Line to read into */ * Yup, update the amount used... */ - http->used += bytes; + http->used += (int)bytes; } /* @@ -1587,7 +1295,7 @@ httpGets(char *line, /* I - Line to read into */ http->used -= (int)(bufptr - http->buffer); if (http->used > 0) - memmove(http->buffer, bufptr, http->used); + memmove(http->buffer, bufptr, (size_t)http->used); if (eol) { @@ -1616,7 +1324,7 @@ httpGets(char *line, /* I - Line to read into */ */ http_state_t /* O - HTTP state */ -httpGetState(http_t *http) /* I - Connection to server */ +httpGetState(http_t *http) /* I - HTTP connection */ { return (http ? http->state : HTTP_STATE_ERROR); } @@ -1625,13 +1333,13 @@ httpGetState(http_t *http) /* I - Connection to server */ /* * 'httpGetStatus()' - Get the status of the last HTTP request. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ http_status_t /* O - HTTP status */ -httpGetStatus(http_t *http) /* I - Connection to server */ +httpGetStatus(http_t *http) /* I - HTTP connection */ { - return (http ? http->status : HTTP_ERROR); + return (http ? http->status : HTTP_STATUS_ERROR); } @@ -1642,7 +1350,7 @@ httpGetStatus(http_t *http) /* I - Connection to server */ */ char * /* O - Value or NULL */ -httpGetSubField(http_t *http, /* I - Connection to server */ +httpGetSubField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value) /* O - Value string */ @@ -1654,11 +1362,11 @@ httpGetSubField(http_t *http, /* I - Connection to server */ /* * 'httpGetSubField2()' - Get a sub-field value. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ char * /* O - Value or NULL */ -httpGetSubField2(http_t *http, /* I - Connection to server */ +httpGetSubField2(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ char *value, /* O - Value string */ @@ -1669,8 +1377,7 @@ httpGetSubField2(http_t *http, /* I - Connection to server */ *ptr, /* Pointer into string buffer */ *end; /* End of value buffer */ - DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, " - "valuelen=%d)", http, field, name, value, valuelen)); + DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen)); if (!http || !name || !value || valuelen < 2 || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX) @@ -1788,7 +1495,7 @@ httpGetSubField2(http_t *http, /* I - Connection to server */ */ http_version_t /* O - Version number */ -httpGetVersion(http_t *http) /* I - Connection to server */ +httpGetVersion(http_t *http) /* I - HTTP connection */ { return (http ? http->version : HTTP_VERSION_1_0); } @@ -1799,11 +1506,11 @@ httpGetVersion(http_t *http) /* I - Connection to server */ */ int /* O - Status of call (0 = success) */ -httpHead(http_t *http, /* I - Connection to server */ +httpHead(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for head */ { - DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", http, uri)); - return (http_send(http, HTTP_HEAD, uri)); + DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri)); + return (http_send(http, HTTP_STATE_HEAD, uri)); } @@ -1819,10 +1526,6 @@ httpInitialize(void) #ifdef WIN32 WSADATA winsockdata; /* WinSock data */ #endif /* WIN32 */ -#ifdef HAVE_LIBSSL - int i; /* Looping var */ - unsigned char data[1024]; /* Seed data */ -#endif /* HAVE_LIBSSL */ _cupsGlobalLock(); @@ -1856,36 +1559,43 @@ httpInitialize(void) # endif /* !SO_NOSIGPIPE */ #endif /* WIN32 */ -#ifdef HAVE_GNUTLS - /* - * Initialize GNU TLS... - */ - - gnutls_global_init(); +# ifdef HAVE_SSL + _httpTLSInitialize(); +# endif /* HAVE_SSL */ -#elif defined(HAVE_LIBSSL) - /* - * Initialize OpenSSL... - */ + initialized = 1; + _cupsGlobalUnlock(); +} - SSL_load_error_strings(); - SSL_library_init(); - /* - * Using the current time is a dubious random seed, but on some systems - * it is the best we can do (on others, this seed isn't even used...) - */ +/* + * 'httpIsChunked()' - Report whether a message body is chunked. + * + * This function returns non-zero if the message body is composed of + * variable-length chunks. + * + * @since CUPS 2.0/OS 10.10@ + */ - CUPS_SRAND(time(NULL)); +int /* O - 1 if chunked, 0 if not */ +httpIsChunked(http_t *http) /* I - HTTP connection */ +{ + return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0); +} - for (i = 0; i < sizeof(data); i ++) - data[i] = CUPS_RAND(); - RAND_seed(data, sizeof(data)); -#endif /* HAVE_GNUTLS */ +/* + * 'httpIsEncrypted()' - Report whether a connection is encrypted. + * + * This function returns non-zero if the connection is currently encrypted. + * + * @since CUPS 2.0/OS 10.10@ + */ - initialized = 1; - _cupsGlobalUnlock(); +int /* O - 1 if encrypted, 0 if not */ +httpIsEncrypted(http_t *http) /* I - HTTP connection */ +{ + return (http ? http->tls != NULL : 0); } @@ -1894,10 +1604,10 @@ httpInitialize(void) */ int /* O - Status of call (0 = success) */ -httpOptions(http_t *http, /* I - Connection to server */ +httpOptions(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for options */ { - return (http_send(http, HTTP_OPTIONS, uri)); + return (http_send(http, HTTP_STATE_OPTIONS, uri)); } @@ -1910,11 +1620,11 @@ httpOptions(http_t *http, /* I - Connection to server */ * * For non-blocking connections the usual timeouts apply. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ ssize_t /* O - Number of bytes copied */ -httpPeek(http_t *http, /* I - Connection to server */ +httpPeek(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { @@ -1922,8 +1632,7 @@ httpPeek(http_t *http, /* I - Connection to server */ char len[32]; /* Length string */ - DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", - http, buffer, CUPS_LLCAST length)); + DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (http == NULL || buffer == NULL) return (-1); @@ -1945,7 +1654,18 @@ httpPeek(http_t *http, /* I - Connection to server */ return (0); } + if (!len[0]) + { + DEBUG_puts("1httpPeek: Blank chunk length, trying again..."); + if (!httpGets(len, sizeof(len), http)) + { + DEBUG_puts("1httpPeek: Could not get chunk length."); + return (0); + } + } + http->data_remaining = strtoll(len, NULL, 16); + if (http->data_remaining < 0) { DEBUG_puts("1httpPeek: Negative chunk length!"); @@ -1964,7 +1684,7 @@ httpPeek(http_t *http, /* I - Connection to server */ */ #ifdef HAVE_LIBZ - if (http->coding) + if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ @@ -1974,10 +1694,10 @@ httpPeek(http_t *http, /* I - Connection to server */ if (http->state == HTTP_STATE_POST_RECV) http->state ++; else - http->state = HTTP_STATE_WAITING; + http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.", - http_states[http->state + 1])); + httpStateString(http->state))); /* * Prevent future reads for this request... @@ -1992,7 +1712,8 @@ httpPeek(http_t *http, /* I - Connection to server */ #ifdef HAVE_LIBZ if (http->used == 0 && - (http->coding == _HTTP_CODING_IDENTITY || http->stream.avail_in == 0)) + (http->coding == _HTTP_CODING_IDENTITY || + (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0))) #else if (http->used == 0) #endif /* HAVE_LIBZ */ @@ -2014,75 +1735,30 @@ httpPeek(http_t *http, /* I - Connection to server */ } } - if (http->data_remaining > sizeof(http->buffer)) + if ((size_t)http->data_remaining > sizeof(http->buffer)) buflen = sizeof(http->buffer); else - buflen = http->data_remaining; + buflen = (ssize_t)http->data_remaining; DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen)); - - 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 (!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); + bytes = http_read(http, http->buffer, (size_t)buflen); DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.", CUPS_LLCAST bytes)); + if (bytes > 0) + { #ifdef DEBUG - http_debug_hex("httpPeek", http->buffer, (int)bytes); + http_debug_hex("httpPeek", http->buffer, (int)bytes); #endif /* DEBUG */ - http->used = bytes; + http->used = (int)bytes; + } } #ifdef HAVE_LIBZ - if (http->coding) + if (http->coding >= _HTTP_CODING_GUNZIP) { +# ifdef HAVE_INFLATECOPY int zerr; /* Decompressor error */ z_stream stream; /* Copy of decompressor stream */ @@ -2092,27 +1768,27 @@ httpPeek(http_t *http, /* I - Connection to server */ /* 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->sbuffer) + memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); - http->stream.next_in = http->dbuffer; + http->stream.next_in = http->sbuffer; - if (buflen > http->data_remaining) - buflen = http->data_remaining; + if (buflen > (size_t)http->data_remaining) + buflen = (size_t)http->data_remaining; - if (buflen > http->used) - buflen = http->used; + if (buflen > (size_t)http->used) + buflen = (size_t)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); + memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen); http->stream.avail_in += buflen; - http->used -= buflen; - http->data_remaining -= buflen; + http->used -= (int)buflen; + http->data_remaining -= (off_t)buflen; if (http->used > 0) - memmove(http->buffer, http->buffer + buflen, http->used); + memmove(http->buffer, http->buffer + buflen, (size_t)http->used); } DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length, @@ -2126,7 +1802,7 @@ httpPeek(http_t *http, /* I - Connection to server */ } stream.next_out = (Bytef *)buffer; - stream.avail_out = length; + stream.avail_out = (uInt)length; zerr = inflate(&stream, Z_SYNC_FLUSH); inflateEnd(&stream); @@ -2135,15 +1811,20 @@ httpPeek(http_t *http, /* I - Connection to server */ { DEBUG_printf(("2httpPeek: zerr=%d", zerr)); #ifdef DEBUG - http_debug_hex("2httpPeek", (char *)http->dbuffer, - http->stream.avail_in); + http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } - bytes = length - http->stream.avail_out; + bytes = (ssize_t)(length - http->stream.avail_out); + +# else + DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not " + "work with compressed streams."); + return (-1); +# endif /* HAVE_INFLATECOPY */ } else #endif /* HAVE_LIBZ */ @@ -2182,27 +1863,19 @@ httpPeek(http_t *http, /* I - Connection to server */ return (0); } -#ifdef DEBUG - http_debug_hex("httpPeek", buffer, (int)bytes); -#endif /* DEBUG */ - return (bytes); } -/* For OS X 10.8 and earlier */ -ssize_t _httpPeek(http_t *http, char *buffer, size_t length) -{ return (httpPeek(http, buffer, length)); } - /* * 'httpPost()' - Send a POST request to the server. */ int /* O - Status of call (0 = success) */ -httpPost(http_t *http, /* I - Connection to server */ +httpPost(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for post */ { - return (http_send(http, HTTP_POST, uri)); + return (http_send(http, HTTP_STATE_POST, uri)); } @@ -2213,25 +1886,25 @@ httpPost(http_t *http, /* I - Connection to server */ */ int /* O - Number of bytes written */ -httpPrintf(http_t *http, /* I - Connection to server */ +httpPrintf(http_t *http, /* I - HTTP connection */ const char *format, /* I - printf-style format string */ ...) /* I - Additional args as needed */ { - int bytes; /* Number of bytes to write */ + ssize_t bytes; /* Number of bytes to write */ char buf[16384]; /* Buffer for formatted string */ va_list ap; /* Variable argument pointer */ - DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", http, format)); + DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format)); va_start(ap, format); bytes = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); - DEBUG_printf(("3httpPrintf: (%d bytes) %s", bytes, buf)); + DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf)); if (http->data_encoding == HTTP_ENCODING_FIELDS) - return (httpWrite2(http, buf, bytes)); + return ((int)httpWrite2(http, buf, (size_t)bytes)); else { if (http->wused) @@ -2242,7 +1915,7 @@ httpPrintf(http_t *http, /* I - Connection to server */ return (-1); } - return (http_write(http, buf, bytes)); + return ((int)http_write(http, buf, (size_t)bytes)); } } @@ -2252,11 +1925,11 @@ httpPrintf(http_t *http, /* I - Connection to server */ */ int /* O - Status of call (0 = success) */ -httpPut(http_t *http, /* I - Connection to server */ +httpPut(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI to put */ { - DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", http, uri)); - return (http_send(http, HTTP_PUT, uri)); + DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", (void *)http, uri)); + return (http_send(http, HTTP_STATE_PUT, uri)); } @@ -2270,32 +1943,33 @@ httpPut(http_t *http, /* I - Connection to server */ */ int /* O - Number of bytes read */ -httpRead(http_t *http, /* I - Connection to server */ +httpRead(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ int length) /* I - Maximum number of bytes */ { - return ((int)httpRead2(http, buffer, length)); + return ((int)httpRead2(http, buffer, (size_t)length)); } /* * 'httpRead2()' - Read data from a HTTP connection. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes read */ -httpRead2(http_t *http, /* I - Connection to server */ +httpRead2(http_t *http, /* I - HTTP connection */ char *buffer, /* I - Buffer for data */ size_t length) /* I - Maximum number of bytes */ { ssize_t bytes; /* Bytes read */ - DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT - ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, - http, buffer, CUPS_LLCAST length, http->coding, - http->data_encoding, CUPS_LLCAST http->data_remaining)); +#ifdef HAVE_LIBZ + DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") coding=%d data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->coding, http->data_encoding, CUPS_LLCAST http->data_remaining)); +#else + DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ") data_encoding=%d data_remaining=" CUPS_LLFMT, (void *)http, (void *)buffer, CUPS_LLCAST length, http->data_encoding, CUPS_LLCAST http->data_remaining)); +#endif /* HAVE_LIBZ */ if (http == NULL || buffer == NULL) return (-1); @@ -2307,7 +1981,7 @@ httpRead2(http_t *http, /* I - Connection to server */ return (0); #ifdef HAVE_LIBZ - if (http->coding) + if (http->coding >= _HTTP_CODING_GUNZIP) { do { @@ -2319,21 +1993,20 @@ httpRead2(http_t *http, /* I - Connection to server */ (int)http->stream.avail_in, (int)length)); http->stream.next_out = (Bytef *)buffer; - http->stream.avail_out = length; + http->stream.avail_out = (uInt)length; if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) { DEBUG_printf(("2httpRead2: zerr=%d", zerr)); #ifdef DEBUG - http_debug_hex("2httpRead2", (char *)http->dbuffer, - http->stream.avail_in); + http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } - bytes = length - http->stream.avail_out; + bytes = (ssize_t)(length - http->stream.avail_out); DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", http->stream.avail_in, http->stream.avail_out, @@ -2344,16 +2017,16 @@ httpRead2(http_t *http, /* I - Connection to server */ if (bytes == 0) { - ssize_t buflen = HTTP_MAX_BUFFER - http->stream.avail_in; + ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in; /* Additional bytes for buffer */ 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->sbuffer) + memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); - http->stream.next_in = http->dbuffer; + http->stream.next_in = http->sbuffer; DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into " "decompression buffer.", (int)buflen)); @@ -2361,16 +2034,12 @@ httpRead2(http_t *http, /* I - Connection to server */ if (http->data_remaining > 0) { if (buflen > http->data_remaining) - buflen = http->data_remaining; + buflen = (ssize_t)http->data_remaining; - bytes = http_read_buffered(http, - (char *)http->dbuffer + - http->stream.avail_in, buflen); + bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); } else if (http->data_encoding == HTTP_ENCODING_CHUNKED) - bytes = http_read_chunk(http, - (char *)http->dbuffer + - http->stream.avail_in, buflen); + bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); else bytes = 0; @@ -2379,8 +2048,25 @@ httpRead2(http_t *http, /* I - Connection to server */ else if (bytes == 0) break; + DEBUG_printf(("1httpRead2: Adding " CUPS_LLFMT " bytes to " + "decompression buffer.", CUPS_LLCAST bytes)); + http->data_remaining -= bytes; - http->stream.avail_in += bytes; + http->stream.avail_in += (uInt)bytes; + + if (http->data_remaining <= 0 && + http->data_encoding == HTTP_ENCODING_CHUNKED) + { + /* + * Read the trailing blank line now... + */ + + char len[32]; /* Length string */ + + httpGets(len, sizeof(len), http); + } + + bytes = 0; } else return (0); @@ -2393,7 +2079,20 @@ httpRead2(http_t *http, /* I - Connection to server */ if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) { if ((bytes = http_read_chunk(http, buffer, length)) > 0) + { http->data_remaining -= bytes; + + if (http->data_remaining <= 0) + { + /* + * Read the trailing blank line now... + */ + + char len[32]; /* Length string */ + + httpGets(len, sizeof(len), http); + } + } } else if (http->data_remaining <= 0) { @@ -2408,173 +2107,82 @@ httpRead2(http_t *http, /* I - Connection to server */ DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.", (int)length)); - if (length > http->data_remaining) - length = http->data_remaining; + if (length > (size_t)http->data_remaining) + length = (size_t)http->data_remaining; if ((bytes = http_read_buffered(http, buffer, length)) > 0) + { http->data_remaining -= bytes; + + if (http->data_remaining <= 0 && + http->data_encoding == HTTP_ENCODING_CHUNKED) + { + /* + * Read the trailing blank line now... + */ + + char len[32]; /* Length string */ + + httpGets(len, sizeof(len), http); + } + } } if ( #ifdef HAVE_LIBZ - (http->coding == _HTTP_CODING_IDENTITY || http->stream.avail_in == 0) && + (http->coding == _HTTP_CODING_IDENTITY || + (http->coding >= _HTTP_CODING_GUNZIP && 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))) { #ifdef HAVE_LIBZ - if (http->coding) + if (http->coding >= _HTTP_CODING_GUNZIP) http_content_coding_finish(http); #endif /* HAVE_LIBZ */ if (http->state == HTTP_STATE_POST_RECV) http->state ++; - else + else if (http->state == HTTP_STATE_GET_SEND || + http->state == HTTP_STATE_POST_SEND) http->state = HTTP_STATE_WAITING; + else + http->state = HTTP_STATE_STATUS; DEBUG_printf(("1httpRead2: End of content, set state to %s.", - http_states[http->state + 1])); + httpStateString(http->state))); } return (bytes); } -#if defined(HAVE_SSL) && defined(HAVE_CDSASSL) /* - * '_httpReadCDSA()' - Read function for the CDSA library. + * 'httpReadRequest()' - Read a HTTP request from a connection. + * + * @since CUPS 1.7/macOS 10.9@ */ -OSStatus /* O - -1 on error, 0 on success */ -_httpReadCDSA( - SSLConnectionRef connection, /* I - SSL/TLS connection */ - void *data, /* I - Data buffer */ - size_t *dataLength) /* IO - Number of bytes */ +http_state_t /* O - New state of connection */ +httpReadRequest(http_t *http, /* I - HTTP connection */ + char *uri, /* I - URI buffer */ + size_t urilen) /* I - Size of URI buffer */ { - OSStatus result; /* Return value */ - ssize_t bytes; /* Number of bytes read */ - http_t *http; /* HTTP connection */ + char line[4096], /* HTTP request line */ + *req_method, /* HTTP request method */ + *req_uri, /* HTTP request URI */ + *req_version; /* HTTP request version number string */ - http = (http_t *)connection; + /* + * Range check input... + */ - if (!http->blocking) - { - /* - * Make sure we have data before we read... - */ + DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen)); - while (!_httpWait(http, http->wait_value, 0)) - { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; - - http->error = ETIMEDOUT; - return (-1); - } - } - - do - { - bytes = recv(http->fd, data, *dataLength, 0); - } - while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); - - if (bytes == *dataLength) - { - result = 0; - } - else if (bytes > 0) - { - *dataLength = bytes; - result = errSSLWouldBlock; - } - else - { - *dataLength = 0; - - if (bytes == 0) - result = errSSLClosedGraceful; - else if (errno == EAGAIN) - result = errSSLWouldBlock; - else - result = errSSLClosedAbort; - } - - return (result); -} -#endif /* HAVE_SSL && HAVE_CDSASSL */ - - -#if defined(HAVE_SSL) && defined(HAVE_GNUTLS) -/* - * '_httpReadGNUTLS()' - Read function for the GNU TLS library. - */ - -ssize_t /* O - Number of bytes read or -1 on error */ -_httpReadGNUTLS( - gnutls_transport_ptr ptr, /* I - Connection to server */ - void *data, /* I - Buffer */ - size_t length) /* I - Number of bytes to read */ -{ - http_t *http; /* HTTP connection */ - ssize_t bytes; /* Bytes read */ - - - DEBUG_printf(("6_httpReadGNUTLS(ptr=%p, data=%p, length=%d)", ptr, data, (int)length)); - - http = (http_t *)ptr; - - if (!http->blocking) - { - /* - * Make sure we have data before we read... - */ - - while (!_httpWait(http, http->wait_value, 0)) - { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; - - http->error = ETIMEDOUT; - return (-1); - } - } - - bytes = recv(http->fd, data, length, 0); - DEBUG_printf(("6_httpReadGNUTLS: bytes=%d", (int)bytes)); - return (bytes); -} -#endif /* HAVE_SSL && HAVE_GNUTLS */ - - -/* - * 'httpReadRequest()' - Read a HTTP request from a connection. - * - * @since CUPS 1.7@ - */ - -http_state_t /* O - New state of connection */ -httpReadRequest(http_t *http, /* I - HTTP connection */ - char *uri, /* I - URI buffer */ - size_t urilen) /* I - Size of URI buffer */ -{ - char line[4096], /* HTTP request line */ - *req_method, /* HTTP request method */ - *req_uri, /* HTTP request URI */ - *req_version; /* HTTP request version number string */ - - - /* - * Range check input... - */ - - DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", - http, uri, CUPS_LLCAST urilen)); - - if (uri) - *uri = '\0'; + if (uri) + *uri = '\0'; if (!http || !uri || urilen < 1) { @@ -2584,7 +2192,7 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ else if (http->state != HTTP_STATE_WAITING) { DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.", - http_states[http->state + 1])); + httpStateString(http->state))); return (HTTP_STATE_ERROR); } @@ -2632,6 +2240,7 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ if (!*req_uri) { DEBUG_puts("1httpReadRequest: No request URI."); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1); return (HTTP_STATE_ERROR); } @@ -2648,6 +2257,7 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ if (!*req_version) { DEBUG_puts("1httpReadRequest: No request protocol version."); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1); return (HTTP_STATE_ERROR); } @@ -2679,11 +2289,12 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ else { DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method)); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1); return (HTTP_STATE_UNKNOWN_METHOD); } DEBUG_printf(("1httpReadRequest: Set state to %s.", - http_states[http->state + 1])); + httpStateString(http->state))); if (!strcmp(req_version, "HTTP/1.0")) { @@ -2698,6 +2309,7 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ else { DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version)); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1); return (HTTP_STATE_UNKNOWN_VERSION); } @@ -2718,9 +2330,9 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ */ int /* O - 0 on success, non-zero on failure */ -httpReconnect(http_t *http) /* I - Connection to server */ +httpReconnect(http_t *http) /* I - HTTP connection */ { - DEBUG_printf(("httpReconnect(http=%p)", http)); + DEBUG_printf(("httpReconnect(http=%p)", (void *)http)); return (httpReconnect2(http, 30000, NULL)); } @@ -2732,7 +2344,7 @@ httpReconnect(http_t *http) /* I - Connection to server */ */ int /* O - 0 on success, non-zero on failure */ -httpReconnect2(http_t *http, /* I - Connection to server */ +httpReconnect2(http_t *http, /* I - HTTP connection */ int msec, /* I - Timeout in milliseconds */ int *cancel) /* I - Pointer to "cancel" variable */ { @@ -2743,12 +2355,11 @@ httpReconnect2(http_t *http, /* I - Connection to server */ #endif /* DEBUG */ - DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", http, msec, - cancel)); + DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel)); if (!http) { - _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (-1); } @@ -2756,7 +2367,7 @@ httpReconnect2(http_t *http, /* I - Connection to server */ if (http->tls) { DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS..."); - http_shutdown_ssl(http); + _httpTLSStop(http); } #endif /* HAVE_SSL */ @@ -2768,11 +2379,7 @@ httpReconnect2(http_t *http, /* I - Connection to server */ { DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd)); -#ifdef WIN32 - closesocket(http->fd); -#else - close(http->fd); -#endif /* WIN32 */ + httpAddrClose(NULL, http->fd); http->fd = -1; } @@ -2782,14 +2389,12 @@ httpReconnect2(http_t *http, /* I - Connection to server */ */ http->state = HTTP_STATE_WAITING; - http->status = HTTP_STATUS_CONTINUE; http->version = HTTP_VERSION_1_1; http->keep_alive = HTTP_KEEPALIVE_OFF; memset(&http->_hostaddr, 0, sizeof(http->_hostaddr)); http->data_encoding = HTTP_ENCODING_FIELDS; http->_data_remaining = 0; http->used = 0; - http->expect = 0; http->data_remaining = 0; http->hostaddr = NULL; http->wused = 0; @@ -2805,8 +2410,7 @@ httpReconnect2(http_t *http, /* I - Connection to server */ httpAddrPort(&(current->addr)))); #endif /* DEBUG */ - if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, - cancel)) == NULL) + if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL) { /* * Unable to connect... @@ -2817,7 +2421,7 @@ httpReconnect2(http_t *http, /* I - Connection to server */ #else http->error = errno; #endif /* WIN32 */ - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s", strerror(http->error))); @@ -2834,25 +2438,21 @@ httpReconnect2(http_t *http, /* I - Connection to server */ http->error = 0; #ifdef HAVE_SSL - if (http->encryption == HTTP_ENCRYPT_ALWAYS) + if (http->encryption == HTTP_ENCRYPTION_ALWAYS) { /* * Always do encryption via SSL. */ - if (http_setup_ssl(http) != 0) + if (_httpTLSStart(http) != 0) { -# ifdef WIN32 - closesocket(http->fd); -# else - close(http->fd); -# endif /* WIN32 */ + httpAddrClose(NULL, http->fd); return (-1); } } - else if (http->encryption == HTTP_ENCRYPT_REQUIRED) - return (http_upgrade(http)); + else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade) + return (http_tls_upgrade(http)); #endif /* HAVE_SSL */ DEBUG_printf(("1httpReconnect2: Connected to %s:%d...", @@ -2871,11 +2471,11 @@ httpReconnect2(http_t *http, /* I - Connection to server */ * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(), * httpHead(), httpOptions(), httpPost, or httpPut(). * - * @since CUPS 1.3/OS X 10.5@ + * @since CUPS 1.3/macOS 10.5@ */ void -httpSetAuthString(http_t *http, /* I - Connection to server */ +httpSetAuthString(http_t *http, /* I - HTTP connection */ const char *scheme, /* I - Auth scheme (NULL to clear it) */ const char *data) /* I - Auth data (NULL for none) */ { @@ -2897,10 +2497,10 @@ httpSetAuthString(http_t *http, /* I - Connection to server */ * Set the current authorization string... */ - int len = (int)strlen(scheme) + (data ? (int)strlen(data) + 1 : 0) + 1; + size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1; char *temp; - if (len > (int)sizeof(http->_authstring)) + if (len > sizeof(http->_authstring)) { if ((temp = malloc(len)) == NULL) len = sizeof(http->_authstring); @@ -2928,19 +2528,21 @@ httpSetAuthString(http_t *http, /* I - Connection to server */ * 'httpSetCredentials()' - Set the credentials associated with an encrypted * connection. * - * @since CUPS 1.5/OS X 10.7@ + * @since CUPS 1.5/macOS 10.7@ */ int /* O - Status of call (0 = success) */ -httpSetCredentials(http_t *http, /* I - Connection to server */ +httpSetCredentials(http_t *http, /* I - HTTP connection */ cups_array_t *credentials) /* I - Array of credentials */ { if (!http || cupsArrayCount(credentials) < 1) return (-1); +#ifdef HAVE_SSL _httpFreeCredentials(http->tls_credentials); http->tls_credentials = _httpCreateCredentials(credentials); +#endif /* HAVE_SSL */ return (http->tls_credentials ? 0 : -1); } @@ -2949,7 +2551,7 @@ httpSetCredentials(http_t *http, /* I - Connection to server */ /* * 'httpSetCookie()' - Set the cookie value(s). * - * @since CUPS 1.1.19/OS X 10.3@ + * @since CUPS 1.1.19/macOS 10.3@ */ void @@ -2972,19 +2574,18 @@ httpSetCookie(http_t *http, /* I - Connection */ /* * 'httpSetDefaultField()' - Set the default value of an HTTP header. * - * Currently only HTTP_FIELD_ACCEPT_ENCODING, HTTP_FIELD_SERVER, and - * HTTP_FIELD_USER_AGENT can be set. + * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@, + * and @code HTTP_FIELD_USER_AGENT@ can be set. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ void -httpSetDefaultField(http_t *http, /* I - Connection to server */ +httpSetDefaultField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value)/* I - Value */ { - DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", - http, field, http_fields[field], value)); + DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value)); if (!http) return; @@ -3025,14 +2626,16 @@ httpSetDefaultField(http_t *http, /* I - Connection to server */ * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect" * argument. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ void -httpSetExpect(http_t *http, /* I - Connection to server */ +httpSetExpect(http_t *http, /* I - HTTP connection */ http_status_t expect) /* I - HTTP status to expect - (@code HTTP_CONTINUE@) */ + (@code HTTP_STATUS_CONTINUE@) */ { + DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect)); + if (http) http->expect = expect; } @@ -3043,12 +2646,11 @@ httpSetExpect(http_t *http, /* I - Connection to server */ */ void -httpSetField(http_t *http, /* I - Connection to server */ +httpSetField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *value) /* I - Value */ { - DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", http, - field, http_fields[field], value)); + DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value)); if (http == NULL || field < HTTP_FIELD_ACCEPT_LANGUAGE || @@ -3079,6 +2681,19 @@ httpSetField(http_t *http, /* I - Connection to server */ http->server = _cupsStrAlloc(value); break; + case HTTP_FIELD_WWW_AUTHENTICATE : + /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */ + if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] && + _cups_strncasecmp(value, "Basic ", 6) && + _cups_strncasecmp(value, "Digest ", 7) && + _cups_strncasecmp(value, "Negotiate ", 10)) + { + DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value)); + return; + } + + /* Fall through to copy */ + default : strlcpy(http->fields[field], value, HTTP_MAX_VALUE); break; @@ -3145,18 +2760,33 @@ httpSetField(http_t *http, /* I - Connection to server */ } +/* + * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection. + * + * @since CUPS 2.0/OS 10.10@ + */ + +void +httpSetKeepAlive( + http_t *http, /* I - HTTP connection */ + http_keepalive_t keep_alive) /* I - New Keep-Alive value */ +{ + if (http) + http->keep_alive = keep_alive; +} + + /* * 'httpSetLength()' - Set the content-length and content-encoding. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ void -httpSetLength(http_t *http, /* I - Connection to server */ +httpSetLength(http_t *http, /* I - HTTP connection */ size_t length) /* I - Length (0 for chunked) */ { - DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", http, - CUPS_LLCAST length)); + DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length)); if (!http) return; @@ -3182,12 +2812,12 @@ httpSetLength(http_t *http, /* I - Connection to server */ * The optional timeout callback receives both the HTTP connection and a user * data pointer and must return 1 to continue or 0 to error (time) out. * - * @since CUPS 1.5/OS X 10.7@ + * @since CUPS 1.5/macOS 10.7@ */ void httpSetTimeout( - http_t *http, /* I - Connection to server */ + http_t *http, /* I - HTTP connection */ double timeout, /* I - Number of seconds for timeout, must be greater than 0 */ http_timeout_cb_t cb, /* I - Callback function or NULL */ @@ -3207,15 +2837,40 @@ httpSetTimeout( } +/* + * 'httpShutdown()' - Shutdown one side of an HTTP connection. + * + * @since CUPS 2.0/OS 10.10@ + */ + +void +httpShutdown(http_t *http) /* I - HTTP connection */ +{ + if (!http || http->fd < 0) + return; + +#ifdef HAVE_SSL + if (http->tls) + _httpTLSStop(http); +#endif /* HAVE_SSL */ + +#ifdef WIN32 + shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */ +#else + shutdown(http->fd, SHUT_RD); +#endif /* WIN32 */ +} + + /* * 'httpTrace()' - Send an TRACE request to the server. */ int /* O - Status of call (0 = success) */ -httpTrace(http_t *http, /* I - Connection to server */ +httpTrace(http_t *http, /* I - HTTP connection */ const char *uri) /* I - URI for trace */ { - return (http_send(http, HTTP_TRACE, uri)); + return (http_send(http, HTTP_STATE_TRACE, uri)); } @@ -3227,7 +2882,7 @@ httpTrace(http_t *http, /* I - Connection to server */ */ int /* O - 1 to continue, 0 to stop */ -_httpUpdate(http_t *http, /* I - Connection to server */ +_httpUpdate(http_t *http, /* I - HTTP connection */ http_status_t *status) /* O - Current HTTP status */ { char line[32768], /* Line from connection... */ @@ -3236,8 +2891,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ int major, minor; /* HTTP version numbers */ - DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", http, status, - http_states[http->state + 1])); + DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state))); /* * Grab a single line from the connection... @@ -3245,7 +2899,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ if (!httpGets(line, sizeof(line), http)) { - *status = HTTP_ERROR; + *status = HTTP_STATUS_ERROR; return (0); } @@ -3268,21 +2922,17 @@ _httpUpdate(http_t *http, /* I - Connection to server */ return (0); } - if (http->status < HTTP_BAD_REQUEST) + if (http->status < HTTP_STATUS_BAD_REQUEST) http->digest_tries = 0; #ifdef HAVE_SSL - if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) + if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls) { - if (http_setup_ssl(http) != 0) + if (_httpTLSStart(http) != 0) { -# ifdef WIN32 - closesocket(http->fd); -# else - close(http->fd); -# endif /* WIN32 */ + httpAddrClose(NULL, http->fd); - *status = http->status = HTTP_ERROR; + *status = http->status = HTTP_STATUS_ERROR; return (0); } @@ -3295,7 +2945,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ { DEBUG_puts("1_httpUpdate: Bad Content-Length."); http->error = EINVAL; - http->status = *status = HTTP_ERROR; + http->status = *status = HTTP_STATUS_ERROR; return (0); } @@ -3308,7 +2958,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ http->state ++; DEBUG_printf(("1_httpUpdate: Set state to %s.", - http_states[http->state + 1])); + httpStateString(http->state))); case HTTP_STATE_POST_SEND : case HTTP_STATE_HEAD : @@ -3317,8 +2967,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ default : http->state = HTTP_STATE_WAITING; - DEBUG_puts("1_httpUpdate: Unknown state, reset state to " - "HTTP_STATE_WAITING."); + DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING."); break; } @@ -3331,7 +2980,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ *status = http->status; return (0); } - else if (!strncmp(line, "HTTP/", 5)) + else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT) { /* * Got the beginning of a response... @@ -3341,7 +2990,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3) { - *status = http->status = HTTP_ERROR; + *status = http->status = HTTP_STATUS_ERROR; return (0); } @@ -3382,7 +3031,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ httpSetCookie(http, value); } - else if ((field = http_field(line)) != HTTP_FIELD_UNKNOWN) + else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN) httpSetField(http, field, value); #ifdef DEBUG else @@ -3393,7 +3042,7 @@ _httpUpdate(http_t *http, /* I - Connection to server */ { DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line)); http->error = EINVAL; - http->status = *status = HTTP_ERROR; + http->status = *status = HTTP_STATUS_ERROR; return (0); } @@ -3406,13 +3055,12 @@ _httpUpdate(http_t *http, /* I - Connection to server */ */ http_status_t /* O - HTTP status */ -httpUpdate(http_t *http) /* I - Connection to server */ +httpUpdate(http_t *http) /* I - HTTP connection */ { http_status_t status; /* Request status */ - DEBUG_printf(("httpUpdate(http=%p), state=%s", http, - http_states[http->state + 1])); + DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state))); /* * Flush pending data, if any... @@ -3423,7 +3071,7 @@ httpUpdate(http_t *http) /* I - Connection to server */ DEBUG_puts("2httpUpdate: flushing buffer..."); if (httpFlushWrite(http) < 0) - return (HTTP_ERROR); + return (HTTP_STATUS_ERROR); } /* @@ -3431,7 +3079,7 @@ httpUpdate(http_t *http) /* I - Connection to server */ */ if (http->state == HTTP_STATE_WAITING) - return (HTTP_CONTINUE); + return (HTTP_STATUS_CONTINUE); /* * Grab all of the lines we can from the connection... @@ -3443,7 +3091,7 @@ httpUpdate(http_t *http) /* I - Connection to server */ * See if there was an error... */ - if (http->error == EPIPE && http->status > HTTP_CONTINUE) + if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE) { DEBUG_printf(("1httpUpdate: Returning status %d...", http->status)); return (http->status); @@ -3453,8 +3101,8 @@ httpUpdate(http_t *http) /* I - Connection to server */ { DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error, strerror(http->error))); - http->status = HTTP_ERROR; - return (HTTP_ERROR); + http->status = HTTP_STATUS_ERROR; + return (HTTP_STATUS_ERROR); } /* @@ -3470,7 +3118,7 @@ httpUpdate(http_t *http) /* I - Connection to server */ */ int /* O - 1 if data is available, 0 otherwise */ -_httpWait(http_t *http, /* I - Connection to server */ +_httpWait(http_t *http, /* I - HTTP connection */ int msec, /* I - Milliseconds to wait */ int usessl) /* I - Use SSL context? */ { @@ -3483,7 +3131,7 @@ _httpWait(http_t *http, /* I - Connection to server */ int nfds; /* Result from select()/poll() */ - DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", http, msec, usessl)); + DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl)); if (http->fd < 0) { @@ -3496,32 +3144,10 @@ _httpWait(http_t *http, /* I - Connection to server */ */ #ifdef HAVE_SSL - if (http->tls && usessl) + if (http->tls && _httpTLSPending(http)) { -# ifdef HAVE_LIBSSL - if (SSL_pending(http->tls)) - { - DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data."); - return (1); - } - -# elif defined(HAVE_GNUTLS) - if (gnutls_record_check_pending(http->tls)) - { - DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data."); - return (1); - } - -# elif defined(HAVE_CDSASSL) - size_t bytes; /* Bytes that are available */ - - if (!SSLGetBufferedReadSize(http->tls, &bytes) && - bytes > 0) - { - DEBUG_puts("5_httpWait: Return 1 since there is pending SSL data."); - return (1); - } -# endif /* HAVE_LIBSSL */ + DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data."); + return (1); } #endif /* HAVE_SSL */ @@ -3577,18 +3203,18 @@ _httpWait(http_t *http, /* I - Connection to server */ /* * 'httpWait()' - Wait for data available on a connection. * - * @since CUPS 1.1.19/OS X 10.3@ + * @since CUPS 1.1.19/macOS 10.3@ */ int /* O - 1 if data is available, 0 otherwise */ -httpWait(http_t *http, /* I - Connection to server */ +httpWait(http_t *http, /* I - HTTP connection */ int msec) /* I - Milliseconds to wait */ { /* * First see if there is data in the buffer... */ - DEBUG_printf(("2httpWait(http=%p, msec=%d)", http, msec)); + DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec)); if (http == NULL) return (0); @@ -3637,30 +3263,29 @@ httpWait(http_t *http, /* I - Connection to server */ */ int /* O - Number of bytes written */ -httpWrite(http_t *http, /* I - Connection to server */ +httpWrite(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ int length) /* I - Number of bytes to write */ { - return ((int)httpWrite2(http, buffer, length)); + return ((int)httpWrite2(http, buffer, (size_t)length)); } /* * 'httpWrite2()' - Write data to a HTTP connection. * - * @since CUPS 1.2/OS X 10.5@ + * @since CUPS 1.2/macOS 10.5@ */ ssize_t /* O - Number of bytes written */ -httpWrite2(http_t *http, /* I - Connection to server */ +httpWrite2(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { ssize_t bytes; /* Bytes written */ - DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http, - buffer, CUPS_LLCAST length)); + DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); /* * Range check input... @@ -3683,7 +3308,7 @@ httpWrite2(http_t *http, /* I - Connection to server */ */ #ifdef HAVE_LIBZ - if (http->coding) + if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) { DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding)); @@ -3694,37 +3319,48 @@ httpWrite2(http_t *http, /* I - Connection to server */ } else { + size_t slen; /* Bytes to write */ + ssize_t sret; /* Bytes written */ + http->stream.next_in = (Bytef *)buffer; - http->stream.avail_in = length; - http->stream.next_out = (Bytef *)http->wbuffer + http->wused; - http->stream.avail_out = sizeof(http->wbuffer) - http->wused; + http->stream.avail_in = (uInt)length; while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK) { - http->wused = sizeof(http->wbuffer) - http->stream.avail_out; + DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out)); - if (http->stream.avail_out == 0) - { - if (httpFlushWrite(http) < 0) - { - DEBUG_puts("1httpWrite2: Unable to flush, returning -1."); - return (-1); - } + if (http->stream.avail_out > 0) + continue; + + slen = _HTTP_MAX_SBUFFER - http->stream.avail_out; + + DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen)); - http->stream.next_out = (Bytef *)http->wbuffer; - http->stream.avail_out = sizeof(http->wbuffer); + if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) + sret = http_write_chunk(http, (char *)http->sbuffer, slen); + else if (slen > 0) + sret = http_write(http, (char *)http->sbuffer, slen); + else + sret = 0; + + if (sret < 0) + { + DEBUG_puts("1httpWrite2: Unable to write, returning -1."); + return (-1); } + + http->stream.next_out = (Bytef *)http->sbuffer; + http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; } - http->wused = sizeof(http->wbuffer) - http->stream.avail_out; - bytes = length; + bytes = (ssize_t)length; } } else #endif /* HAVE_LIBZ */ if (length > 0) { - if (http->wused && (length + http->wused) > sizeof(http->wbuffer)) + if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer)) { DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length=" CUPS_LLFMT ")", http->wused, CUPS_LLCAST length)); @@ -3732,8 +3368,7 @@ httpWrite2(http_t *http, /* I - Connection to server */ httpFlushWrite(http); } - if ((length + http->wused) <= sizeof(http->wbuffer) && - length < sizeof(http->wbuffer)) + if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer)) { /* * Write to buffer... @@ -3756,9 +3391,9 @@ httpWrite2(http_t *http, /* I - Connection to server */ CUPS_LLCAST length)); if (http->data_encoding == HTTP_ENCODING_CHUNKED) - bytes = (ssize_t)http_write_chunk(http, buffer, (int)length); + bytes = (ssize_t)http_write_chunk(http, buffer, length); else - bytes = (ssize_t)http_write(http, buffer, (int)length); + bytes = (ssize_t)http_write(http, buffer, length); DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...", CUPS_LLCAST bytes)); @@ -3782,6 +3417,11 @@ httpWrite2(http_t *http, /* I - Connection to server */ * data, go idle... */ +#ifdef HAVE_LIBZ + if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE) + http_content_coding_finish(http); +#endif /* HAVE_LIBZ */ + if (http->wused) { if (httpFlushWrite(http) < 0) @@ -3805,17 +3445,15 @@ httpWrite2(http_t *http, /* I - Connection to server */ } if (http->state == HTTP_STATE_POST_RECV) - { -#ifdef HAVE_LIBZ - if (http->coding) - http_content_coding_finish(http); -#endif /* HAVE_LIBZ */ - http->state ++; + else if (http->state == HTTP_STATE_POST_SEND || + http->state == HTTP_STATE_GET_SEND) + http->state = HTTP_STATE_WAITING; + else + http->state = HTTP_STATE_STATUS; - DEBUG_printf(("2httpWrite2: Changed state to %s.", - http_states[http->state + 1])); - } + DEBUG_printf(("2httpWrite2: Changed state to %s.", + httpStateString(http->state))); } DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes)); @@ -3824,86 +3462,10 @@ httpWrite2(http_t *http, /* I - Connection to server */ } -#if defined(HAVE_SSL) && defined(HAVE_CDSASSL) -/* - * '_httpWriteCDSA()' - Write function for the CDSA library. - */ - -OSStatus /* O - -1 on error, 0 on success */ -_httpWriteCDSA( - SSLConnectionRef connection, /* I - SSL/TLS connection */ - const void *data, /* I - Data buffer */ - size_t *dataLength) /* IO - Number of bytes */ -{ - OSStatus result; /* Return value */ - ssize_t bytes; /* Number of bytes read */ - http_t *http; /* HTTP connection */ - - - http = (http_t *)connection; - - do - { - bytes = write(http->fd, data, *dataLength); - } - while (bytes == -1 && (errno == EINTR || errno == EAGAIN)); - - if (bytes == *dataLength) - { - result = 0; - } - else if (bytes >= 0) - { - *dataLength = bytes; - result = errSSLWouldBlock; - } - else - { - *dataLength = 0; - - if (errno == EAGAIN) - result = errSSLWouldBlock; - else - result = errSSLClosedAbort; - } - - return (result); -} -#endif /* HAVE_SSL && HAVE_CDSASSL */ - - -#if defined(HAVE_SSL) && defined(HAVE_GNUTLS) -/* - * '_httpWriteGNUTLS()' - Write function for the GNU TLS library. - */ - -ssize_t /* O - Number of bytes written or -1 on error */ -_httpWriteGNUTLS( - gnutls_transport_ptr ptr, /* I - Connection to server */ - const void *data, /* I - Data buffer */ - size_t length) /* I - Number of bytes to write */ -{ - ssize_t bytes; /* Bytes written */ - - - DEBUG_printf(("6_httpWriteGNUTLS(ptr=%p, data=%p, length=%d)", ptr, data, - (int)length)); -#ifdef DEBUG - http_debug_hex("_httpWriteGNUTLS", data, (int)length); -#endif /* DEBUG */ - - bytes = send(((http_t *)ptr)->fd, data, length, 0); - DEBUG_printf(("_httpWriteGNUTLS: bytes=%d", (int)bytes)); - - return (bytes); -} -#endif /* HAVE_SSL && HAVE_GNUTLS */ - - /* * 'httpWriteResponse()' - Write a HTTP response to a client connection. * - * @since CUPS 1.7@ + * @since CUPS 1.7/macOS 10.9@ */ int /* O - 0 on success, -1 on error */ @@ -3918,7 +3480,7 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ * Range check input... */ - DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", http, status)); + DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status)); if (!http || status < HTTP_STATUS_CONTINUE) { @@ -3933,9 +3495,9 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ if (!http->fields[HTTP_FIELD_DATE][0]) httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL))); - if (status >= HTTP_BAD_REQUEST && http->keep_alive) + if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive) { - http->keep_alive = 0; + http->keep_alive = HTTP_KEEPALIVE_OFF; httpSetField(http, HTTP_FIELD_KEEP_ALIVE, ""); } @@ -3954,13 +3516,17 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ } #ifdef HAVE_SSL - if (status == HTTP_STATUS_UPGRADE_REQUIRED) + if (status == HTTP_STATUS_UPGRADE_REQUIRED || + status == HTTP_STATUS_SWITCHING_PROTOCOLS) { if (!http->fields[HTTP_FIELD_CONNECTION][0]) httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); if (!http->fields[HTTP_FIELD_UPGRADE][0]) httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); + + if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0]) + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0"); } #endif /* HAVE_SSL */ @@ -4019,28 +3585,47 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ if (http->cookie) { - if (httpPrintf(http, "Set-Cookie: %s path=/%s\r\n", http->cookie, - http->tls ? " secure" : "") < 1) + if (strchr(http->cookie, ';')) + { + if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1) + { + http->status = HTTP_STATUS_ERROR; + return (-1); + } + } + else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } } + + /* + * "Click-jacking" defense (STR #4492)... + */ + + if (httpPrintf(http, "X-Frame-Options: DENY\r\n" + "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1) + { + http->status = HTTP_STATUS_ERROR; + return (-1); + } } if (httpWrite2(http, "\r\n", 2) < 2) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } if (httpFlushWrite(http) < 0) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } - if (status == HTTP_STATUS_CONTINUE) + if (status == HTTP_STATUS_CONTINUE || + status == HTTP_STATUS_SWITCHING_PROTOCOLS) { /* * Restore the old data_encoding and data_length values... @@ -4058,10 +3643,11 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ http->state == HTTP_STATE_HEAD || http->state == HTTP_STATE_PUT || http->state == HTTP_STATE_TRACE || - http->state == HTTP_STATE_CONNECT) + http->state == HTTP_STATE_CONNECT || + http->state == HTTP_STATE_STATUS) { DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " - "was %s.", http_states[http->state + 1])); + "was %s.", httpStateString(http->state))); http->state = HTTP_STATE_WAITING; } else @@ -4073,6 +3659,15 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ http_set_length(http); + if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0) + { + DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, " + "was %s.", httpStateString(http->state))); + http->state = HTTP_STATE_WAITING; + return (0); + } + +#ifdef HAVE_LIBZ /* * Then start any content encoding... */ @@ -4080,201 +3675,72 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start."); http_content_coding_start(http, httpGetField(http, HTTP_FIELD_CONTENT_ENCODING)); +#endif /* HAVE_LIBZ */ + } return (0); } -#if defined(HAVE_SSL) && defined(HAVE_LIBSSL) +#ifdef HAVE_LIBZ /* - * 'http_bio_ctrl()' - Control the HTTP connection. + * 'http_content_coding_finish()' - Finish doing any content encoding. */ -static long /* O - Result/data */ -http_bio_ctrl(BIO *h, /* I - BIO data */ - int cmd, /* I - Control command */ - long arg1, /* I - First argument */ - void *arg2) /* I - Second argument */ +static void +http_content_coding_finish( + http_t *http) /* I - HTTP connection */ { - switch (cmd) - { - default : - return (0); + int zerr; /* Compression status */ + Byte dummy[1]; /* Dummy read buffer */ + size_t bytes; /* Number of bytes to write */ - case BIO_CTRL_RESET : - h->ptr = NULL; - return (0); - case BIO_C_SET_FILE_PTR : - h->ptr = arg2; - h->init = 1; - return (1); + DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http)); + DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding)); - case BIO_C_GET_FILE_PTR : - if (arg2) - { - *((void **)arg2) = h->ptr; - return (1); - } - else - return (0); + switch (http->coding) + { + case _HTTP_CODING_DEFLATE : + case _HTTP_CODING_GZIP : + http->stream.next_in = dummy; + http->stream.avail_in = 0; - case BIO_CTRL_DUP : - case BIO_CTRL_FLUSH : - return (1); - } -} + do + { + zerr = deflate(&(http->stream), Z_FINISH); + bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out; + if (bytes > 0) + { + DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes)); -/* - * 'http_bio_free()' - Free OpenSSL data. - */ + if (http->data_encoding == HTTP_ENCODING_CHUNKED) + http_write_chunk(http, (char *)http->sbuffer, bytes); + else + http_write(http, (char *)http->sbuffer, bytes); + } -static int /* O - 1 on success, 0 on failure */ -http_bio_free(BIO *h) /* I - BIO data */ -{ - if (!h) - return (0); + http->stream.next_out = (Bytef *)http->sbuffer; + http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; + } + while (zerr == Z_OK); - if (h->shutdown) - { - h->init = 0; - h->flags = 0; - } + deflateEnd(&(http->stream)); - return (1); -} + free(http->sbuffer); + http->sbuffer = NULL; - -/* - * 'http_bio_new()' - Initialize an OpenSSL BIO structure. - */ - -static int /* O - 1 on success, 0 on failure */ -http_bio_new(BIO *h) /* I - BIO data */ -{ - if (!h) - return (0); - - h->init = 0; - h->num = 0; - h->ptr = NULL; - h->flags = 0; - - return (1); -} - - -/* - * 'http_bio_puts()' - Send a string for OpenSSL. - */ - -static int /* O - Bytes written */ -http_bio_puts(BIO *h, /* I - BIO data */ - const char *str) /* I - String to write */ -{ -#ifdef WIN32 - return (send(((http_t *)h->ptr)->fd, str, (int)strlen(str), 0)); -#else - return (send(((http_t *)h->ptr)->fd, str, strlen(str), 0)); -#endif /* WIN32 */ -} - - -/* - * 'http_bio_read()' - Read data for OpenSSL. - */ - -static int /* O - Bytes read */ -http_bio_read(BIO *h, /* I - BIO data */ - char *buf, /* I - Buffer */ - int size) /* I - Number of bytes to read */ -{ - http_t *http; /* HTTP connection */ - - - http = (http_t *)h->ptr; - - if (!http->blocking) - { - /* - * Make sure we have data before we read... - */ - - while (!_httpWait(http, http->wait_value, 0)) - { - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) - continue; - -#ifdef WIN32 - http->error = WSAETIMEDOUT; -#else - http->error = ETIMEDOUT; -#endif /* WIN32 */ - - return (-1); - } - } - - return (recv(http->fd, buf, size, 0)); -} - - -/* - * 'http_bio_write()' - Write data for OpenSSL. - */ - -static int /* O - Bytes written */ -http_bio_write(BIO *h, /* I - BIO data */ - const char *buf, /* I - Buffer to write */ - int num) /* I - Number of bytes to write */ -{ - return (send(((http_t *)h->ptr)->fd, buf, num, 0)); -} -#endif /* HAVE_SSL && HAVE_LIBSSL */ - - -#ifdef HAVE_LIBZ -/* - * 'http_content_coding_finish()' - Finish doing any content encoding. - */ - -static void -http_content_coding_finish( - http_t *http) /* I - HTTP connection */ -{ - int zerr; /* Compression status */ - - - switch (http->coding) - { - case _HTTP_CODING_DEFLATE : - case _HTTP_CODING_GZIP : - do - { - http->stream.next_out = (Bytef *)http->wbuffer + http->wused; - http->stream.avail_out = sizeof(http->wbuffer) - http->wused; - - zerr = deflate(&(http->stream), Z_FINISH); - - http->wused = sizeof(http->wbuffer) - http->stream.avail_out; - if (http->wused == sizeof(http->wbuffer)) - httpFlushWrite(http); - } - while (zerr == Z_OK); - - deflateEnd(&(http->stream)); - - if (http->wused) - httpFlushWrite(http); - break; + if (http->wused) + httpFlushWrite(http); + break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : inflateEnd(&(http->stream)); - free(http->dbuffer); - http->dbuffer = NULL; + free(http->sbuffer); + http->sbuffer = NULL; break; default : @@ -4298,8 +3764,7 @@ http_content_coding_start( _http_coding_t coding; /* Content coding value */ - DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", http, - value)); + DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value)); if (http->coding != _HTTP_CODING_IDENTITY) { @@ -4309,10 +3774,12 @@ http_content_coding_start( } else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip")) { - if (http->state == HTTP_GET_SEND || http->state == HTTP_POST_SEND) + if (http->state == HTTP_STATE_GET_SEND || + http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; - else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_PUT_RECV) + else if (http->state == HTTP_STATE_POST_RECV || + http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP : _HTTP_CODING_GUNZIP; else @@ -4323,10 +3790,12 @@ http_content_coding_start( } else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate")) { - if (http->state == HTTP_GET_SEND || http->state == HTTP_POST_SEND) + if (http->state == HTTP_STATE_GET_SEND || + http->state == HTTP_STATE_POST_SEND) coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; - else if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_PUT_RECV) + else if (http->state == HTTP_STATE_POST_RECV || + http->state == HTTP_STATE_PUT_RECV) coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE : _HTTP_CODING_INFLATE; else @@ -4350,39 +3819,60 @@ http_content_coding_start( if (http->wused) httpFlushWrite(http); + if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) + { + http->status = HTTP_STATUS_ERROR; + http->error = errno; + return; + } + + /* + * Window size for compression is 11 bits - optimal based on PWG Raster + * sample files on pwg.org. -11 is raw deflate, 27 is gzip, per ZLIB + * documentation. + */ + if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION, Z_DEFLATED, - coding == _HTTP_CODING_DEFLATE ? 11 : 27, 7, + coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK) { - http->status = HTTP_ERROR; + 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; break; case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : - if ((http->dbuffer = malloc(HTTP_MAX_BUFFER)) == NULL) + if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; http->error = errno; return; } + /* + * Window size for decompression is up to 15 bits (maximum supported). + * -15 is raw inflate, 31 is gunzip, per ZLIB documentation. + */ + if ((zerr = inflateInit2(&(http->stream), - coding == _HTTP_CODING_INFLATE ? 15 : 31)) + coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK) { - free(http->dbuffer); - http->dbuffer = NULL; - http->status = HTTP_ERROR; + free(http->sbuffer); + http->sbuffer = 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->dbuffer; + http->stream.next_in = http->sbuffer; break; default : @@ -4397,6 +3887,95 @@ http_content_coding_start( #endif /* HAVE_LIBZ */ +/* + * 'http_create()' - Create an unconnected HTTP connection. + */ + +static http_t * /* O - HTTP connection */ +http_create( + const char *host, /* I - Hostname */ + int port, /* I - Port number */ + http_addrlist_t *addrlist, /* I - Address list or NULL */ + int family, /* I - Address family or AF_UNSPEC */ + http_encryption_t encryption, /* I - Encryption to use */ + int blocking, /* I - 1 for blocking mode */ + _http_mode_t mode) /* I - _HTTP_MODE_CLIENT or _SERVER */ +{ + http_t *http; /* New HTTP connection */ + char service[255]; /* Service name */ + http_addrlist_t *myaddrlist = NULL; /* My address list */ + + + DEBUG_printf(("4http_create(host=\"%s\", port=%d, addrlist=%p, family=%d, encryption=%d, blocking=%d, mode=%d)", host, port, (void *)addrlist, family, encryption, blocking, mode)); + + if (!host && mode == _HTTP_MODE_CLIENT) + return (NULL); + + httpInitialize(); + + /* + * Lookup the host... + */ + + if (addrlist) + { + myaddrlist = httpAddrCopyList(addrlist); + } + else + { + snprintf(service, sizeof(service), "%d", port); + + myaddrlist = httpAddrGetList(host, family, service); + } + + if (!myaddrlist) + return (NULL); + + /* + * Allocate memory for the structure... + */ + + if ((http = calloc(sizeof(http_t), 1)) == NULL) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); + httpAddrFreeList(addrlist); + return (NULL); + } + + /* + * Initialize the HTTP data... + */ + + http->mode = mode; + http->activity = time(NULL); + http->addrlist = myaddrlist; + http->blocking = blocking; + http->fd = -1; +#ifdef HAVE_GSSAPI + http->gssctx = GSS_C_NO_CONTEXT; + http->gssname = GSS_C_NO_NAME; +#endif /* HAVE_GSSAPI */ + http->status = HTTP_STATUS_CONTINUE; + http->version = HTTP_VERSION_1_1; + + if (host) + strlcpy(http->hostname, host, sizeof(http->hostname)); + + if (port == 443) /* Always use encryption for https */ + http->encryption = HTTP_ENCRYPTION_ALWAYS; + else + http->encryption = encryption; + + http_set_wait(http); + + /* + * Return the new structure... + */ + + return (http); +} + + #ifdef DEBUG /* * 'http_debug_hex()' - Do a hex dump of a buffer. @@ -4425,7 +4004,7 @@ http_debug_hex(const char *prefix, /* I - Prefix for line */ for (i = 0; i < bytes; i += 16) { for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2) - sprintf(ptr, "%02X", buffer[i + j] & 255); + snprintf(ptr, 3, "%02X", buffer[i + j] & 255); while (j < 16) { @@ -4444,7 +4023,7 @@ http_debug_hex(const char *prefix, /* I - Prefix for line */ if (ch < ' ' || ch >= 127) ch = '.'; - *ptr++ = ch; + *ptr++ = (char)ch; } *ptr = '\0'; @@ -4454,24 +4033,6 @@ http_debug_hex(const char *prefix, /* I - Prefix for line */ #endif /* DEBUG */ -/* - * 'http_field()' - Return the field index for a field name. - */ - -static http_field_t /* O - Field index */ -http_field(const char *name) /* I - String name */ -{ - int i; /* Looping var */ - - - for (i = 0; i < HTTP_FIELD_MAX; i ++) - if (_cups_strcasecmp(name, http_fields[i]) == 0) - return ((http_field_t)i); - - return (HTTP_FIELD_UNKNOWN); -} - - /* * 'http_read()' - Read a buffer from a HTTP connection. * @@ -4480,15 +4041,14 @@ http_field(const char *name) /* I - String name */ */ static ssize_t /* O - Number of bytes read or -1 on error */ -http_read(http_t *http, /* I - Connection to server */ +http_read(http_t *http, /* I - HTTP connection */ 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)); + DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (!http->blocking) { @@ -4508,7 +4068,7 @@ http_read(http_t *http, /* I - Connection to server */ { #ifdef HAVE_SSL if (http->tls) - bytes = http_read_ssl(http, buffer, length); + bytes = _httpTLSRead(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = recv(http->fd, buffer, length, 0); @@ -4560,7 +4120,7 @@ http_read(http_t *http, /* I - Connection to server */ CUPS_LLCAST bytes)); #ifdef DEBUG if (bytes > 0) - http_debug_hex("http_read", http->buffer, (int)bytes); + http_debug_hex("http_read", buffer, (int)bytes); #endif /* DEBUG */ if (bytes < 0) @@ -4594,32 +4154,30 @@ http_read(http_t *http, /* I - Connection to server */ */ static ssize_t /* O - Number of bytes read or -1 on error */ -http_read_buffered(http_t *http, /* I - Connection to server */ +http_read_buffered(http_t *http, /* I - HTTP connection */ 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)); + DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used)); if (http->used > 0) { if (length > (size_t)http->used) - bytes = (size_t)http->used; + bytes = (ssize_t)http->used; else - bytes = length; + bytes = (ssize_t)length; DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.", (int)bytes)); - memcpy(buffer, http->buffer, bytes); + memcpy(buffer, http->buffer, (size_t)bytes); http->used -= (int)bytes; if (http->used > 0) - memmove(http->buffer, http->buffer + bytes, http->used); + memmove(http->buffer, http->buffer + bytes, (size_t)http->used); } else bytes = http_read(http, buffer, length); @@ -4636,12 +4194,11 @@ http_read_buffered(http_t *http, /* I - Connection to server */ */ static ssize_t /* O - Number of bytes read or -1 on error */ -http_read_chunk(http_t *http, /* I - Connection to server */ +http_read_chunk(http_t *http, /* I - HTTP connection */ 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)); + DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); if (http->data_remaining <= 0) { @@ -4697,103 +4254,12 @@ http_read_chunk(http_t *http, /* I - Connection to server */ } -#ifdef HAVE_SSL -/* - * 'http_read_ssl()' - Read from a SSL/TLS connection. - */ - -static int /* O - Bytes read */ -http_read_ssl(http_t *http, /* I - Connection to server */ - char *buf, /* I - Buffer to store data */ - int len) /* I - Length of buffer */ -{ -# if defined(HAVE_LIBSSL) - return (SSL_read((SSL *)(http->tls), buf, len)); - -# elif defined(HAVE_GNUTLS) - ssize_t result; /* Return value */ - - - result = gnutls_record_recv(http->tls, buf, len); - - if (result < 0 && !errno) - { - /* - * Convert GNU TLS error to errno value... - */ - - switch (result) - { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; - - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; - - default : - errno = EPIPE; - break; - } - - result = -1; - } - - return ((int)result); - -# elif defined(HAVE_CDSASSL) - int result; /* Return value */ - OSStatus error; /* Error info */ - size_t processed; /* Number of bytes processed */ - - - error = SSLRead(http->tls, buf, len, &processed); - DEBUG_printf(("6http_read_ssl: error=%d, processed=%d", (int)error, - (int)processed)); - switch (error) - { - case 0 : - result = (int)processed; - break; - - case errSSLWouldBlock : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EINTR; - } - break; - - case errSSLClosedGraceful : - default : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EPIPE; - } - break; - } - - return (result); - -# elif defined(HAVE_SSPISSL) - return _sspiRead((_sspi_struct_t*) http->tls, buf, len); -# endif /* HAVE_LIBSSL */ -} -#endif /* HAVE_SSL */ - - /* * 'http_send()' - Send a request with all fields and the trailing blank line. */ static int /* O - 0 on success, non-zero on error */ -http_send(http_t *http, /* I - Connection to server */ +http_send(http_t *http, /* I - HTTP connection */ http_state_t request, /* I - Request code */ const char *uri) /* I - URI */ { @@ -4820,8 +4286,7 @@ http_send(http_t *http, /* I - Connection to server */ }; - DEBUG_printf(("7http_send(http=%p, request=HTTP_%s, uri=\"%s\")", - http, codes[request], uri)); + DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri)); if (http == NULL || uri == NULL) return (-1); @@ -4831,9 +4296,12 @@ http_send(http_t *http, /* I - Connection to server */ */ if (!http->fields[HTTP_FIELD_USER_AGENT][0]) - httpSetField(http, HTTP_FIELD_USER_AGENT, - http->default_user_agent ? http->default_user_agent : - CUPS_MINIMAL); + { + if (http->default_user_agent) + httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_user_agent); + else + httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent()); + } /* * Set the Accept-Encoding field if it isn't already... @@ -4853,10 +4321,15 @@ http_send(http_t *http, /* I - Connection to server */ * See if we had an error the last time around; if so, reconnect... */ - if (http->fd < 0 || http->status == HTTP_ERROR || - http->status >= HTTP_BAD_REQUEST) - if (httpReconnect(http)) + if (http->fd < 0 || http->status == HTTP_STATUS_ERROR || + http->status >= HTTP_STATUS_BAD_REQUEST) + { + DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d", + http->fd, http->status, http->tls_upgrade)); + + if (httpReconnect2(http, 30000, NULL)) return (-1); + } /* * Flush any written data that is pending... @@ -4865,7 +4338,7 @@ http_send(http_t *http, /* I - Connection to server */ if (http->wused) { if (httpFlushWrite(http) < 0) - if (httpReconnect(http)) + if (httpReconnect2(http, 30000, NULL)) return (-1); } @@ -4876,13 +4349,13 @@ http_send(http_t *http, /* I - Connection to server */ http->state = request; http->data_encoding = HTTP_ENCODING_FIELDS; - if (request == HTTP_POST || request == HTTP_PUT) + if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT) http->state ++; - http->status = HTTP_CONTINUE; + http->status = HTTP_STATUS_CONTINUE; #ifdef HAVE_SSL - if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls) + if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls) { httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade"); httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0"); @@ -4891,27 +4364,27 @@ http_send(http_t *http, /* I - Connection to server */ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } for (i = 0; i < HTTP_FIELD_MAX; i ++) if ((value = httpGetField(http, i)) != NULL && *value) { - DEBUG_printf(("9http_send: %s: %s", http_fields[i], value)); + DEBUG_printf(("5http_send: %s: %s", http_fields[i], value)); if (i == HTTP_FIELD_HOST) { if (httpPrintf(http, "Host: %s:%d\r\n", value, httpAddrPort(http->hostaddr)) < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } } else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } } @@ -4919,21 +4392,25 @@ http_send(http_t *http, /* I - Connection to server */ if (http->cookie) if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } - if (http->expect == HTTP_CONTINUE && http->mode == _HTTP_MODE_CLIENT && - (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_PUT_RECV)) + DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect, + http->mode, http->state)); + + if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT && + (http->state == HTTP_STATE_POST_RECV || + http->state == HTTP_STATE_PUT_RECV)) if (httpPrintf(http, "Expect: 100-continue\r\n") < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } if (httpPrintf(http, "\r\n") < 1) { - http->status = HTTP_ERROR; + http->status = HTTP_STATUS_ERROR; return (-1); } @@ -4963,100 +4440,6 @@ http_send(http_t *http, /* I - Connection to server */ } -#ifdef HAVE_SSL -# if defined(HAVE_CDSASSL) -/* - * 'http_set_credentials()' - Set the SSL/TLS credentials. - */ - -static int /* O - Status of connection */ -http_set_credentials(http_t *http) /* I - Connection to server */ -{ - _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - OSStatus error = 0; /* Error code */ - http_tls_credentials_t credentials = NULL; - /* TLS credentials */ - - - DEBUG_printf(("7http_set_credentials(%p)", http)); - - /* - * Prefer connection specific credentials... - */ - - if ((credentials = http->tls_credentials) == NULL) - credentials = cg->tls_credentials; - - /* - * Otherwise root around in the user's keychain to see if one can be found... - */ - - if (!credentials) - { - CFDictionaryRef query; /* Query dictionary */ - CFTypeRef matches = NULL; /* Matching credentials */ - CFArrayRef dn_array = NULL;/* Distinguished names array */ - CFTypeRef keys[] = { kSecClass, - kSecMatchLimit, - kSecReturnRef }; - /* Keys for dictionary */ - CFTypeRef values[] = { kSecClassCertificate, - kSecMatchLimitOne, - kCFBooleanTrue }; - /* Values for dictionary */ - - /* - * Get the names associated with the server. - */ - - if ((error = SSLCopyDistinguishedNames(http->tls, &dn_array)) != noErr) - { - DEBUG_printf(("4http_set_credentials: SSLCopyDistinguishedNames, error=%d", - (int)error)); - return (error); - } - - /* - * Create a query which will return all identities that can sign and match - * the passed in policy. - */ - - query = CFDictionaryCreate(NULL, - (const void**)(&keys[0]), - (const void**)(&values[0]), - sizeof(keys) / sizeof(keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (query) - { - error = SecItemCopyMatching(query, &matches); - DEBUG_printf(("4http_set_credentials: SecItemCopyMatching, error=%d", - (int)error)); - CFRelease(query); - } - - if (matches) - CFRelease(matches); - - if (dn_array) - CFRelease(dn_array); - } - - if (credentials) - { - error = SSLSetCertificate(http->tls, credentials); - DEBUG_printf(("4http_set_credentials: SSLSetCertificate, error=%d", - (int)error)); - } - else - DEBUG_puts("4http_set_credentials: No credentials to set."); - - return (error); -} -# endif /* HAVE_CDSASSL */ -#endif /* HAVE_SSL */ - - /* * 'http_set_length()' - Set the data_encoding and data_remaining values. */ @@ -5067,8 +4450,7 @@ http_set_length(http_t *http) /* I - Connection */ off_t remaining; /* Remainder */ - DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", http, http->mode, - http_states[http->state + 1])); + DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state))); if ((remaining = httpGetLength2(http)) >= 0) { @@ -5101,7 +4483,7 @@ http_set_length(http_t *http) /* I - Connection */ http->data_remaining = remaining; if (remaining <= INT_MAX) - http->_data_remaining = remaining; + http->_data_remaining = (int)remaining; else http->_data_remaining = INT_MAX; } @@ -5121,8 +4503,8 @@ http_set_timeout(int fd, /* I - File descriptor */ DWORD tv = (DWORD)(timeout * 1000); /* Timeout in milliseconds */ - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #else struct timeval tv; /* Timeout in secs and usecs */ @@ -5130,8 +4512,8 @@ http_set_timeout(int fd, /* I - File descriptor */ tv.tv_sec = (int)timeout; tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0)); - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); #endif /* WIN32 */ } @@ -5141,7 +4523,7 @@ http_set_timeout(int fd, /* I - File descriptor */ */ static void -http_set_wait(http_t *http) /* I - Connection to server */ +http_set_wait(http_t *http) /* I - HTTP connection */ { if (http->blocking) { @@ -5157,476 +4539,17 @@ http_set_wait(http_t *http) /* I - Connection to server */ #ifdef HAVE_SSL /* - * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. - */ - -static int /* O - 0 on success, -1 on failure */ -http_setup_ssl(http_t *http) /* I - Connection to server */ -{ - char hostname[256], /* Hostname */ - *hostptr; /* Pointer into hostname */ - -# ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - BIO *bio; /* BIO data */ - const char *message = NULL;/* Error message */ -# elif defined(HAVE_GNUTLS) - int status; /* Status of handshake */ - 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 */ - cups_array_t *names; /* CUPS distinguished names */ - CFArrayRef dn_array; /* CF distinguished names array */ - CFIndex count; /* Number of credentials */ - CFDataRef data; /* Certificate data */ - int i; /* Looping var */ - http_credential_t *credential; /* Credential data */ -# elif defined(HAVE_SSPISSL) - TCHAR username[256]; /* Username returned from GetUserName() */ - TCHAR commonName[256];/* Common name for certificate */ - DWORD dwSize; /* 32 bit size */ -# endif /* HAVE_LIBSSL */ - - - DEBUG_printf(("7http_setup_ssl(http=%p)", http)); - - /* - * Get the hostname to use for SSL... - */ - - if (httpAddrLocalhost(http->hostaddr)) - { - strlcpy(hostname, "localhost", sizeof(hostname)); - } - else - { - /* - * Otherwise make sure the hostname we have does not end in a trailing dot. - */ - - strlcpy(hostname, http->hostname, sizeof(hostname)); - if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && - *hostptr == '.') - *hostptr = '\0'; - } - -# ifdef HAVE_LIBSSL - context = SSL_CTX_new(SSLv23_client_method()); - - SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ - - bio = BIO_new(_httpBIOMethods()); - BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)http); - - http->tls = SSL_new(context); - SSL_set_bio(http->tls, bio, bio); - -# ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME - SSL_set_tlsext_host_name(http->tls, hostname); -# endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */ - - if (SSL_connect(http->tls) != 1) - { - unsigned long error; /* Error code */ - - while ((error = ERR_get_error()) != 0) - { - message = ERR_error_string(error, NULL); - DEBUG_printf(("8http_setup_ssl: %s", message)); - } - - SSL_CTX_free(context); - SSL_free(http->tls); - http->tls = NULL; - -# ifdef WIN32 - http->error = WSAGetLastError(); -# else - http->error = errno; -# endif /* WIN32 */ - http->status = HTTP_ERROR; - - if (!message) - message = _("Unable to establish a secure connection to host."); - - _cupsSetError(IPP_PKI_ERROR, message, 1); - - return (-1); - } - -# elif defined(HAVE_GNUTLS) - credentials = (gnutls_certificate_client_credentials *) - malloc(sizeof(gnutls_certificate_client_credentials)); - if (credentials == NULL) - { - DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s", - strerror(errno))); - http->error = errno; - http->status = HTTP_ERROR; - _cupsSetHTTPError(HTTP_ERROR); - - return (-1); - } - - gnutls_certificate_allocate_credentials(credentials); - - gnutls_init(&http->tls, GNUTLS_CLIENT); - gnutls_set_default_priority(http->tls); - gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, - strlen(hostname)); - gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials); - gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr)http); - gnutls_transport_set_pull_function(http->tls, _httpReadGNUTLS); - gnutls_transport_set_push_function(http->tls, _httpWriteGNUTLS); - - while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) - { - DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)", - status, gnutls_strerror(status))); - - if (gnutls_error_is_fatal(status)) - { - http->error = EIO; - http->status = HTTP_ERROR; - - _cupsSetError(IPP_PKI_ERROR, gnutls_strerror(status), 0); - - gnutls_deinit(http->tls); - gnutls_certificate_free_credentials(*credentials); - free(credentials); - http->tls = NULL; - - return (-1); - } - } - - http->tls_credentials = credentials; - -# elif defined(HAVE_CDSASSL) - if ((http->tls = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, - kSSLStreamType)) == NULL) - { - DEBUG_puts("4http_setup_ssl: SSLCreateContext failed."); - http->error = errno = ENOMEM; - http->status = HTTP_ERROR; - _cupsSetHTTPError(HTTP_ERROR); - - return (-1); - } - - error = SSLSetConnection(http->tls, http); - DEBUG_printf(("4http_setup_ssl: SSLSetConnection, error=%d", (int)error)); - - if (!error) - { - error = SSLSetIOFuncs(http->tls, _httpReadCDSA, _httpWriteCDSA); - DEBUG_printf(("4http_setup_ssl: SSLSetIOFuncs, error=%d", (int)error)); - } - - if (!error) - { - error = SSLSetSessionOption(http->tls, kSSLSessionOptionBreakOnServerAuth, - true); - DEBUG_printf(("4http_setup_ssl: SSLSetSessionOption, error=%d", - (int)error)); - } - - if (!error) - { - if (cg->client_cert_cb) - { - error = SSLSetSessionOption(http->tls, - kSSLSessionOptionBreakOnCertRequested, true); - DEBUG_printf(("4http_setup_ssl: kSSLSessionOptionBreakOnCertRequested, " - "error=%d", (int)error)); - } - else - { - error = http_set_credentials(http); - DEBUG_printf(("4http_setup_ssl: http_set_credentials, error=%d", - (int)error)); - } - } - - /* - * Let the server know which hostname/domain we are trying to connect to - * in case it wants to serve up a certificate with a matching common name. - */ - - if (!error) - { - error = SSLSetPeerDomainName(http->tls, hostname, strlen(hostname)); - - DEBUG_printf(("4http_setup_ssl: SSLSetPeerDomainName, error=%d", - (int)error)); - } - - if (!error) - { - int done = 0; /* Are we done yet? */ - - while (!error && !done) - { - error = SSLHandshake(http->tls); - - DEBUG_printf(("4http_setup_ssl: SSLHandshake returned %d.", (int)error)); - - switch (error) - { - case noErr : - done = 1; - break; - - case errSSLWouldBlock : - error = noErr; /* Force a retry */ - usleep(1000); /* in 1 millisecond */ - break; - - case errSSLServerAuthCompleted : - error = 0; - if (cg->server_cert_cb) - { - error = httpCopyCredentials(http, &credentials); - if (!error) - { - error = (cg->server_cert_cb)(http, http->tls, credentials, - cg->server_cert_data); - httpFreeCredentials(credentials); - } - - DEBUG_printf(("4http_setup_ssl: Server certificate callback " - "returned %d.", (int)error)); - } - break; - - case errSSLClientCertRequested : - error = 0; - - if (cg->client_cert_cb) - { - names = NULL; - if (!(error = SSLCopyDistinguishedNames(http->tls, &dn_array)) && - dn_array) - { - if ((names = cupsArrayNew(NULL, NULL)) != NULL) - { - for (i = 0, count = CFArrayGetCount(dn_array); i < count; i++) - { - data = (CFDataRef)CFArrayGetValueAtIndex(dn_array, i); - - if ((credential = malloc(sizeof(*credential))) != NULL) - { - credential->datalen = CFDataGetLength(data); - if ((credential->data = malloc(credential->datalen))) - { - memcpy((void *)credential->data, CFDataGetBytePtr(data), - credential->datalen); - cupsArrayAdd(names, credential); - } - else - free(credential); - } - } - } - - CFRelease(dn_array); - } - - if (!error) - { - error = (cg->client_cert_cb)(http, http->tls, names, - cg->client_cert_data); - - DEBUG_printf(("4http_setup_ssl: Client certificate callback " - "returned %d.", (int)error)); - } - - httpFreeCredentials(names); - } - break; - - case errSSLUnknownRootCert : - message = _("Unable to establish a secure connection to host " - "(untrusted certificate)."); - break; - - case errSSLNoRootCert : - message = _("Unable to establish a secure connection to host " - "(self-signed certificate)."); - break; - - case errSSLCertExpired : - message = _("Unable to establish a secure connection to host " - "(expired certificate)."); - break; - - case errSSLCertNotYetValid : - message = _("Unable to establish a secure connection to host " - "(certificate not yet valid)."); - break; - - case errSSLHostNameMismatch : - message = _("Unable to establish a secure connection to host " - "(host name mismatch)."); - break; - - case errSSLXCertChainInvalid : - message = _("Unable to establish a secure connection to host " - "(certificate chain invalid)."); - break; - - case errSSLConnectionRefused : - message = _("Unable to establish a secure connection to host " - "(peer dropped connection before responding)."); - break; - - default : - break; - } - } - } - - if (error) - { - http->error = error; - http->status = HTTP_ERROR; - errno = ECONNREFUSED; - - CFRelease(http->tls); - http->tls = NULL; - - /* - * If an error string wasn't set by the callbacks use a generic one... - */ - - if (!message) -#ifdef HAVE_CSSMERRORSTRING - message = cssmErrorString(error); -#else - message = _("Unable to establish a secure connection to host."); -#endif /* HAVE_CSSMERRORSTRING */ - - _cupsSetError(IPP_PKI_ERROR, message, 1); - - return (-1); - } - -# elif defined(HAVE_SSPISSL) - http->tls = _sspiAlloc(); - - if (!http->tls) - { - _cupsSetHTTPError(HTTP_ERROR); - return (-1); - } - - http->tls->sock = http->fd; - dwSize = sizeof(username) / sizeof(TCHAR); - GetUserName(username, &dwSize); - _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR), - sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username); - - if (!_sspiGetCredentials(http->tls_credentials, L"ClientContainer", - commonName, FALSE)) - { - _sspiFree(http->tls_credentials); - http->tls_credentials = NULL; - - http->error = EIO; - http->status = HTTP_ERROR; - - _cupsSetError(IPP_PKI_ERROR, - _("Unable to establish a secure connection to host."), 1); - - return (-1); - } - - _sspiSetAllowsAnyRoot(http->tls_credentials, TRUE); - _sspiSetAllowsExpiredCerts(http->tls_credentials, TRUE); - - if (!_sspiConnect(http->tls_credentials, hostname)) - { - _sspiFree(http->tls_credentials); - http->tls_credentials = NULL; - - http->error = EIO; - http->status = HTTP_ERROR; - - _cupsSetError(IPP_PKI_ERROR, - _("Unable to establish a secure connection to host."), 1); - - return (-1); - } -# endif /* HAVE_CDSASSL */ - - return (0); -} - - -/* - * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection. - */ - -static void -http_shutdown_ssl(http_t *http) /* I - Connection to server */ -{ -# ifdef HAVE_LIBSSL - SSL_CTX *context; /* Context for encryption */ - - context = SSL_get_SSL_CTX(http->tls); - - SSL_shutdown(http->tls); - SSL_CTX_free(context); - SSL_free(http->tls); - -# elif defined(HAVE_GNUTLS) - gnutls_certificate_client_credentials *credentials; - /* TLS credentials */ - - credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials); - - gnutls_bye(http->tls, GNUTLS_SHUT_RDWR); - gnutls_deinit(http->tls); - gnutls_certificate_free_credentials(*credentials); - free(credentials); - -# elif defined(HAVE_CDSASSL) - while (SSLClose(http->tls) == errSSLWouldBlock) - usleep(1000); - - CFRelease(http->tls); - - if (http->tls_credentials) - CFRelease(http->tls_credentials); - -# elif defined(HAVE_SSPISSL) - _sspiFree(http->tls_credentials); -# endif /* HAVE_LIBSSL */ - - http->tls = NULL; - http->tls_credentials = NULL; -} -#endif /* HAVE_SSL */ - - -#ifdef HAVE_SSL -/* - * 'http_upgrade()' - Force upgrade to TLS encryption. + * 'http_tls_upgrade()' - Force upgrade to TLS encryption. */ static int /* O - Status of connection */ -http_upgrade(http_t *http) /* I - Connection to server */ +http_tls_upgrade(http_t *http) /* I - HTTP connection */ { int ret; /* Return value */ http_t myhttp; /* Local copy of HTTP data */ - DEBUG_printf(("7http_upgrade(%p)", http)); + DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http)); /* * Flush the connection to make sure any previous "Upgrade" message @@ -5647,6 +4570,7 @@ http_upgrade(http_t *http) /* I - Connection to server */ * encryption on the link... */ + http->tls_upgrade = 1; http->field_authorization = NULL; /* Don't free the auth string */ httpClearFields(http); @@ -5659,7 +4583,7 @@ http_upgrade(http_t *http) /* I - Connection to server */ * Wait for the secure connection... */ - while (httpUpdate(http) == HTTP_CONTINUE); + while (httpUpdate(http) == HTTP_STATUS_CONTINUE); } /* @@ -5673,6 +4597,7 @@ http_upgrade(http_t *http) /* I - Connection to server */ http->expect = myhttp.expect; http->field_authorization = myhttp.field_authorization; http->digest_tries = myhttp.digest_tries; + http->tls_upgrade = 0; /* * See if we actually went secure... @@ -5684,13 +4609,10 @@ http_upgrade(http_t *http) /* I - Connection to server */ * Server does not support HTTP upgrade... */ - DEBUG_puts("8http_upgrade: Server does not support HTTP upgrade!"); + DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!"); -# ifdef WIN32 - closesocket(http->fd); -# else - close(http->fd); -# endif + _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1); + httpAddrClose(NULL, http->fd); http->fd = -1; @@ -5707,7 +4629,7 @@ http_upgrade(http_t *http) /* I - Connection to server */ */ static ssize_t /* O - Number of bytes written */ -http_write(http_t *http, /* I - Connection to server */ +http_write(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer for data */ size_t length) /* I - Number of bytes to write */ { @@ -5715,8 +4637,7 @@ http_write(http_t *http, /* I - Connection to server */ bytes; /* Bytes sent */ - DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", http, - buffer, CUPS_LLCAST length)); + DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); http->error = 0; tbytes = 0; @@ -5783,7 +4704,7 @@ http_write(http_t *http, /* I - Connection to server */ #ifdef HAVE_SSL if (http->tls) - bytes = http_write_ssl(http, buffer, length); + bytes = _httpTLSWrite(http, buffer, (int)length); else #endif /* HAVE_SSL */ bytes = send(http->fd, buffer, length, 0); @@ -5837,11 +4758,11 @@ http_write(http_t *http, /* I - Connection to server */ buffer += bytes; tbytes += bytes; - length -= bytes; + length -= (size_t)bytes; } #ifdef DEBUG - http_debug_hex("http_write", buffer - tbytes, tbytes); + http_debug_hex("http_write", buffer - tbytes, (int)tbytes); #endif /* DEBUG */ DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes)); @@ -5855,7 +4776,7 @@ http_write(http_t *http, /* I - Connection to server */ */ static ssize_t /* O - Number bytes written */ -http_write_chunk(http_t *http, /* I - Connection to server */ +http_write_chunk(http_t *http, /* I - HTTP connection */ const char *buffer, /* I - Buffer to write */ size_t length) /* I - Length of buffer */ { @@ -5863,8 +4784,7 @@ http_write_chunk(http_t *http, /* I - Connection to server */ ssize_t bytes; /* Bytes written */ - DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", - http, buffer, CUPS_LLCAST length)); + DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); /* * Write the chunk header, data, and trailer. @@ -5891,98 +4811,3 @@ http_write_chunk(http_t *http, /* I - Connection to server */ return (bytes); } - - -#ifdef HAVE_SSL -/* - * 'http_write_ssl()' - Write to a SSL/TLS connection. - */ - -static int /* O - Bytes written */ -http_write_ssl(http_t *http, /* I - Connection to server */ - const char *buf, /* I - Buffer holding data */ - int len) /* I - Length of buffer */ -{ - ssize_t result; /* Return value */ - - - DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); - -# if defined(HAVE_LIBSSL) - result = SSL_write((SSL *)(http->tls), buf, len); - -# elif defined(HAVE_GNUTLS) - result = gnutls_record_send(http->tls, buf, len); - - if (result < 0 && !errno) - { - /* - * Convert GNU TLS error to errno value... - */ - - switch (result) - { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; - - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; - - default : - errno = EPIPE; - break; - } - - result = -1; - } - -# elif defined(HAVE_CDSASSL) - OSStatus error; /* Error info */ - size_t processed; /* Number of bytes processed */ - - - error = SSLWrite(http->tls, buf, len, &processed); - - switch (error) - { - case 0 : - result = (int)processed; - break; - - case errSSLWouldBlock : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EINTR; - } - break; - - case errSSLClosedGraceful : - default : - if (processed) - result = (int)processed; - else - { - result = -1; - errno = EPIPE; - } - break; - } -# elif defined(HAVE_SSPISSL) - return _sspiWrite((_sspi_struct_t *)http->tls, (void *)buf, len); -# endif /* HAVE_LIBSSL */ - - DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); - - return ((int)result); -} -#endif /* HAVE_SSL */ - - -/* - * End of "$Id: http.c 7850 2008-08-20 00:07:25Z mike $". - */