]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/http.c
Merge changes from CUPS 1.4svn-r7696.
[thirdparty/cups.git] / cups / http.c
index da2279344c1905a90dfc1d0e86a395e9b287df7d..8baf29119589d30b158b4c7f47c5df397b662fcb 100644 (file)
@@ -1,30 +1,25 @@
 /*
- * "$Id: http.c 5200 2006-02-28 00:10:32Z mike $"
+ * "$Id: http.c 7661 2008-06-16 21:46:51Z mike $"
  *
  *   HTTP routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products 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 missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
+ *   This file contains Kerberos support code, copyright 2006 by
+ *   Jelmer Vernooij.
  *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: 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:
  *
+ *   _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.
@@ -39,6 +34,7 @@
  *   httpFlush()          - Flush data from a HTTP connection.
  *   httpFlushWrite()     - Flush data in write buffer.
  *   httpGet()            - Send a GET request to the 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.
  *   httpGetFd()          - Get the file descriptor associated with a
  *   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 CDSA decryption code.
+ *   _httpReadCDSA()      - Read function for the CDSA library.
+ *   _httpReadGNUTLS()    - Read function for the GNU TLS library.
  *   httpReconnect()      - Reconnect to a HTTP server...
+ *   httpSetAuthString()  - Set the current authorization string.
  *   httpSetCookie()      - Set the cookie value(s)...
  *   httpSetExpect()      - Set the Expect: header in a request.
  *   httpSetField()       - Set the value of an HTTP header.
  *   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 CDSA encryption code.
+ *   _httpWriteCDSA()     - Write function for the CDSA library.
+ *   _httpWriteGNUTLS()   - Write function for the GNU TLS library.
+ *   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_debug_hex()     - Do a hex dump of a buffer.
  *   http_field()         - Return the field index for a field name.
  *   http_read_ssl()      - Read from a SSL/TLS connection.
  *   http_send()          - Send a request with all fields and the trailing
 #  include <sys/time.h>
 #  include <sys/resource.h>
 #endif /* !WIN32 */
+#ifdef HAVE_POLL
+#  include <sys/poll.h>
+#endif /* HAVE_POLL */
 
 
 /*
  * Local functions...
  */
 
+#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 int             http_send(http_t *http, http_state_t request,
                                  const char *uri);
-static int             http_wait(http_t *http, int msec);
+static int             http_wait(http_t *http, int msec, int usessl);
 static int             http_write(http_t *http, const char *buffer,
                                   int length);
 static int             http_write_chunk(http_t *http, const char *buffer,
@@ -168,12 +181,51 @@ static const char * const http_fields[] =
                        };
 
 
+#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,
+                       };
+
+
+/*
+ * '_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 - HTTP connection */
+httpBlocking(http_t *http,             /* I - Connection to server */
              int    b)                 /* I - 1 = blocking, 0 = non-blocking */
 {
   if (http)
@@ -186,7 +238,7 @@ httpBlocking(http_t *http,          /* I - HTTP connection */
  */
 
 int                                    /* O - 0 = no data, 1 = data available */
-httpCheck(http_t *http)                        /* I - HTTP connection */
+httpCheck(http_t *http)                        /* I - Connection to server */
 {
   return (httpWait(http, 0));
 }
@@ -199,7 +251,7 @@ httpCheck(http_t *http)                     /* I - HTTP connection */
  */
 
 void
-httpClearCookie(http_t *http)          /* I - HTTP connection */
+httpClearCookie(http_t *http)          /* I - Connection to server */
 {
   if (!http)
     return;
@@ -217,12 +269,21 @@ httpClearCookie(http_t *http)             /* I - HTTP connection */
  */
 
 void
-httpClearFields(http_t *http)          /* I - HTTP connection */
+httpClearFields(http_t *http)          /* I - Connection to server */
 {
   if (http)
   {
     memset(http->fields, 0, sizeof(http->fields));
-    httpSetField(http, HTTP_FIELD_HOST, http->hostname);
+    if (http->hostname[0] == '/')
+      httpSetField(http, HTTP_FIELD_HOST, "localhost");
+    else
+      httpSetField(http, HTTP_FIELD_HOST, http->hostname);
+
+    if (http->field_authorization)
+    {
+      free(http->field_authorization);
+      http->field_authorization = NULL;
+    }
 
     http->expect = (http_status_t)0;
   }
@@ -234,8 +295,14 @@ httpClearFields(http_t *http)              /* I - HTTP connection */
  */
 
 void
-httpClose(http_t *http)                        /* I - HTTP connection */
+httpClose(http_t *http)                        /* I - Connection to server */
 {
+#ifdef HAVE_GSSAPI
+  OM_uint32    minor_status,           /* Minor status code */
+               major_status;           /* Major status code */
+#endif /* HAVE_GSSAPI */
+
+
   DEBUG_printf(("httpClose(http=%p)\n", http));
 
   if (!http)
@@ -243,9 +310,6 @@ httpClose(http_t *http)                     /* I - HTTP connection */
 
   httpAddrFreeList(http->addrlist);
 
-  if (http->input_set)
-    free(http->input_set);
-
   if (http->cookie)
     free(http->cookie);
 
@@ -260,6 +324,25 @@ httpClose(http_t *http)                    /* I - HTTP connection */
   close(http->fd);
 #endif /* WIN32 */
 
+#ifdef HAVE_GSSAPI
+  if (http->gssctx != GSS_C_NO_CONTEXT)
+    major_status = gss_delete_sec_context(&minor_status, &http->gssctx,
+                                          GSS_C_NO_BUFFER);
+
+  if (http->gssname != GSS_C_NO_NAME)
+    major_status = gss_release_name(&minor_status, &http->gssname);
+#endif /* HAVE_GSSAPI */
+
+#ifdef HAVE_AUTHORIZATION_H
+  if (http->auth_ref)
+    AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
+#endif /* HAVE_AUTHORIZATION_H */
+
+  httpClearFields(http);
+
+  if (http->authstring && http->authstring != http->_authstring)
+    free(http->authstring);
+
   free(http);
 }
 
@@ -324,15 +407,22 @@ httpConnectEncrypt(
   * Allocate memory for the structure...
   */
 
-  http = calloc(sizeof(http_t), 1);
-  if (http == NULL)
+  if ((http = calloc(sizeof(http_t), 1)) == NULL)
+  {
+    httpAddrFreeList(addrlist);
     return (NULL);
+  }
 
   http->version  = HTTP_1_1;
   http->blocking = 1;
   http->activity = time(NULL);
   http->fd       = -1;
 
+#ifdef HAVE_GSSAPI
+  http->gssctx  = GSS_C_NO_CONTEXT;
+  http->gssname = GSS_C_NO_NAME;
+#endif /* HAVE_GSSAPI */
+
  /*
   * Set the encryption status...
   */
@@ -374,7 +464,7 @@ httpConnectEncrypt(
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpDelete(http_t     *http,           /* I - HTTP connection */
+httpDelete(http_t     *http,           /* I - Connection to server */
            const char *uri)            /* I - URI to delete */
 {
   return (http_send(http, HTTP_DELETE, uri));
@@ -386,7 +476,7 @@ httpDelete(http_t     *http,                /* I - HTTP connection */
  */
 
 int                                    /* O - -1 on error, 0 on success */
-httpEncryption(http_t            *http,        /* I - HTTP connection */
+httpEncryption(http_t            *http,        /* I - Connection to server */
                http_encryption_t e)    /* I - New encryption preference */
 {
   DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
@@ -418,7 +508,7 @@ httpEncryption(http_t            *http,     /* I - HTTP connection */
  */
 
 int                                    /* O - Error code (errno) value */
-httpError(http_t *http)                        /* I - HTTP connection */
+httpError(http_t *http)                        /* I - Connection to server */
 {
   if (http)
     return (http->error);
@@ -432,7 +522,7 @@ httpError(http_t *http)                     /* I - HTTP connection */
  */
 
 void
-httpFlush(http_t *http)                        /* I - HTTP connection */
+httpFlush(http_t *http)                        /* I - Connection to server */
 {
   char buffer[8192];                   /* Junk buffer */
   int  blocking;                       /* To block or not to block */
@@ -491,7 +581,7 @@ httpFlush(http_t *http)                     /* I - HTTP connection */
  */
 
 int                                    /* O - Bytes written or -1 on error */
-httpFlushWrite(http_t *http)           /* I - HTTP connection */
+httpFlushWrite(http_t *http)           /* I - Connection to server */
 {
   int  bytes;                          /* Bytes written */
 
@@ -517,13 +607,34 @@ httpFlushWrite(http_t *http)              /* I - HTTP connection */
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpGet(http_t     *http,              /* I - HTTP connection */
+httpGet(http_t     *http,              /* I - Connection to server */
         const char *uri)               /* I - URI to get */
 {
   return (http_send(http, HTTP_GET, uri));
 }
 
 
+/*
+ * '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@
+ */
+
+char *                                 /* O - Authorization string */
+httpGetAuthString(http_t *http)                /* I - Connection to server */
+{
+  if (http)
+    return (http->authstring);
+  else
+    return (NULL);
+}
+
+
 /*
  * 'httpGetBlocking()' - Get the blocking/non-block state of a connection.
  *
@@ -531,7 +642,7 @@ httpGet(http_t     *http,           /* I - HTTP connection */
  */
 
 int                                    /* O - 1 if blocking, 0 if non-blocking */
-httpGetBlocking(http_t *http)          /* I - HTTP connection */
+httpGetBlocking(http_t *http)          /* I - Connection to server */
 {
   return (http ? http->blocking : 0);
 }
@@ -539,6 +650,8 @@ httpGetBlocking(http_t *http)               /* I - HTTP connection */
 
 /*
  * 'httpGetCookie()' - Get any cookie data from the response.
+ *
+ * @since CUPS 1.1.19@
  */
 
 const char *                           /* O - Cookie data or NULL */
@@ -555,7 +668,7 @@ httpGetCookie(http_t *http)         /* I - HTTP connecion */
  */
 
 int                                    /* O - File descriptor or -1 if none */
-httpGetFd(http_t *http)                        /* I - HTTP connection */
+httpGetFd(http_t *http)                        /* I - Connection to server */
 {
   return (http ? http->fd : -1);
 }
@@ -566,11 +679,21 @@ httpGetFd(http_t *http)                   /* I - HTTP connection */
  */
 
 const char *                           /* O - Field value */
-httpGetField(http_t       *http,       /* I - HTTP connection */
+httpGetField(http_t       *http,       /* I - Connection to server */
              http_field_t field)       /* I - Field to get */
 {
   if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
     return (NULL);
+  else if (field == HTTP_FIELD_AUTHORIZATION && 
+          http->field_authorization)
+  {
+   /*
+    * Special case for WWW-Authenticate: as its contents can be
+    * longer than HTTP_MAX_VALUE...
+    */
+
+    return (http->field_authorization);
+  }
   else
     return (http->fields[field]);
 }
@@ -587,7 +710,7 @@ httpGetField(http_t       *http,    /* I - HTTP connection */
  */
 
 int                                    /* O - Content length */
-httpGetLength(http_t *http)            /* I - HTTP connection */
+httpGetLength(http_t *http)            /* I - Connection to server */
 {
  /*
   * Get the read content length and return the 32-bit value.
@@ -615,7 +738,7 @@ httpGetLength(http_t *http)         /* I - HTTP connection */
  */
 
 off_t                                  /* O - Content length */
-httpGetLength2(http_t *http)           /* I - HTTP connection */
+httpGetLength2(http_t *http)           /* I - Connection to server */
 {
   DEBUG_printf(("httpGetLength2(http=%p), state=%d\n", http, http->state));
 
@@ -641,8 +764,18 @@ httpGetLength2(http_t *http)               /* I - HTTP connection */
     * after the transfer is complete...
     */
 
-    if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
-      http->data_remaining = 2147483647;
+    if (!http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
+    {
+     /*
+      * Default content length is 0 for errors and 2^31-1 for other
+      * successful requests...
+      */
+
+      if (http->status >= HTTP_MULTIPLE_CHOICES)
+        http->data_remaining = 0;
+      else
+        http->data_remaining = 2147483647;
+    }
     else
       http->data_remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
                                      NULL, 10);
@@ -667,7 +800,7 @@ httpGetLength2(http_t *http)                /* I - HTTP connection */
  */
 
 http_status_t                          /* O - HTTP status */
-httpGetStatus(http_t *http)            /* I - HTTP connection */
+httpGetStatus(http_t *http)            /* I - Connection to server */
 {
   return (http ? http->status : HTTP_ERROR);
 }
@@ -680,7 +813,7 @@ httpGetStatus(http_t *http)         /* I - HTTP connection */
  */
 
 char *                                 /* O - Value or NULL */
-httpGetSubField(http_t       *http,    /* I - HTTP connection */
+httpGetSubField(http_t       *http,    /* I - Connection to server */
                 http_field_t field,    /* I - Field index */
                 const char   *name,    /* I - Name of sub-field */
                char         *value)    /* O - Value string */
@@ -696,7 +829,7 @@ httpGetSubField(http_t       *http, /* I - HTTP connection */
  */
 
 char *                                 /* O - Value or NULL */
-httpGetSubField2(http_t       *http,   /* I - HTTP connection */
+httpGetSubField2(http_t       *http,   /* I - Connection to server */
                  http_field_t field,   /* I - Field index */
                  const char   *name,   /* I - Name of sub-field */
                 char         *value,   /* O - Value string */
@@ -823,7 +956,7 @@ httpGetSubField2(http_t       *http,        /* I - HTTP connection */
 char *                                 /* O - Line or NULL */
 httpGets(char   *line,                 /* I - Line to read into */
          int    length,                        /* I - Max length of buffer */
-        http_t *http)                  /* I - HTTP connection */
+        http_t *http)                  /* I - Connection to server */
 {
   char *lineptr,                       /* Pointer into line */
        *lineend,                       /* End of line */
@@ -864,8 +997,16 @@ httpGets(char   *line,                     /* I - Line to read into */
       * No newline; see if there is more data to be read...
       */
 
-      if (!http->blocking && !http_wait(http, 1000))
+      if (!http->blocking && !http_wait(http, 10000, 1))
+      {
+        DEBUG_puts("httpGets: Timed out!");
+#ifdef WIN32
+        http->error = WSAETIMEDOUT;
+#else
+        http->error = ETIMEDOUT;
+#endif /* WIN32 */
         return (NULL);
+      }
 
 #ifdef HAVE_SSL
       if (http->tls)
@@ -939,7 +1080,7 @@ httpGets(char   *line,                     /* I - Line to read into */
        *lineptr++ = *bufptr++;
     }
 
-    http->used -= bufptr - http->buffer;
+    http->used -= (int)(bufptr - http->buffer);
     if (http->used > 0)
       memmove(http->buffer, bufptr, http->used);
 
@@ -970,7 +1111,7 @@ httpGets(char   *line,                     /* I - Line to read into */
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpHead(http_t     *http,             /* I - HTTP connection */
+httpHead(http_t     *http,             /* I - Connection to server */
          const char *uri)              /* I - URI for head */
 {
   return (http_send(http, HTTP_HEAD, uri));
@@ -1051,7 +1192,7 @@ httpInitialize(void)
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpOptions(http_t     *http,          /* I - HTTP connection */
+httpOptions(http_t     *http,          /* I - Connection to server */
             const char *uri)           /* I - URI for options */
 {
   return (http_send(http, HTTP_OPTIONS, uri));
@@ -1063,7 +1204,7 @@ httpOptions(http_t     *http,             /* I - HTTP connection */
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpPost(http_t     *http,             /* I - HTTP connection */
+httpPost(http_t     *http,             /* I - Connection to server */
          const char *uri)              /* I - URI for post */
 {
   return (http_send(http, HTTP_POST, uri));
@@ -1077,7 +1218,7 @@ httpPost(http_t     *http,                /* I - HTTP connection */
  */
 
 int                                    /* O - Number of bytes written */
-httpPrintf(http_t     *http,           /* I - HTTP connection */
+httpPrintf(http_t     *http,           /* I - Connection to server */
            const char *format,         /* I - printf-style format string */
           ...)                         /* I - Additional args as needed */
 {
@@ -1094,15 +1235,20 @@ httpPrintf(http_t     *http,            /* I - HTTP connection */
 
   DEBUG_printf(("httpPrintf: %s", buf));
 
-  if (http->wused)
+  if (http->data_encoding == HTTP_ENCODE_FIELDS)
+    return (httpWrite2(http, buf, bytes));
+  else
   {
-    DEBUG_puts("    flushing existing data...");
+    if (http->wused)
+    {
+      DEBUG_puts("    flushing existing data...");
 
-    if (httpFlushWrite(http) < 0)
-      return (-1);
-  }
+      if (httpFlushWrite(http) < 0)
+       return (-1);
+    }
 
-  return (http_write(http, buf, bytes));
+    return (http_write(http, buf, bytes));
+  }
 }
 
 
@@ -1111,7 +1257,7 @@ httpPrintf(http_t     *http,              /* I - HTTP connection */
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpPut(http_t     *http,              /* I - HTTP connection */
+httpPut(http_t     *http,              /* I - Connection to server */
         const char *uri)               /* I - URI to put */
 {
   return (http_send(http, HTTP_PUT, uri));
@@ -1128,7 +1274,7 @@ httpPut(http_t     *http,         /* I - HTTP connection */
  */
 
 int                                    /* O - Number of bytes read */
-httpRead(http_t *http,                 /* I - HTTP connection */
+httpRead(http_t *http,                 /* I - Connection to server */
          char   *buffer,               /* I - Buffer for data */
         int    length)                 /* I - Maximum number of bytes */
 {
@@ -1143,7 +1289,7 @@ httpRead(http_t *http,                    /* I - HTTP connection */
  */
 
 ssize_t                                        /* O - Number of bytes read */
-httpRead2(http_t *http,                        /* I - HTTP connection */
+httpRead2(http_t *http,                        /* I - Connection to server */
           char   *buffer,              /* I - Buffer for data */
          size_t length)                /* I - Maximum number of bytes */
 {
@@ -1151,8 +1297,8 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
   char         len[32];                /* Length string */
 
 
-  DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
-                http, buffer, length));
+  DEBUG_printf(("httpRead2(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n",
+                http, buffer, CUPS_LLCAST length));
 
   if (http == NULL || buffer == NULL)
     return (-1);
@@ -1207,8 +1353,8 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
 
     return (0);
   }
-  else if (length > http->data_remaining)
-    length = http->data_remaining;
+  else if (length > (size_t)http->data_remaining)
+    length = (size_t)http->data_remaining;
 
   if (http->used == 0 && length <= 256)
   {
@@ -1216,7 +1362,7 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
     * Buffer small reads for better performance...
     */
 
-    if (!http->blocking && !httpWait(http, 1000))
+    if (!http->blocking && !httpWait(http, 10000))
       return (0);
 
     if (http->data_remaining > sizeof(http->buffer))
@@ -1231,12 +1377,12 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
 #endif /* HAVE_SSL */
     {
       DEBUG_printf(("httpRead2: reading %d bytes from socket into buffer...\n",
-                    bytes));
+                    (int)bytes));
 
       bytes = recv(http->fd, http->buffer, bytes, 0);
 
       DEBUG_printf(("httpRead2: read %d bytes from socket into buffer...\n",
-                    bytes));
+                    (int)bytes));
     }
 
     if (bytes > 0)
@@ -1263,15 +1409,16 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
 
   if (http->used > 0)
   {
-    if (length > http->used)
-      length = http->used;
+    if (length > (size_t)http->used)
+      length = (size_t)http->used;
 
-    bytes = length;
+    bytes = (ssize_t)length;
 
-    DEBUG_printf(("httpRead2: grabbing %d bytes from input buffer...\n", bytes));
+    DEBUG_printf(("httpRead2: grabbing %d bytes from input buffer...\n",
+                  (int)bytes));
 
     memcpy(buffer, http->buffer, length);
-    http->used -= length;
+    http->used -= (int)length;
 
     if (http->used > 0)
       memmove(http->buffer, http->buffer + length, http->used);
@@ -1279,24 +1426,30 @@ httpRead2(http_t *http,                 /* I - HTTP connection */
 #ifdef HAVE_SSL
   else if (http->tls)
   {
-    if (!http->blocking && !httpWait(http, 1000))
+    if (!http->blocking && !httpWait(http, 10000))
       return (0);
 
-    bytes = http_read_ssl(http, buffer, length);
+    bytes = (ssize_t)http_read_ssl(http, buffer, (int)length);
   }
 #endif /* HAVE_SSL */
   else
   {
-    if (!http->blocking && !httpWait(http, 1000))
+    if (!http->blocking && !httpWait(http, 10000))
       return (0);
 
-    DEBUG_printf(("httpRead2: reading %d bytes from socket...\n", length));
+    DEBUG_printf(("httpRead2: reading " CUPS_LLFMT " bytes from socket...\n",
+                  CUPS_LLCAST length));
 
+#ifdef WIN32
+    bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0);
+#else
     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
       if (errno != EINTR)
         break;
+#endif /* WIN32 */
 
-    DEBUG_printf(("httpRead2: read %d bytes from socket...\n", bytes));
+    DEBUG_printf(("httpRead2: read " CUPS_LLFMT " bytes from socket...\n",
+                  CUPS_LLCAST bytes));
   }
 
   if (bytes > 0)
@@ -1340,35 +1493,7 @@ httpRead2(http_t *http,                  /* I - HTTP connection */
   }
 
 #ifdef DEBUG
-  {
-    int i, j, ch;
-    printf("httpRead2: Read %d bytes:\n", bytes);
-    for (i = 0; i < bytes; i += 16)
-    {
-      printf("   ");
-
-      for (j = 0; j < 16 && (i + j) < bytes; j ++)
-        printf(" %02X", buffer[i + j] & 255);
-
-      while (j < 16)
-      {
-        printf("   ");
-       j ++;
-      }
-
-      printf("    ");
-      for (j = 0; j < 16 && (i + j) < bytes; j ++)
-      {
-        ch = buffer[i + j] & 255;
-
-       if (ch < ' ' || ch >= 127)
-         ch = '.';
-
-        putchar(ch);
-      }
-      putchar('\n');
-    }
-  }
+  http_debug_hex("httpRead2", buffer, (int)bytes);
 #endif /* DEBUG */
 
   return (bytes);
@@ -1377,7 +1502,7 @@ httpRead2(http_t *http,                   /* I - HTTP connection */
 
 #if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
 /*
- * '_httpReadCDSA()' - Read function for CDSA decryption code.
+ * '_httpReadCDSA()' - Read function for the CDSA library.
  */
 
 OSStatus                               /* O  - -1 on error, 0 on success */
@@ -1388,13 +1513,34 @@ _httpReadCDSA(
 {
   OSStatus     result;                 /* Return value */
   ssize_t      bytes;                  /* Number of bytes read */
+  http_t       *http;                  /* HTTP connection */
+
+
+  http = (http_t *)connection;
+
+  if (!http->blocking)
+  {
+   /*
+    * Make sure we have data before we read...
+    */
+
+    if (!http_wait(http, 10000, 0))
+    {
+      http->error = ETIMEDOUT;
+      return (-1);
+    }
+  }
 
   do
-    bytes = recv((int)connection, data, *dataLength, 0);
+  {
+    bytes = recv(http->fd, data, *dataLength, 0);
+  }
   while (bytes == -1 && errno == EINTR);
 
   if (bytes == *dataLength)
+  {
     result = 0;
+  }
   else if (bytes > 0)
   {
     *dataLength = bytes;
@@ -1405,26 +1551,58 @@ _httpReadCDSA(
     *dataLength = 0;
 
     if (bytes == 0)
-      result = errSSLClosedAbort;
+      result = errSSLClosedGraceful;
     else if (errno == EAGAIN)
       result = errSSLWouldBlock;
-    else if (errno == EPIPE)
-      result = errSSLClosedAbort;
     else
-      result = errSSLInternal;
+      result = errSSLClosedAbort;
   }
 
-  return result;
+  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 */
+
+
+  http = (http_t *)ptr;
+
+  if (!http->blocking)
+  {
+   /*
+    * Make sure we have data before we read...
+    */
+
+    if (!http_wait(http, 10000, 0))
+    {
+      http->error = ETIMEDOUT;
+      return (-1);
+    }
+  }
+
+  return (recv(http->fd, data, length, 0));
+}
+#endif /* HAVE_SSL && HAVE_GNUTLS */
+
+
 /*
  * 'httpReconnect()' - Reconnect to a HTTP server.
  */
 
 int                                    /* O - 0 on success, non-zero on failure */
-httpReconnect(http_t *http)            /* I - HTTP connection */
+httpReconnect(http_t *http)            /* I - Connection to server */
 {
   http_addrlist_t      *addr;          /* Connected address */
 
@@ -1487,11 +1665,11 @@ httpReconnect(http_t *http)             /* I - HTTP connection */
 
     if (http_setup_ssl(http) != 0)
     {
-#ifdef WIN32
+#  ifdef WIN32
       closesocket(http->fd);
-#else
+#  else
       close(http->fd);
-#endif /* WIN32 */
+#  endif /* WIN32 */
 
       return (-1);
     }
@@ -1504,6 +1682,67 @@ httpReconnect(http_t *http)              /* I - HTTP connection */
 }
 
 
+/*
+ * 'httpSetAuthString()' - Set the current authorization string.
+ *
+ * This function just stores a copy of the current authorization string in
+ * the HTTP connection object.  You must still call httpSetField() to set
+ * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
+ * httpHead(), httpOptions(), httpPost, or httpPut().
+ *
+ * @since CUPS 1.3@
+ */
+
+void
+httpSetAuthString(http_t     *http,    /* I - Connection to server */
+                  const char *scheme,  /* I - Auth scheme (NULL to clear it) */
+                 const char *data)     /* I - Auth data (NULL for none) */
+{
+ /*
+  * Range check input...
+  */
+
+  if (!http)
+    return;
+
+  if (http->authstring && http->authstring != http->_authstring)
+    free(http->authstring);
+
+  http->authstring = http->_authstring;
+
+  if (scheme)
+  {
+   /*
+    * Set the current authorization string...
+    */
+
+    int len = (int)strlen(scheme) + (data ? (int)strlen(data) + 1 : 0) + 1;
+    char *temp;
+
+    if (len > (int)sizeof(http->_authstring))
+    {
+      if ((temp = malloc(len)) == NULL)
+        len = sizeof(http->_authstring);
+      else
+        http->authstring = temp;
+    }
+
+    if (data)
+      snprintf(http->authstring, len, "%s %s", scheme, data);
+    else
+      strlcpy(http->authstring, scheme, len);
+  }
+  else
+  {
+   /*
+    * Clear the current authorization string...
+    */
+
+    http->_authstring[0] = '\0';
+  }
+}
+
+
 /*
  * 'httpSetCookie()' - Set the cookie value(s)...
  *
@@ -1536,7 +1775,7 @@ httpSetCookie(http_t     *http,           /* I - Connection */
  */
 
 void
-httpSetExpect(http_t        *http,     /* I - HTTP connection */
+httpSetExpect(http_t        *http,     /* I - Connection to server */
               http_status_t expect)    /* I - HTTP status to expect (HTTP_CONTINUE) */
 {
   if (http)
@@ -1549,7 +1788,7 @@ httpSetExpect(http_t        *http,        /* I - HTTP connection */
  */
 
 void
-httpSetField(http_t       *http,       /* I - HTTP connection */
+httpSetField(http_t       *http,       /* I - Connection to server */
              http_field_t field,       /* I - Field index */
             const char   *value)       /* I - Value */
 {
@@ -1560,6 +1799,19 @@ httpSetField(http_t       *http, /* I - HTTP connection */
     return;
 
   strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
+
+ /*
+  * Special case for Authorization: as its contents can be
+  * longer than HTTP_MAX_VALUE
+  */
+
+  if (field == HTTP_FIELD_AUTHORIZATION)
+  {
+    if (http->field_authorization)
+      free(http->field_authorization);
+
+    http->field_authorization = strdup(value);
+  }
 }
 
 
@@ -1570,7 +1822,7 @@ httpSetField(http_t       *http,  /* I - HTTP connection */
  */
 
 void
-httpSetLength(http_t *http,            /* I - HTTP connection */
+httpSetLength(http_t *http,            /* I - Connection to server */
               size_t length)           /* I - Length (0 for chunked) */
 {
   if (!http)
@@ -1595,7 +1847,7 @@ httpSetLength(http_t *http,               /* I - HTTP connection */
  */
 
 int                                    /* O - Status of call (0 = success) */
-httpTrace(http_t     *http,            /* I - HTTP connection */
+httpTrace(http_t     *http,            /* I - Connection to server */
           const char *uri)             /* I - URI for trace */
 {
   return (http_send(http, HTTP_TRACE, uri));
@@ -1607,7 +1859,7 @@ httpTrace(http_t     *http,               /* I - HTTP connection */
  */
 
 http_status_t                          /* O - HTTP status */
-httpUpdate(http_t *http)               /* I - HTTP connection */
+httpUpdate(http_t *http)               /* I - Connection to server */
 {
   char         line[32768],            /* Line from connection... */
                *value;                 /* Pointer to value on line */
@@ -1690,6 +1942,7 @@ httpUpdate(http_t *http)          /* I - HTTP connection */
        case HTTP_PUT :
            http->state ++;
        case HTTP_POST_SEND :
+       case HTTP_HEAD :
            break;
 
        default :
@@ -1786,7 +2039,7 @@ httpUpdate(http_t *http)          /* I - HTTP connection */
  */
 
 int                                    /* O - 1 if data is available, 0 otherwise */
-httpWait(http_t *http,                 /* I - HTTP connection */
+httpWait(http_t *http,                 /* I - Connection to server */
          int    msec)                  /* I - Milliseconds to wait */
 {
  /*
@@ -1799,11 +2052,21 @@ httpWait(http_t *http,                  /* I - HTTP connection */
   if (http->used)
     return (1);
 
+ /*
+  * Flush pending data, if any...
+  */
+
+  if (http->wused)
+  {
+    if (httpFlushWrite(http) < 0)
+      return (0);
+  }
+
  /*
   * If not, check the SSL/TLS buffers and do a select() on the connection...
   */
 
-  return (http_wait(http, msec));
+  return (http_wait(http, msec, 1));
 }
 
 
@@ -1817,7 +2080,7 @@ httpWait(http_t *http,                    /* I - HTTP connection */
  */
  
 int                                    /* O - Number of bytes written */
-httpWrite(http_t     *http,            /* I - HTTP connection */
+httpWrite(http_t     *http,            /* I - Connection to server */
           const char *buffer,          /* I - Buffer for data */
          int        length)            /* I - Number of bytes to write */
 {
@@ -1832,15 +2095,15 @@ httpWrite(http_t     *http,             /* I - HTTP connection */
  */
  
 ssize_t                                        /* O - Number of bytes written */
-httpWrite2(http_t     *http,           /* I - HTTP connection */
+httpWrite2(http_t     *http,           /* I - Connection to server */
            const char *buffer,         /* I - Buffer for data */
           size_t     length)           /* I - Number of bytes to write */
 {
   ssize_t      bytes;                  /* Bytes written */
 
 
-  DEBUG_printf(("httpWrite(http=%p, buffer=%p, length=%d)\n", http,
-                buffer, length));
+  DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")\n", http,
+                buffer, CUPS_LLCAST length));
 
  /*
   * Range check input...
@@ -1863,8 +2126,8 @@ httpWrite2(http_t     *http,              /* I - HTTP connection */
   {
     if (http->wused && (length + http->wused) > sizeof(http->wbuffer))
     {
-      DEBUG_printf(("    flushing buffer (wused=%d, length=%d)\n",
-                    http->wused, length));
+      DEBUG_printf(("httpWrite2: Flushing buffer (wused=%d, length="
+                    CUPS_LLFMT ")\n", http->wused, CUPS_LLCAST length));
 
       httpFlushWrite(http);
     }
@@ -1875,11 +2138,12 @@ httpWrite2(http_t     *http,            /* I - HTTP connection */
       * Write to buffer...
       */
 
-      DEBUG_printf(("    copying %d bytes to wbuffer...\n", length));
+      DEBUG_printf(("httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...\n",
+                    CUPS_LLCAST length));
 
       memcpy(http->wbuffer + http->wused, buffer, length);
-      http->wused += length;
-      bytes = length;
+      http->wused += (int)length;
+      bytes = (ssize_t)length;
     }
     else
     {
@@ -1887,14 +2151,16 @@ httpWrite2(http_t     *http,            /* I - HTTP connection */
       * Otherwise write the data directly...
       */
 
-      DEBUG_printf(("    writing %d bytes to socket...\n", length));
+      DEBUG_printf(("httpWrite2: Writing " CUPS_LLFMT " bytes to socket...\n",
+                    CUPS_LLCAST length));
 
       if (http->data_encoding == HTTP_ENCODE_CHUNKED)
-       bytes = http_write_chunk(http, buffer, length);
+       bytes = (ssize_t)http_write_chunk(http, buffer, (int)length);
       else
-       bytes = http_write(http, buffer, length);
+       bytes = (ssize_t)http_write(http, buffer, (int)length);
 
-      DEBUG_printf(("    wrote %d bytes...\n", bytes));
+      DEBUG_printf(("httpWrite2: Wrote " CUPS_LLFMT " bytes...\n",
+                    CUPS_LLCAST bytes));
     }
 
     if (http->data_encoding == HTTP_ENCODE_LENGTH)
@@ -1950,7 +2216,7 @@ httpWrite2(http_t     *http,              /* I - HTTP connection */
 
 #if defined(HAVE_SSL) && defined(HAVE_CDSASSL)
 /*
- * '_httpWriteCDSA()' - Write function for CDSA encryption code.
+ * '_httpWriteCDSA()' - Write function for the CDSA library.
  */
 
 OSStatus                               /* O  - -1 on error, 0 on success */
@@ -1961,13 +2227,21 @@ _httpWriteCDSA(
 {
   OSStatus     result;                 /* Return value */
   ssize_t      bytes;                  /* Number of bytes read */
+  http_t       *http;                  /* HTTP connection */
+
+
+  http = (http_t *)connection;
 
   do
-    bytes = write((int)connection, data, *dataLength);
+  {
+    bytes = write(http->fd, data, *dataLength);
+  }
   while (bytes == -1 && errno == EINTR);
 
   if (bytes == *dataLength)
+  {
     result = 0;
+  }
   else if (bytes >= 0)
   {
     *dataLength = bytes;
@@ -1979,25 +2253,243 @@ _httpWriteCDSA(
   
     if (errno == EAGAIN)
       result = errSSLWouldBlock;
-    else if (errno == EPIPE)
-      result = errSSLClosedAbort;
     else
-      result = errSSLInternal;
+      result = errSSLClosedAbort;
   }
 
-  return result;
+  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 */
+{
+  return (send(((http_t *)ptr)->fd, data, length, 0));
+}
+#endif /* HAVE_SSL && HAVE_GNUTLS */
+
+
+#if defined(HAVE_SSL) && defined(HAVE_LIBSSL)
+/*
+ * 'http_bio_ctrl()' - Control the HTTP connection.
+ */
+
+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 */
+{
+  switch (cmd)
+  {
+    default :
+        return (0);
+
+    case BIO_CTRL_RESET :
+        h->ptr = NULL;
+       return (0);
+
+    case BIO_C_SET_FILE_PTR :
+        h->ptr  = arg2;
+       h->init = 1;
+       return (1);
+
+    case BIO_C_GET_FILE_PTR :
+        if (arg2)
+       {
+         *((void **)arg2) = h->ptr;
+         return (1);
+       }
+       else
+         return (0);
+        
+    case BIO_CTRL_DUP :
+    case BIO_CTRL_FLUSH :
+        return (1);
+  }
+}
+
+
+/*
+ * 'http_bio_free()' - Free OpenSSL data.
+ */
+
+static int                             /* O - 1 on success, 0 on failure */
+http_bio_free(BIO *h)                  /* I - BIO data */
+{
+  if (!h)
+    return (0);
+
+  if (h->shutdown)
+  {
+    h->init  = 0;
+    h->flags = 0;
+  }
+
+  return (1);
+}
+
+
+/*
+ * '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...
+    */
+
+    if (!http_wait(http, 10000, 0))
+    {
+#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 DEBUG
+/*
+ * 'http_debug_hex()' - Do a hex dump of a buffer.
+ */
+
+static void
+http_debug_hex(const char *prefix,     /* I - Prefix for line */
+               const char *buffer,     /* I - Buffer to dump */
+               int        bytes)       /* I - Bytes to dump */
+{
+  int  i, j,                           /* Looping vars */
+       ch;                             /* Current character */
+  char line[255],                      /* Line buffer */
+       *start,                         /* Start of line after prefix */
+       *ptr;                           /* Pointer into line */
+  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
+
+
+  if (cg->debug_init && cg->debug_fd < 0)
+    return;
+
+  DEBUG_printf(("%s: %d bytes:\n", prefix, bytes));
+
+  snprintf(line, sizeof(line), "%s: ", prefix);
+  start = line + strlen(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);
+
+    while (j < 16)
+    {
+      strcpy(ptr, "  ");
+      ptr += 2;
+      j ++;
+    }
+
+    strcpy(ptr, "  ");
+    ptr += 2;
+
+    for (j = 0; j < 16 && (i + j) < bytes; j ++)
+    {
+      ch = buffer[i + j] & 255;
+
+      if (ch < ' ' || ch >= 127)
+       ch = '.';
+
+      *ptr++ = ch;
+    }
+
+    *ptr = '\0';
+    DEBUG_puts(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 */
+static http_field_t                    /* O - Field index */
+http_field(const char *name)           /* I - String name */
 {
-  int  i;                      /* Looping var */
+  int  i;                              /* Looping var */
 
 
   for (i = 0; i < HTTP_FIELD_MAX; i ++)
@@ -2014,7 +2506,7 @@ http_field(const char *name)      /* I - String name */
  */
 
 static int                             /* O - Bytes read */
-http_read_ssl(http_t *http,            /* I - HTTP connection */
+http_read_ssl(http_t *http,            /* I - Connection to server */
              char   *buf,              /* I - Buffer to store data */
              int    len)               /* I - Length of buffer */
 {
@@ -2030,7 +2522,7 @@ http_read_ssl(http_t *http,               /* I - HTTP connection */
   size_t       processed;              /* Number of bytes processed */
 
 
-  error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
+  error = SSLRead(((http_tls_t *)http->tls)->session, buf, len, &processed);
 
   switch (error)
   {
@@ -2066,13 +2558,12 @@ http_read_ssl(http_t *http,             /* I - HTTP connection */
  */
 
 static int                     /* O - 0 on success, non-zero on error */
-http_send(http_t       *http,  /* I - HTTP connection */
+http_send(http_t       *http,  /* I - Connection to server */
           http_state_t request,        /* I - Request code */
          const char   *uri)    /* I - URI */
 {
   int          i;              /* Looping var */
-  char         *ptr,           /* Pointer in buffer */
-               buf[1024];      /* Encoded URI buffer */
+  char         buf[1024];      /* Encoded URI buffer */
   static const char * const codes[] =
                {               /* Request code strings */
                  NULL,
@@ -2089,8 +2580,6 @@ http_send(http_t       *http,     /* I - HTTP connection */
                  "TRACE",
                  "CLOSE"
                };
-  static const char hex[] = "0123456789ABCDEF";
-                               /* Hex digits */
 
 
   DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
@@ -2110,20 +2599,7 @@ http_send(http_t       *http,    /* I - HTTP connection */
   * Encode the URI as needed...
   */
 
-  for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
-    if (*uri <= ' ' || *uri >= 127)
-    {
-      if (ptr < (buf + sizeof(buf) - 1))
-        *ptr ++ = '%';
-      if (ptr < (buf + sizeof(buf) - 1))
-        *ptr ++ = hex[(*uri >> 4) & 15];
-      if (ptr < (buf + sizeof(buf) - 1))
-        *ptr ++ = hex[*uri & 15];
-    }
-    else
-      *ptr ++ = *uri;
-
-  *ptr = '\0';
+  _httpEncodeURI(buf, uri, sizeof(buf));
 
  /*
   * See if we had an error the last time around; if so, reconnect...
@@ -2133,11 +2609,20 @@ http_send(http_t       *http,   /* I - HTTP connection */
     if (httpReconnect(http))
       return (-1);
 
+ /*
+  * Flush any written data that is pending...
+  */
+
+  if (http->wused)
+    httpFlushWrite(http);
+
  /*
   * Send the request header...
   */
 
-  http->state = request;
+  http->state         = request;
+  http->data_encoding = HTTP_ENCODE_FIELDS;
+
   if (request == HTTP_POST || request == HTTP_PUT)
     http->state ++;
 
@@ -2160,9 +2645,11 @@ http_send(http_t       *http,    /* I - HTTP connection */
   for (i = 0; i < HTTP_FIELD_MAX; i ++)
     if (http->fields[i][0] != '\0')
     {
-      DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
+      DEBUG_printf(("http_send: %s: %s\n", http_fields[i],
+                    httpGetField(http, i)));
 
-      if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
+      if (httpPrintf(http, "%s: %s\r\n", http_fields[i], 
+                    httpGetField(http, i)) < 1)
       {
        http->status = HTTP_ERROR;
        return (-1);
@@ -2190,9 +2677,26 @@ http_send(http_t       *http,    /* I - HTTP connection */
     return (-1);
   }
 
+  httpFlushWrite(http);
   httpGetLength2(http);
   httpClearFields(http);
 
+ /*
+  * The Kerberos and AuthRef authentication strings can only be used once...
+  */
+
+  if (http->field_authorization && http->authstring && 
+      (!strncmp(http->authstring, "Negotiate", 9) || 
+       !strncmp(http->authstring, "AuthRef", 7)))
+  {
+    http->_authstring[0] = '\0';
+
+    if (http->authstring != http->_authstring)
+      free(http->authstring);
+  
+    http->authstring = http->_authstring;
+  }
+
   return (0);
 }
 
@@ -2203,18 +2707,19 @@ http_send(http_t       *http,   /* I - HTTP connection */
  */
 
 static int                             /* O - Status of connection */
-http_setup_ssl(http_t *http)           /* I - HTTP connection */
+http_setup_ssl(http_t *http)           /* I - Connection to server */
 {
 #  ifdef HAVE_LIBSSL
-  SSL_CTX      *context;       /* Context for encryption */
-  SSL          *conn;          /* Connection for encryption */
+  SSL_CTX      *context;               /* Context for encryption */
+  SSL          *conn;                  /* Connection for encryption */
+  BIO          *bio;                   /* BIO data */
 #  elif defined(HAVE_GNUTLS)
-  http_tls_t   *conn;          /* TLS session object */
+  http_tls_t   *conn;                  /* TLS session object */
   gnutls_certificate_client_credentials *credentials;
-                               /* TLS credentials */
+                                       /* TLS credentials */
 #  elif defined(HAVE_CDSASSL)
-  SSLContextRef        conn;           /* Context for encryption */
-  OSStatus     error;          /* Error info */
+  OSStatus     error;                  /* Error code */
+  http_tls_t   *conn;                  /* CDSA connection information */
 #  endif /* HAVE_LIBSSL */
 
 
@@ -2225,9 +2730,12 @@ http_setup_ssl(http_t *http)             /* I - HTTP connection */
 
   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);
+
   conn = SSL_new(context);
+  SSL_set_bio(conn, bio, bio);
 
-  SSL_set_fd(conn, http->fd);
   if (SSL_connect(conn) != 1)
   {
 #    ifdef DEBUG
@@ -2251,9 +2759,7 @@ http_setup_ssl(http_t *http)              /* I - HTTP connection */
   }
 
 #  elif defined(HAVE_GNUTLS)
-  conn = (http_tls_t *)malloc(sizeof(http_tls_t));
-
-  if (conn == NULL)
+  if ((conn = (http_tls_t *)malloc(sizeof(http_tls_t))) == NULL)
   {
     http->error  = errno;
     http->status = HTTP_ERROR;
@@ -2278,7 +2784,9 @@ http_setup_ssl(http_t *http)              /* I - HTTP connection */
   gnutls_init(&(conn->session), GNUTLS_CLIENT);
   gnutls_set_default_priority(conn->session);
   gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
-  gnutls_transport_set_ptr(conn->session, http->fd);
+  gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr)http);
+  gnutls_transport_set_pull_function(conn->session, _httpReadGNUTLS);
+  gnutls_transport_set_push_function(conn->session, _httpWriteGNUTLS);
 
   if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
   {
@@ -2291,34 +2799,52 @@ http_setup_ssl(http_t *http)            /* I - HTTP connection */
   conn->credentials = credentials;
 
 #  elif defined(HAVE_CDSASSL)
-  error = SSLNewContext(false, &conn);
+  conn = (http_tls_t *)calloc(1, sizeof(http_tls_t));
+
+  if (conn == NULL)
+    return (-1);
+
+  if ((error = SSLNewContext(false, &conn->session)))
+  {
+    http->error  = error;
+    http->status = HTTP_ERROR;
+
+    free(conn);
+    return (-1);
+  }
+
+ /*
+  * Use a union to resolve warnings about int/pointer size mismatches...
+  */
+
+  error = SSLSetConnection(conn->session, http);
 
   if (!error)
-    error = SSLSetIOFuncs(conn, _httpReadCDSA, _httpWriteCDSA);
+    error = SSLSetIOFuncs(conn->session, _httpReadCDSA, _httpWriteCDSA);
 
   if (!error)
-    error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
+    error = SSLSetAllowsExpiredCerts(conn->session, true);
 
   if (!error)
-    error = SSLSetAllowsExpiredCerts(conn, true);
+    error = SSLSetAllowsAnyRoot(conn->session, true);
 
   if (!error)
-    error = SSLSetAllowsAnyRoot(conn, true);
+    error = SSLSetProtocolVersionEnabled(conn->session, kSSLProtocol2, false);
 
   if (!error)
   {
-    while ((error = SSLHandshake(conn)) == errSSLWouldBlock)
+    while ((error = SSLHandshake(conn->session)) == errSSLWouldBlock)
       usleep(1000);
   }
 
-  if (error != 0)
+  if (error)
   {
     http->error  = error;
     http->status = HTTP_ERROR;
 
-    SSLDisposeContext(conn);
+    SSLDisposeContext(conn->session);
 
-    close(http->fd);
+    free(conn);
 
     return (-1);
   }
@@ -2336,11 +2862,11 @@ http_setup_ssl(http_t *http)            /* I - HTTP connection */
  */
 
 static void
-http_shutdown_ssl(http_t *http)        /* I - HTTP connection */
+http_shutdown_ssl(http_t *http)                /* I - Connection to server */
 {
 #  ifdef HAVE_LIBSSL
-  SSL_CTX      *context;       /* Context for encryption */
-  SSL          *conn;          /* Connection for encryption */
+  SSL_CTX      *context;               /* Context for encryption */
+  SSL          *conn;                  /* Connection for encryption */
 
 
   conn    = (SSL *)(http->tls);
@@ -2351,9 +2877,9 @@ http_shutdown_ssl(http_t *http)   /* I - HTTP connection */
   SSL_free(conn);
 
 #  elif defined(HAVE_GNUTLS)
-  http_tls_t      *conn;       /* Encryption session */
+  http_tls_t      *conn;               /* Encryption session */
   gnutls_certificate_client_credentials *credentials;
-                               /* TLS credentials */
+                                       /* TLS credentials */
 
 
   conn = (http_tls_t *)(http->tls);
@@ -2366,10 +2892,20 @@ http_shutdown_ssl(http_t *http) /* I - HTTP connection */
   free(conn);
 
 #  elif defined(HAVE_CDSASSL)
-  while (SSLClose((SSLContextRef)http->tls) == errSSLWouldBlock)
+  http_tls_t      *conn;               /* CDSA connection information */
+
+
+  conn = (http_tls_t *)(http->tls);
+
+  while (SSLClose(conn->session) == errSSLWouldBlock)
     usleep(1000);
 
-  SSLDisposeContext((SSLContextRef)http->tls);
+  SSLDisposeContext(conn->session);
+
+  if (conn->certsArray)
+    CFRelease(conn->certsArray);
+
+  free(conn);
 #  endif /* HAVE_LIBSSL */
 
   http->tls = NULL;
@@ -2382,11 +2918,11 @@ http_shutdown_ssl(http_t *http) /* I - HTTP connection */
  * 'http_upgrade()' - Force upgrade to TLS encryption.
  */
 
-static int                     /* O - Status of connection */
-http_upgrade(http_t *http)     /* I - HTTP connection */
+static int                             /* O - Status of connection */
+http_upgrade(http_t *http)             /* I - Connection to server */
 {
-  int          ret;            /* Return value */
-  http_t       myhttp;         /* Local copy of HTTP data */
+  int          ret;                    /* Return value */
+  http_t       myhttp;                 /* Local copy of HTTP data */
 
 
   DEBUG_printf(("http_upgrade(%p)\n", http));
@@ -2403,43 +2939,34 @@ http_upgrade(http_t *http)      /* I - HTTP connection */
   * encryption on the link...
   */
 
-  httpClearFields(&myhttp);
-  httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
-  httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
+  http->field_authorization = NULL;    /* Don't free the auth string */
 
-  if ((ret = httpOptions(&myhttp, "*")) == 0)
+  httpClearFields(http);
+  httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
+  httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
+
+  if ((ret = httpOptions(http, "*")) == 0)
   {
    /*
     * Wait for the secure connection...
     */
 
-    while (httpUpdate(&myhttp) == HTTP_CONTINUE);
+    while (httpUpdate(http) == HTTP_CONTINUE);
   }
 
-  httpFlush(&myhttp);
+  httpFlush(http);
 
  /*
-  * Copy the HTTP data back over, if any...
+  * Restore the HTTP request data...
   */
 
-  http->fd         = myhttp.fd;
-  http->error      = myhttp.error;
-  http->activity   = myhttp.activity;
-  http->status     = myhttp.status;
-  http->version    = myhttp.version;
-  http->keep_alive = myhttp.keep_alive;
-  http->used       = myhttp.used;
-
-  if (http->used)
-    memcpy(http->buffer, myhttp.buffer, http->used);
-
-  http->auth_type   = myhttp.auth_type;
-  http->nonce_count = myhttp.nonce_count;
-
-  memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
-
-  http->tls        = myhttp.tls;
-  http->encryption = myhttp.encryption;
+  memcpy(http->fields, myhttp.fields, sizeof(http->fields));
+  http->data_encoding       = myhttp.data_encoding;
+  http->data_remaining      = myhttp.data_remaining;
+  http->_data_remaining     = myhttp._data_remaining;
+  http->expect              = myhttp.expect;
+  http->field_authorization = myhttp.field_authorization;
+  http->digest_tries        = myhttp.digest_tries;
 
  /*
   * See if we actually went secure...
@@ -2474,15 +3001,17 @@ http_upgrade(http_t *http)      /* I - HTTP connection */
  */
 
 static int                             /* O - 1 if data is available, 0 otherwise */
-http_wait(http_t *http,                        /* I - HTTP connection */
-          int    msec)                 /* I - Milliseconds to wait */
+http_wait(http_t *http,                        /* I - Connection to server */
+          int    msec,                 /* I - Milliseconds to wait */
+         int    usessl)                /* I - Use SSL context? */
 {
-#ifndef WIN32
-  struct rlimit                limit;          /* Runtime limit */
-  int                  set_size;       /* Size of select set */
-#endif /* !WIN32 */
+#ifdef HAVE_POLL
+  struct pollfd                pfd;            /* Polled file descriptor */
+#else
+  fd_set               input_set;      /* select() input set */
   struct timeval       timeout;        /* Timeout */
-  int                  nfds;           /* Result from select() */
+#endif /* HAVE_POLL */
+  int                  nfds;           /* Result from select()/poll() */
 
 
   DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
@@ -2495,7 +3024,7 @@ http_wait(http_t *http,                   /* I - HTTP connection */
   */
 
 #ifdef HAVE_SSL
-  if (http->tls)
+  if (http->tls && usessl)
   {
 #  ifdef HAVE_LIBSSL
     if (SSL_pending((SSL *)(http->tls)))
@@ -2506,66 +3035,50 @@ http_wait(http_t *http,                 /* I - HTTP connection */
 #  elif defined(HAVE_CDSASSL)
     size_t bytes;                      /* Bytes that are available */
 
-    if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
+    if (!SSLGetBufferedReadSize(((http_tls_t *)http->tls)->session, &bytes) && bytes > 0)
       return (1);
 #  endif /* HAVE_LIBSSL */
   }
 #endif /* HAVE_SSL */
 
  /*
-  * Then try doing a select() to poll the socket...
+  * Then try doing a select() or poll() to poll the socket...
   */
 
-  if (!http->input_set)
-  {
-#ifdef WIN32
-   /*
-    * Windows has a fixed-size select() structure, different (surprise,
-    * surprise!) from all UNIX implementations.  Just allocate this
-    * fixed structure...
-    */
+#ifdef HAVE_POLL
+  pfd.fd     = http->fd;
+  pfd.events = POLLIN;
 
-    http->input_set = calloc(1, sizeof(fd_set));
-#else
-   /*
-    * Allocate the select() input set based upon the max number of file
-    * descriptors available for this process...
-    */
-
-    getrlimit(RLIMIT_NOFILE, &limit);
-
-    set_size = (limit.rlim_cur + 31) / 8 + 4;
-    if (set_size < sizeof(fd_set))
-      set_size = sizeof(fd_set);
-
-    http->input_set = calloc(1, set_size);
-#endif /* WIN32 */
-
-    if (!http->input_set)
-      return (0);
-  }
+  while ((nfds = poll(&pfd, 1, msec)) < 0 && errno == EINTR);
 
+#else
   do
   {
-    FD_SET(http->fd, http->input_set);
+    FD_ZERO(&input_set);
+    FD_SET(http->fd, &input_set);
+
+    DEBUG_printf(("http_wait: msec=%d, http->fd=%d\n", msec, http->fd));
 
     if (msec >= 0)
     {
       timeout.tv_sec  = msec / 1000;
       timeout.tv_usec = (msec % 1000) * 1000;
 
-      nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
+      nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
     }
     else
-      nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
+      nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
+
+    DEBUG_printf(("http_wait: select() returned %d...\n", nfds));
   }
-#ifdef WIN32
+#  ifdef WIN32
   while (nfds < 0 && WSAGetLastError() == WSAEINTR);
-#else
+#  else
   while (nfds < 0 && errno == EINTR);
-#endif /* WIN32 */
+#  endif /* WIN32 */
+#endif /* HAVE_POLL */
 
-  FD_CLR(http->fd, http->input_set);
+  DEBUG_printf(("http_wait: returning with nfds=%d...\n", nfds));
 
   return (nfds > 0);
 }
@@ -2576,7 +3089,7 @@ http_wait(http_t *http,                   /* I - HTTP connection */
  */
  
 static int                             /* O - Number of bytes written */
-http_write(http_t     *http,           /* I - HTTP connection */
+http_write(http_t     *http,           /* I - Connection to server */
           const char *buffer,          /* I - Buffer for data */
          int        length)            /* I - Number of bytes to write */
 {
@@ -2624,35 +3137,7 @@ http_write(http_t     *http,             /* I - HTTP connection */
   }
 
 #ifdef DEBUG
-  {
-    int i, j, ch;
-    printf("http_write: wrote %d bytes: \n", tbytes);
-    for (i = 0, buffer -= tbytes; i < tbytes; i += 16)
-    {
-      printf("   ");
-
-      for (j = 0; j < 16 && (i + j) < tbytes; j ++)
-        printf(" %02X", buffer[i + j] & 255);
-
-      while (j < 16)
-      {
-        printf("   ");
-       j ++;
-      }
-
-      printf("    ");
-      for (j = 0; j < 16 && (i + j) < tbytes; j ++)
-      {
-        ch = buffer[i + j] & 255;
-
-       if (ch < ' ' || ch == 127)
-         ch = '.';
-
-        putchar(ch);
-      }
-      putchar('\n');
-    }
-  }
+  http_debug_hex("http_write", buffer - tbytes, tbytes);
 #endif /* DEBUG */
 
   return (tbytes);
@@ -2664,7 +3149,7 @@ http_write(http_t     *http,              /* I - HTTP connection */
  */
 
 static int                             /* O - Number bytes written */
-http_write_chunk(http_t     *http,     /* I - HTTP connection */
+http_write_chunk(http_t     *http,     /* I - Connection to server */
                  const char *buffer,   /* I - Buffer to write */
                 int        length)     /* I - Length of buffer */
 {
@@ -2679,7 +3164,7 @@ http_write_chunk(http_t     *http,        /* I - HTTP connection */
   */
 
   sprintf(header, "%x\r\n", length);
-  if (http_write(http, header, strlen(header)) < 0)
+  if (http_write(http, header, (int)strlen(header)) < 0)
   {
     DEBUG_puts("    http_write of length failed!");
     return (-1);
@@ -2707,7 +3192,7 @@ http_write_chunk(http_t     *http,        /* I - HTTP connection */
  */
 
 static int                             /* O - Bytes written */
-http_write_ssl(http_t     *http,       /* I - HTTP connection */
+http_write_ssl(http_t     *http,       /* I - Connection to server */
               const char *buf,         /* I - Buffer holding data */
               int        len)          /* I - Length of buffer */
 {
@@ -2722,7 +3207,7 @@ http_write_ssl(http_t     *http,  /* I - HTTP connection */
   size_t       processed;              /* Number of bytes processed */
 
 
-  error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
+  error = SSLWrite(((http_tls_t *)http->tls)->session, buf, len, &processed);
 
   switch (error)
   {
@@ -2754,5 +3239,5 @@ http_write_ssl(http_t     *http,  /* I - HTTP connection */
 
 
 /*
- * End of "$Id: http.c 5200 2006-02-28 00:10:32Z mike $".
+ * End of "$Id: http.c 7661 2008-06-16 21:46:51Z mike $".
  */