"Fossies" - the Fresh Open Source Software Archive

Member "cups-2.3rc1/cups/http.c" (21 May 2019, 117657 Bytes) of package /linux/misc/cups-2.3rc1-source.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "http.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.2.11_vs_2.3b8.

    1 /*
    2  * HTTP routines for CUPS.
    3  *
    4  * Copyright 2007-2018 by Apple Inc.
    5  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
    6  *
    7  * This file contains Kerberos support code, copyright 2006 by
    8  * Jelmer Vernooij.
    9  *
   10  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
   11  * information.
   12  */
   13 
   14 /*
   15  * Include necessary headers...
   16  */
   17 
   18 #include "cups-private.h"
   19 #include "debug-internal.h"
   20 #include <fcntl.h>
   21 #include <math.h>
   22 #ifdef _WIN32
   23 #  include <tchar.h>
   24 #else
   25 #  include <signal.h>
   26 #  include <sys/time.h>
   27 #  include <sys/resource.h>
   28 #endif /* _WIN32 */
   29 #ifdef HAVE_POLL
   30 #  include <poll.h>
   31 #endif /* HAVE_POLL */
   32 #  ifdef HAVE_LIBZ
   33 #    include <zlib.h>
   34 #  endif /* HAVE_LIBZ */
   35 
   36 
   37 /*
   38  * Local functions...
   39  */
   40 
   41 static void     http_add_field(http_t *http, http_field_t field, const char *value, int append);
   42 #ifdef HAVE_LIBZ
   43 static void     http_content_coding_finish(http_t *http);
   44 static void     http_content_coding_start(http_t *http,
   45                           const char *value);
   46 #endif /* HAVE_LIBZ */
   47 static http_t       *http_create(const char *host, int port,
   48                          http_addrlist_t *addrlist, int family,
   49                      http_encryption_t encryption,
   50                      int blocking, _http_mode_t mode);
   51 #ifdef DEBUG
   52 static void     http_debug_hex(const char *prefix, const char *buffer,
   53                            int bytes);
   54 #endif /* DEBUG */
   55 static ssize_t      http_read(http_t *http, char *buffer, size_t length);
   56 static ssize_t      http_read_buffered(http_t *http, char *buffer, size_t length);
   57 static ssize_t      http_read_chunk(http_t *http, char *buffer, size_t length);
   58 static int      http_send(http_t *http, http_state_t request,
   59                       const char *uri);
   60 static ssize_t      http_write(http_t *http, const char *buffer,
   61                        size_t length);
   62 static ssize_t      http_write_chunk(http_t *http, const char *buffer,
   63                              size_t length);
   64 static off_t        http_set_length(http_t *http);
   65 static void     http_set_timeout(int fd, double timeout);
   66 static void     http_set_wait(http_t *http);
   67 
   68 #ifdef HAVE_SSL
   69 static int      http_tls_upgrade(http_t *http);
   70 #endif /* HAVE_SSL */
   71 
   72 
   73 /*
   74  * Local globals...
   75  */
   76 
   77 static const char * const http_fields[] =
   78             {
   79               "Accept-Language",
   80               "Accept-Ranges",
   81               "Authorization",
   82               "Connection",
   83               "Content-Encoding",
   84               "Content-Language",
   85               "Content-Length",
   86               "Content-Location",
   87               "Content-MD5",
   88               "Content-Range",
   89               "Content-Type",
   90               "Content-Version",
   91               "Date",
   92               "Host",
   93               "If-Modified-Since",
   94               "If-Unmodified-since",
   95               "Keep-Alive",
   96               "Last-Modified",
   97               "Link",
   98               "Location",
   99               "Range",
  100               "Referer",
  101               "Retry-After",
  102               "Transfer-Encoding",
  103               "Upgrade",
  104               "User-Agent",
  105               "WWW-Authenticate",
  106               "Accept-Encoding",
  107               "Allow",
  108               "Server",
  109               "Authentication-Info"
  110             };
  111 
  112 
  113 /*
  114  * 'httpAcceptConnection()' - Accept a new HTTP client connection from the
  115  *                            specified listening socket.
  116  *
  117  * @since CUPS 1.7/macOS 10.9@
  118  */
  119 
  120 http_t *                /* O - HTTP connection or @code NULL@ */
  121 httpAcceptConnection(int fd,        /* I - Listen socket file descriptor */
  122                      int blocking)  /* I - 1 if the connection should be
  123                                blocking, 0 otherwise */
  124 {
  125   http_t        *http;      /* HTTP connection */
  126   http_addrlist_t   addrlist;   /* Dummy address list */
  127   socklen_t     addrlen;    /* Length of address */
  128   int           val;        /* Socket option value */
  129 
  130 
  131  /*
  132   * Range check input...
  133   */
  134 
  135   if (fd < 0)
  136     return (NULL);
  137 
  138  /*
  139   * Create the client connection...
  140   */
  141 
  142   memset(&addrlist, 0, sizeof(addrlist));
  143 
  144   if ((http = http_create(NULL, 0, &addrlist, AF_UNSPEC,
  145                           HTTP_ENCRYPTION_IF_REQUESTED, blocking,
  146                           _HTTP_MODE_SERVER)) == NULL)
  147     return (NULL);
  148 
  149  /*
  150   * Accept the client and get the remote address...
  151   */
  152 
  153   addrlen = sizeof(http_addr_t);
  154 
  155   if ((http->fd = accept(fd, (struct sockaddr *)&(http->addrlist->addr),
  156              &addrlen)) < 0)
  157   {
  158     _cupsSetHTTPError(HTTP_STATUS_ERROR);
  159     httpClose(http);
  160 
  161     return (NULL);
  162   }
  163 
  164   http->hostaddr = &(http->addrlist->addr);
  165 
  166   if (httpAddrLocalhost(http->hostaddr))
  167     strlcpy(http->hostname, "localhost", sizeof(http->hostname));
  168   else
  169     httpAddrString(http->hostaddr, http->hostname, sizeof(http->hostname));
  170 
  171 #ifdef SO_NOSIGPIPE
  172  /*
  173   * Disable SIGPIPE for this socket.
  174   */
  175 
  176   val = 1;
  177   setsockopt(http->fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
  178 #endif /* SO_NOSIGPIPE */
  179 
  180  /*
  181   * Using TCP_NODELAY improves responsiveness, especially on systems
  182   * with a slow loopback interface.  Since we write large buffers
  183   * when sending print files and requests, there shouldn't be any
  184   * performance penalty for this...
  185   */
  186 
  187   val = 1;
  188   setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, CUPS_SOCAST &val, sizeof(val));
  189 
  190 #ifdef FD_CLOEXEC
  191  /*
  192   * Close this socket when starting another process...
  193   */
  194 
  195   fcntl(http->fd, F_SETFD, FD_CLOEXEC);
  196 #endif /* FD_CLOEXEC */
  197 
  198   return (http);
  199 }
  200 
  201 
  202 /*
  203  * 'httpAddCredential()' - Allocates and adds a single credential to an array.
  204  *
  205  * Use @code cupsArrayNew(NULL, NULL)@ to create a credentials array.
  206  *
  207  * @since CUPS 1.5/macOS 10.7@
  208  */
  209 
  210 int                 /* O - 0 on success, -1 on error */
  211 httpAddCredential(
  212     cups_array_t *credentials,      /* I - Credentials array */
  213     const void   *data,         /* I - PEM-encoded X.509 data */
  214     size_t       datalen)       /* I - Length of data */
  215 {
  216   http_credential_t *credential;    /* Credential data */
  217 
  218 
  219   if ((credential = malloc(sizeof(http_credential_t))) != NULL)
  220   {
  221     credential->datalen = datalen;
  222 
  223     if ((credential->data = malloc(datalen)) != NULL)
  224     {
  225       memcpy(credential->data, data, datalen);
  226       cupsArrayAdd(credentials, credential);
  227       return (0);
  228     }
  229 
  230     free(credential);
  231   }
  232 
  233   return (-1);
  234 }
  235 
  236 
  237 /*
  238  * 'httpBlocking()' - Set blocking/non-blocking behavior on a connection.
  239  */
  240 
  241 void
  242 httpBlocking(http_t *http,      /* I - HTTP connection */
  243              int    b)          /* I - 1 = blocking, 0 = non-blocking */
  244 {
  245   if (http)
  246   {
  247     http->blocking = b;
  248     http_set_wait(http);
  249   }
  250 }
  251 
  252 
  253 /*
  254  * 'httpCheck()' - Check to see if there is a pending response from the server.
  255  */
  256 
  257 int                 /* O - 0 = no data, 1 = data available */
  258 httpCheck(http_t *http)         /* I - HTTP connection */
  259 {
  260   return (httpWait(http, 0));
  261 }
  262 
  263 
  264 /*
  265  * 'httpClearCookie()' - Clear the cookie value(s).
  266  *
  267  * @since CUPS 1.1.19/macOS 10.3@
  268  */
  269 
  270 void
  271 httpClearCookie(http_t *http)       /* I - HTTP connection */
  272 {
  273   if (!http)
  274     return;
  275 
  276   if (http->cookie)
  277   {
  278     free(http->cookie);
  279     http->cookie = NULL;
  280   }
  281 }
  282 
  283 
  284 /*
  285  * 'httpClearFields()' - Clear HTTP request fields.
  286  */
  287 
  288 void
  289 httpClearFields(http_t *http)       /* I - HTTP connection */
  290 {
  291   http_field_t  field;          /* Current field */
  292 
  293 
  294   DEBUG_printf(("httpClearFields(http=%p)", (void *)http));
  295 
  296   if (http)
  297   {
  298     memset(http->_fields, 0, sizeof(http->fields));
  299 
  300     for (field = HTTP_FIELD_ACCEPT_LANGUAGE; field < HTTP_FIELD_MAX; field ++)
  301     {
  302       if (http->fields[field] && http->fields[field] != http->_fields[field])
  303         free(http->fields[field]);
  304 
  305       http->fields[field] = NULL;
  306     }
  307 
  308     if (http->mode == _HTTP_MODE_CLIENT)
  309     {
  310       if (http->hostname[0] == '/')
  311     httpSetField(http, HTTP_FIELD_HOST, "localhost");
  312       else
  313     httpSetField(http, HTTP_FIELD_HOST, http->hostname);
  314     }
  315 
  316     http->expect = (http_status_t)0;
  317   }
  318 }
  319 
  320 
  321 /*
  322  * 'httpClose()' - Close an HTTP connection.
  323  */
  324 
  325 void
  326 httpClose(http_t *http)         /* I - HTTP connection */
  327 {
  328 #ifdef HAVE_GSSAPI
  329   OM_uint32 minor_status;       /* Minor status code */
  330 #endif /* HAVE_GSSAPI */
  331 
  332 
  333   DEBUG_printf(("httpClose(http=%p)", (void *)http));
  334 
  335  /*
  336   * Range check input...
  337   */
  338 
  339   if (!http)
  340     return;
  341 
  342  /*
  343   * Close any open connection...
  344   */
  345 
  346   _httpDisconnect(http);
  347 
  348  /*
  349   * Free memory used...
  350   */
  351 
  352   httpAddrFreeList(http->addrlist);
  353 
  354   if (http->cookie)
  355     free(http->cookie);
  356 
  357 #ifdef HAVE_GSSAPI
  358   if (http->gssctx != GSS_C_NO_CONTEXT)
  359     gss_delete_sec_context(&minor_status, &http->gssctx, GSS_C_NO_BUFFER);
  360 
  361   if (http->gssname != GSS_C_NO_NAME)
  362     gss_release_name(&minor_status, &http->gssname);
  363 #endif /* HAVE_GSSAPI */
  364 
  365 #ifdef HAVE_AUTHORIZATION_H
  366   if (http->auth_ref)
  367     AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
  368 #endif /* HAVE_AUTHORIZATION_H */
  369 
  370   httpClearFields(http);
  371 
  372   if (http->authstring && http->authstring != http->_authstring)
  373     free(http->authstring);
  374 
  375   free(http);
  376 }
  377 
  378 
  379 /*
  380  * 'httpCompareCredentials()' - Compare two sets of X.509 credentials.
  381  *
  382  * @since CUPS 2.0/OS 10.10@
  383  */
  384 
  385 int                 /* O - 1 if they match, 0 if they do not */
  386 httpCompareCredentials(
  387     cups_array_t *cred1,        /* I - First set of X.509 credentials */
  388     cups_array_t *cred2)        /* I - Second set of X.509 credentials */
  389 {
  390   http_credential_t *temp1, *temp2; /* Temporary credentials */
  391 
  392 
  393   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))
  394     if (temp1->datalen != temp2->datalen)
  395       return (0);
  396     else if (memcmp(temp1->data, temp2->data, temp1->datalen))
  397       return (0);
  398 
  399   return (temp1 == temp2);
  400 }
  401 
  402 
  403 /*
  404  * 'httpConnect()' - Connect to a HTTP server.
  405  *
  406  * This function is deprecated - use @link httpConnect2@ instead.
  407  *
  408  * @deprecated@ @exclude all@
  409  */
  410 
  411 http_t *                /* O - New HTTP connection */
  412 httpConnect(const char *host,       /* I - Host to connect to */
  413             int        port)        /* I - Port number */
  414 {
  415   return (httpConnect2(host, port, NULL, AF_UNSPEC,
  416                        HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL));
  417 }
  418 
  419 
  420 /*
  421  * 'httpConnect2()' - Connect to a HTTP server.
  422  *
  423  * @since CUPS 1.7/macOS 10.9@
  424  */
  425 
  426 http_t *                /* O - New HTTP connection */
  427 httpConnect2(
  428     const char        *host,        /* I - Host to connect to */
  429     int               port,     /* I - Port number */
  430     http_addrlist_t   *addrlist,    /* I - List of addresses or @code NULL@ to lookup */
  431     int               family,       /* I - Address family to use or @code AF_UNSPEC@ for any */
  432     http_encryption_t encryption,   /* I - Type of encryption to use */
  433     int               blocking,     /* I - 1 for blocking connection, 0 for non-blocking */
  434     int               msec,     /* I - Connection timeout in milliseconds, 0 means don't connect */
  435     int               *cancel)      /* I - Pointer to "cancel" variable */
  436 {
  437   http_t    *http;          /* New HTTP connection */
  438 
  439 
  440   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));
  441 
  442  /*
  443   * Create the HTTP structure...
  444   */
  445 
  446   if ((http = http_create(host, port, addrlist, family, encryption, blocking,
  447                           _HTTP_MODE_CLIENT)) == NULL)
  448     return (NULL);
  449 
  450  /*
  451   * Optionally connect to the remote system...
  452   */
  453 
  454   if (msec == 0 || !httpReconnect2(http, msec, cancel))
  455     return (http);
  456 
  457  /*
  458   * Could not connect to any known address - bail out!
  459   */
  460 
  461   httpClose(http);
  462 
  463   return (NULL);
  464 }
  465 
  466 
  467 /*
  468  * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
  469  *
  470  * This function is now deprecated. Please use the @link httpConnect2@ function
  471  * instead.
  472  *
  473  * @deprecated@ @exclude all@
  474  */
  475 
  476 http_t *                /* O - New HTTP connection */
  477 httpConnectEncrypt(
  478     const char        *host,        /* I - Host to connect to */
  479     int               port,     /* I - Port number */
  480     http_encryption_t encryption)   /* I - Type of encryption to use */
  481 {
  482   DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)",
  483                 host, port, encryption));
  484 
  485   return (httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000,
  486                        NULL));
  487 }
  488 
  489 
  490 /*
  491  * 'httpDelete()' - Send a DELETE request to the server.
  492  */
  493 
  494 int                 /* O - Status of call (0 = success) */
  495 httpDelete(http_t     *http,        /* I - HTTP connection */
  496            const char *uri)     /* I - URI to delete */
  497 {
  498   return (http_send(http, HTTP_STATE_DELETE, uri));
  499 }
  500 
  501 
  502 /*
  503  * '_httpDisconnect()' - Disconnect a HTTP connection.
  504  */
  505 
  506 void
  507 _httpDisconnect(http_t *http)       /* I - HTTP connection */
  508 {
  509 #ifdef HAVE_SSL
  510   if (http->tls)
  511     _httpTLSStop(http);
  512 #endif /* HAVE_SSL */
  513 
  514   httpAddrClose(NULL, http->fd);
  515 
  516   http->fd = -1;
  517 }
  518 
  519 
  520 /*
  521  * 'httpEncryption()' - Set the required encryption on the link.
  522  */
  523 
  524 int                 /* O - -1 on error, 0 on success */
  525 httpEncryption(http_t            *http, /* I - HTTP connection */
  526                http_encryption_t e) /* I - New encryption preference */
  527 {
  528   DEBUG_printf(("httpEncryption(http=%p, e=%d)", (void *)http, e));
  529 
  530 #ifdef HAVE_SSL
  531   if (!http)
  532     return (0);
  533 
  534   if (http->mode == _HTTP_MODE_CLIENT)
  535   {
  536     http->encryption = e;
  537 
  538     if ((http->encryption == HTTP_ENCRYPTION_ALWAYS && !http->tls) ||
  539         (http->encryption == HTTP_ENCRYPTION_NEVER && http->tls))
  540       return (httpReconnect2(http, 30000, NULL));
  541     else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
  542       return (http_tls_upgrade(http));
  543     else
  544       return (0);
  545   }
  546   else
  547   {
  548     if (e == HTTP_ENCRYPTION_NEVER && http->tls)
  549       return (-1);
  550 
  551     http->encryption = e;
  552     if (e != HTTP_ENCRYPTION_IF_REQUESTED && !http->tls)
  553       return (_httpTLSStart(http));
  554     else
  555       return (0);
  556   }
  557 #else
  558   if (e == HTTP_ENCRYPTION_ALWAYS || e == HTTP_ENCRYPTION_REQUIRED)
  559     return (-1);
  560   else
  561     return (0);
  562 #endif /* HAVE_SSL */
  563 }
  564 
  565 
  566 /*
  567  * 'httpError()' - Get the last error on a connection.
  568  */
  569 
  570 int                 /* O - Error code (errno) value */
  571 httpError(http_t *http)         /* I - HTTP connection */
  572 {
  573   if (http)
  574     return (http->error);
  575   else
  576     return (EINVAL);
  577 }
  578 
  579 
  580 /*
  581  * 'httpFieldValue()' - Return the HTTP field enumeration value for a field
  582  *                      name.
  583  */
  584 
  585 http_field_t                /* O - Field index */
  586 httpFieldValue(const char *name)    /* I - String name */
  587 {
  588   int   i;              /* Looping var */
  589 
  590 
  591   for (i = 0; i < HTTP_FIELD_MAX; i ++)
  592     if (!_cups_strcasecmp(name, http_fields[i]))
  593       return ((http_field_t)i);
  594 
  595   return (HTTP_FIELD_UNKNOWN);
  596 }
  597 
  598 
  599 /*
  600  * 'httpFlush()' - Flush data read from a HTTP connection.
  601  */
  602 
  603 void
  604 httpFlush(http_t *http)         /* I - HTTP connection */
  605 {
  606   char      buffer[8192];       /* Junk buffer */
  607   int       blocking;       /* To block or not to block */
  608   http_state_t  oldstate;       /* Old state */
  609 
  610 
  611   DEBUG_printf(("httpFlush(http=%p), state=%s", (void *)http, httpStateString(http->state)));
  612 
  613  /*
  614   * Nothing to do if we are in the "waiting" state...
  615   */
  616 
  617   if (http->state == HTTP_STATE_WAITING)
  618     return;
  619 
  620  /*
  621   * Temporarily set non-blocking mode so we don't get stuck in httpRead()...
  622   */
  623 
  624   blocking = http->blocking;
  625   http->blocking = 0;
  626 
  627  /*
  628   * Read any data we can...
  629   */
  630 
  631   oldstate = http->state;
  632   while (httpRead2(http, buffer, sizeof(buffer)) > 0);
  633 
  634  /*
  635   * Restore blocking and reset the connection if we didn't get all of
  636   * the remaining data...
  637   */
  638 
  639   http->blocking = blocking;
  640 
  641   if (http->state == oldstate && http->state != HTTP_STATE_WAITING &&
  642       http->fd >= 0)
  643   {
  644    /*
  645     * Didn't get the data back, so close the current connection.
  646     */
  647 
  648 #ifdef HAVE_LIBZ
  649     if (http->coding)
  650       http_content_coding_finish(http);
  651 #endif /* HAVE_LIBZ */
  652 
  653     DEBUG_puts("1httpFlush: Setting state to HTTP_STATE_WAITING and closing.");
  654 
  655     http->state = HTTP_STATE_WAITING;
  656 
  657 #ifdef HAVE_SSL
  658     if (http->tls)
  659       _httpTLSStop(http);
  660 #endif /* HAVE_SSL */
  661 
  662     httpAddrClose(NULL, http->fd);
  663 
  664     http->fd = -1;
  665   }
  666 }
  667 
  668 
  669 /*
  670  * 'httpFlushWrite()' - Flush data written to a HTTP connection.
  671  *
  672  * @since CUPS 1.2/macOS 10.5@
  673  */
  674 
  675 int                 /* O - Bytes written or -1 on error */
  676 httpFlushWrite(http_t *http)        /* I - HTTP connection */
  677 {
  678   ssize_t   bytes;          /* Bytes written */
  679 
  680 
  681   DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", (void *)http, http ? http->data_encoding : 100));
  682 
  683   if (!http || !http->wused)
  684   {
  685     DEBUG_puts(http ? "1httpFlushWrite: Write buffer is empty." :
  686                       "1httpFlushWrite: No connection.");
  687     return (0);
  688   }
  689 
  690   if (http->data_encoding == HTTP_ENCODING_CHUNKED)
  691     bytes = http_write_chunk(http, http->wbuffer, (size_t)http->wused);
  692   else
  693     bytes = http_write(http, http->wbuffer, (size_t)http->wused);
  694 
  695   http->wused = 0;
  696 
  697   DEBUG_printf(("1httpFlushWrite: Returning %d, errno=%d.", (int)bytes, errno));
  698 
  699   return ((int)bytes);
  700 }
  701 
  702 
  703 /*
  704  * 'httpFreeCredentials()' - Free an array of credentials.
  705  */
  706 
  707 void
  708 httpFreeCredentials(
  709     cups_array_t *credentials)      /* I - Array of credentials */
  710 {
  711   http_credential_t *credential;    /* Credential */
  712 
  713 
  714   for (credential = (http_credential_t *)cupsArrayFirst(credentials);
  715        credential;
  716        credential = (http_credential_t *)cupsArrayNext(credentials))
  717   {
  718     cupsArrayRemove(credentials, credential);
  719     free((void *)credential->data);
  720     free(credential);
  721   }
  722 
  723   cupsArrayDelete(credentials);
  724 }
  725 
  726 
  727 /*
  728  * 'httpGet()' - Send a GET request to the server.
  729  */
  730 
  731 int                 /* O - Status of call (0 = success) */
  732 httpGet(http_t     *http,       /* I - HTTP connection */
  733         const char *uri)        /* I - URI to get */
  734 {
  735   return (http_send(http, HTTP_STATE_GET, uri));
  736 }
  737 
  738 
  739 /*
  740  * 'httpGetActivity()' - Get the most recent activity for a connection.
  741  *
  742  * The return value is the time in seconds of the last read or write.
  743  *
  744  * @since CUPS 2.0/OS 10.10@
  745  */
  746 
  747 time_t                  /* O - Time of last read or write */
  748 httpGetActivity(http_t *http)       /* I - HTTP connection */
  749 {
  750   return (http ? http->activity : 0);
  751 }
  752 
  753 
  754 /*
  755  * 'httpGetAuthString()' - Get the current authorization string.
  756  *
  757  * The authorization string is set by @link cupsDoAuthentication@ and
  758  * @link httpSetAuthString@.  Use @link httpGetAuthString@ to retrieve the
  759  * string to use with @link httpSetField@ for the
  760  * @code HTTP_FIELD_AUTHORIZATION@ value.
  761  *
  762  * @since CUPS 1.3/macOS 10.5@
  763  */
  764 
  765 char *                  /* O - Authorization string */
  766 httpGetAuthString(http_t *http)     /* I - HTTP connection */
  767 {
  768   if (http)
  769     return (http->authstring);
  770   else
  771     return (NULL);
  772 }
  773 
  774 
  775 /*
  776  * 'httpGetBlocking()' - Get the blocking/non-block state of a connection.
  777  *
  778  * @since CUPS 1.2/macOS 10.5@
  779  */
  780 
  781 int                 /* O - 1 if blocking, 0 if non-blocking */
  782 httpGetBlocking(http_t *http)       /* I - HTTP connection */
  783 {
  784   return (http ? http->blocking : 0);
  785 }
  786 
  787 
  788 /*
  789  * 'httpGetContentEncoding()' - Get a common content encoding, if any, between
  790  *                              the client and server.
  791  *
  792  * This function uses the value of the Accepts-Encoding HTTP header and must be
  793  * called after receiving a response from the server or a request from the
  794  * client.  The value returned can be use in subsequent requests (for clients)
  795  * or in the response (for servers) in order to compress the content stream.
  796  *
  797  * @since CUPS 1.7/macOS 10.9@
  798  */
  799 
  800 const char *                /* O - Content-Coding value or
  801                            @code NULL@ for the identity
  802                            coding. */
  803 httpGetContentEncoding(http_t *http)    /* I - HTTP connection */
  804 {
  805 #ifdef HAVE_LIBZ
  806   if (http && http->fields[HTTP_FIELD_ACCEPT_ENCODING])
  807   {
  808     int     i;          /* Looping var */
  809     char    temp[HTTP_MAX_VALUE],   /* Copy of Accepts-Encoding value */
  810         *start,         /* Start of coding value */
  811         *end;           /* End of coding value */
  812     double  qvalue;         /* "qvalue" for coding */
  813     struct lconv *loc = localeconv();   /* Locale data */
  814     static const char * const codings[] =
  815     {                   /* Supported content codings */
  816       "deflate",
  817       "gzip",
  818       "x-deflate",
  819       "x-gzip"
  820     };
  821 
  822     strlcpy(temp, http->fields[HTTP_FIELD_ACCEPT_ENCODING], sizeof(temp));
  823 
  824     for (start = temp; *start; start = end)
  825     {
  826      /*
  827       * Find the end of the coding name...
  828       */
  829 
  830       qvalue = 1.0;
  831       end    = start;
  832       while (*end && *end != ';' && *end != ',' && !isspace(*end & 255))
  833         end ++;
  834 
  835       if (*end == ';')
  836       {
  837        /*
  838         * Grab the qvalue as needed...
  839         */
  840 
  841         if (!strncmp(end, ";q=", 3))
  842           qvalue = _cupsStrScand(end + 3, NULL, loc);
  843 
  844        /*
  845         * Skip past all attributes...
  846         */
  847 
  848         *end++ = '\0';
  849         while (*end && *end != ',' && !isspace(*end & 255))
  850           end ++;
  851       }
  852       else if (*end)
  853         *end++ = '\0';
  854 
  855       while (*end && isspace(*end & 255))
  856     end ++;
  857 
  858      /*
  859       * Check value if it matches something we support...
  860       */
  861 
  862       if (qvalue <= 0.0)
  863         continue;
  864 
  865       for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++)
  866         if (!strcmp(start, codings[i]))
  867           return (codings[i]);
  868     }
  869   }
  870 #endif /* HAVE_LIBZ */
  871 
  872   return (NULL);
  873 }
  874 
  875 
  876 /*
  877  * 'httpGetCookie()' - Get any cookie data from the response.
  878  *
  879  * @since CUPS 1.1.19/macOS 10.3@
  880  */
  881 
  882 const char *                /* O - Cookie data or @code NULL@ */
  883 httpGetCookie(http_t *http)     /* I - HTTP connection */
  884 {
  885   return (http ? http->cookie : NULL);
  886 }
  887 
  888 
  889 /*
  890  * 'httpGetEncryption()' - Get the current encryption mode of a connection.
  891  *
  892  * This function returns the encryption mode for the connection. Use the
  893  * @link httpIsEncrypted@ function to determine whether a TLS session has
  894  * been established.
  895  *
  896  * @since CUPS 2.0/OS 10.10@
  897  */
  898 
  899 http_encryption_t           /* O - Current encryption mode */
  900 httpGetEncryption(http_t *http)     /* I - HTTP connection */
  901 {
  902   return (http ? http->encryption : HTTP_ENCRYPTION_IF_REQUESTED);
  903 }
  904 
  905 
  906 /*
  907  * 'httpGetExpect()' - Get the value of the Expect header, if any.
  908  *
  909  * Returns @code HTTP_STATUS_NONE@ if there is no Expect header, otherwise
  910  * returns the expected HTTP status code, typically @code HTTP_STATUS_CONTINUE@.
  911  *
  912  * @since CUPS 1.7/macOS 10.9@
  913  */
  914 
  915 http_status_t               /* O - Expect: status, if any */
  916 httpGetExpect(http_t *http)     /* I - HTTP connection */
  917 {
  918   if (!http)
  919     return (HTTP_STATUS_ERROR);
  920   else
  921     return (http->expect);
  922 }
  923 
  924 
  925 /*
  926  * 'httpGetFd()' - Get the file descriptor associated with a connection.
  927  *
  928  * @since CUPS 1.2/macOS 10.5@
  929  */
  930 
  931 int                 /* O - File descriptor or -1 if none */
  932 httpGetFd(http_t *http)         /* I - HTTP connection */
  933 {
  934   return (http ? http->fd : -1);
  935 }
  936 
  937 
  938 /*
  939  * 'httpGetField()' - Get a field value from a request/response.
  940  */
  941 
  942 const char *                /* O - Field value */
  943 httpGetField(http_t       *http,    /* I - HTTP connection */
  944              http_field_t field)    /* I - Field to get */
  945 {
  946   if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
  947     return (NULL);
  948   else if (http->fields[field])
  949     return (http->fields[field]);
  950   else
  951     return ("");
  952 }
  953 
  954 
  955 /*
  956  * 'httpGetKeepAlive()' - Get the current Keep-Alive state of the connection.
  957  *
  958  * @since CUPS 2.0/OS 10.10@
  959  */
  960 
  961 http_keepalive_t            /* O - Keep-Alive state */
  962 httpGetKeepAlive(http_t *http)      /* I - HTTP connection */
  963 {
  964   return (http ? http->keep_alive : HTTP_KEEPALIVE_OFF);
  965 }
  966 
  967 
  968 /*
  969  * 'httpGetLength()' - Get the amount of data remaining from the
  970  *                     content-length or transfer-encoding fields.
  971  *
  972  * This function is deprecated and will not return lengths larger than
  973  * 2^31 - 1; use httpGetLength2() instead.
  974  *
  975  * @deprecated@ @exclude all@
  976  */
  977 
  978 int                 /* O - Content length */
  979 httpGetLength(http_t *http)     /* I - HTTP connection */
  980 {
  981  /*
  982   * Get the read content length and return the 32-bit value.
  983   */
  984 
  985   if (http)
  986   {
  987     httpGetLength2(http);
  988 
  989     return (http->_data_remaining);
  990   }
  991   else
  992     return (-1);
  993 }
  994 
  995 
  996 /*
  997  * 'httpGetLength2()' - Get the amount of data remaining from the
  998  *                      content-length or transfer-encoding fields.
  999  *
 1000  * This function returns the complete content length, even for
 1001  * content larger than 2^31 - 1.
 1002  *
 1003  * @since CUPS 1.2/macOS 10.5@
 1004  */
 1005 
 1006 off_t                   /* O - Content length */
 1007 httpGetLength2(http_t *http)        /* I - HTTP connection */
 1008 {
 1009   off_t         remaining;  /* Remaining length */
 1010 
 1011 
 1012   DEBUG_printf(("2httpGetLength2(http=%p), state=%s", (void *)http, httpStateString(http->state)));
 1013 
 1014   if (!http)
 1015     return (-1);
 1016 
 1017   if (http->fields[HTTP_FIELD_TRANSFER_ENCODING] && !_cups_strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"))
 1018   {
 1019     DEBUG_puts("4httpGetLength2: chunked request!");
 1020     remaining = 0;
 1021   }
 1022   else
 1023   {
 1024    /*
 1025     * The following is a hack for HTTP servers that don't send a
 1026     * Content-Length or Transfer-Encoding field...
 1027     *
 1028     * If there is no Content-Length then the connection must close
 1029     * after the transfer is complete...
 1030     */
 1031 
 1032     if (!http->fields[HTTP_FIELD_CONTENT_LENGTH] || !http->fields[HTTP_FIELD_CONTENT_LENGTH][0])
 1033     {
 1034      /*
 1035       * Default content length is 0 for errors and certain types of operations,
 1036       * and 2^31-1 for other successful requests...
 1037       */
 1038 
 1039       if (http->status >= HTTP_STATUS_MULTIPLE_CHOICES ||
 1040           http->state == HTTP_STATE_OPTIONS ||
 1041           (http->state == HTTP_STATE_GET && http->mode == _HTTP_MODE_SERVER) ||
 1042           http->state == HTTP_STATE_HEAD ||
 1043           (http->state == HTTP_STATE_PUT && http->mode == _HTTP_MODE_CLIENT) ||
 1044           http->state == HTTP_STATE_DELETE ||
 1045           http->state == HTTP_STATE_TRACE ||
 1046           http->state == HTTP_STATE_CONNECT)
 1047         remaining = 0;
 1048       else
 1049         remaining = 2147483647;
 1050     }
 1051     else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
 1052                       NULL, 10)) < 0)
 1053       remaining = -1;
 1054 
 1055     DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT,
 1056                   CUPS_LLCAST remaining));
 1057   }
 1058 
 1059   return (remaining);
 1060 }
 1061 
 1062 
 1063 /*
 1064  * 'httpGetPending()' - Get the number of bytes that are buffered for writing.
 1065  *
 1066  * @since CUPS 2.0/OS 10.10@
 1067  */
 1068 
 1069 size_t                  /* O - Number of bytes buffered */
 1070 httpGetPending(http_t *http)        /* I - HTTP connection */
 1071 {
 1072   return (http ? (size_t)http->wused : 0);
 1073 }
 1074 
 1075 
 1076 /*
 1077  * 'httpGetReady()' - Get the number of bytes that can be read without blocking.
 1078  *
 1079  * @since CUPS 2.0/OS 10.10@
 1080  */
 1081 
 1082 size_t                  /* O - Number of bytes available */
 1083 httpGetReady(http_t *http)      /* I - HTTP connection */
 1084 {
 1085   if (!http)
 1086     return (0);
 1087   else if (http->used > 0)
 1088     return ((size_t)http->used);
 1089 #ifdef HAVE_SSL
 1090   else if (http->tls)
 1091     return (_httpTLSPending(http));
 1092 #endif /* HAVE_SSL */
 1093 
 1094   return (0);
 1095 }
 1096 
 1097 
 1098 /*
 1099  * 'httpGetRemaining()' - Get the number of remaining bytes in the message
 1100  *                        body or current chunk.
 1101  *
 1102  * The @link httpIsChunked@ function can be used to determine whether the
 1103  * message body is chunked or fixed-length.
 1104  *
 1105  * @since CUPS 2.0/OS 10.10@
 1106  */
 1107 
 1108 size_t                  /* O - Remaining bytes */
 1109 httpGetRemaining(http_t *http)      /* I - HTTP connection */
 1110 {
 1111   return (http ? (size_t)http->data_remaining : 0);
 1112 }
 1113 
 1114 
 1115 /*
 1116  * 'httpGets()' - Get a line of text from a HTTP connection.
 1117  */
 1118 
 1119 char *                  /* O - Line or @code NULL@ */
 1120 httpGets(char   *line,          /* I - Line to read into */
 1121          int    length,         /* I - Max length of buffer */
 1122      http_t *http)          /* I - HTTP connection */
 1123 {
 1124   char      *lineptr,       /* Pointer into line */
 1125         *lineend,       /* End of line */
 1126         *bufptr,        /* Pointer into input buffer */
 1127             *bufend;        /* Pointer to end of buffer */
 1128   ssize_t   bytes;          /* Number of bytes read */
 1129   int       eol;            /* End-of-line? */
 1130 
 1131 
 1132   DEBUG_printf(("2httpGets(line=%p, length=%d, http=%p)", (void *)line, length, (void *)http));
 1133 
 1134   if (!http || !line || length <= 1)
 1135     return (NULL);
 1136 
 1137  /*
 1138   * Read a line from the buffer...
 1139   */
 1140 
 1141   http->error = 0;
 1142   lineptr     = line;
 1143   lineend     = line + length - 1;
 1144   eol         = 0;
 1145 
 1146   while (lineptr < lineend)
 1147   {
 1148    /*
 1149     * Pre-load the buffer as needed...
 1150     */
 1151 
 1152 #ifdef _WIN32
 1153     WSASetLastError(0);
 1154 #else
 1155     errno = 0;
 1156 #endif /* _WIN32 */
 1157 
 1158     while (http->used == 0)
 1159     {
 1160      /*
 1161       * No newline; see if there is more data to be read...
 1162       */
 1163 
 1164       while (!_httpWait(http, http->wait_value, 1))
 1165       {
 1166     if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 1167       continue;
 1168 
 1169         DEBUG_puts("3httpGets: Timed out!");
 1170 #ifdef _WIN32
 1171         http->error = WSAETIMEDOUT;
 1172 #else
 1173         http->error = ETIMEDOUT;
 1174 #endif /* _WIN32 */
 1175         return (NULL);
 1176       }
 1177 
 1178       bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used));
 1179 
 1180       DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes));
 1181 
 1182       if (bytes < 0)
 1183       {
 1184        /*
 1185     * Nope, can't get a line this time...
 1186     */
 1187 
 1188 #ifdef _WIN32
 1189         DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
 1190 
 1191         if (WSAGetLastError() == WSAEINTR)
 1192       continue;
 1193     else if (WSAGetLastError() == WSAEWOULDBLOCK)
 1194     {
 1195       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 1196         continue;
 1197 
 1198       http->error = WSAGetLastError();
 1199     }
 1200     else if (WSAGetLastError() != http->error)
 1201     {
 1202       http->error = WSAGetLastError();
 1203       continue;
 1204     }
 1205 
 1206 #else
 1207         DEBUG_printf(("3httpGets: recv() error %d!", errno));
 1208 
 1209         if (errno == EINTR)
 1210       continue;
 1211     else if (errno == EWOULDBLOCK || errno == EAGAIN)
 1212     {
 1213       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 1214         continue;
 1215       else if (!http->timeout_cb && errno == EAGAIN)
 1216         continue;
 1217 
 1218       http->error = errno;
 1219     }
 1220     else if (errno != http->error)
 1221     {
 1222       http->error = errno;
 1223       continue;
 1224     }
 1225 #endif /* _WIN32 */
 1226 
 1227         return (NULL);
 1228       }
 1229       else if (bytes == 0)
 1230       {
 1231     http->error = EPIPE;
 1232 
 1233         return (NULL);
 1234       }
 1235 
 1236      /*
 1237       * Yup, update the amount used...
 1238       */
 1239 
 1240       http->used += (int)bytes;
 1241     }
 1242 
 1243    /*
 1244     * Now copy as much of the current line as possible...
 1245     */
 1246 
 1247     for (bufptr = http->buffer, bufend = http->buffer + http->used;
 1248          lineptr < lineend && bufptr < bufend;)
 1249     {
 1250       if (*bufptr == 0x0a)
 1251       {
 1252         eol = 1;
 1253     bufptr ++;
 1254     break;
 1255       }
 1256       else if (*bufptr == 0x0d)
 1257     bufptr ++;
 1258       else
 1259     *lineptr++ = *bufptr++;
 1260     }
 1261 
 1262     http->used -= (int)(bufptr - http->buffer);
 1263     if (http->used > 0)
 1264       memmove(http->buffer, bufptr, (size_t)http->used);
 1265 
 1266     if (eol)
 1267     {
 1268      /*
 1269       * End of line...
 1270       */
 1271 
 1272       http->activity = time(NULL);
 1273 
 1274       *lineptr = '\0';
 1275 
 1276       DEBUG_printf(("3httpGets: Returning \"%s\"", line));
 1277 
 1278       return (line);
 1279     }
 1280   }
 1281 
 1282   DEBUG_puts("3httpGets: No new line available!");
 1283 
 1284   return (NULL);
 1285 }
 1286 
 1287 
 1288 /*
 1289  * 'httpGetState()' - Get the current state of the HTTP request.
 1290  */
 1291 
 1292 http_state_t                /* O - HTTP state */
 1293 httpGetState(http_t *http)      /* I - HTTP connection */
 1294 {
 1295   return (http ? http->state : HTTP_STATE_ERROR);
 1296 }
 1297 
 1298 
 1299 /*
 1300  * 'httpGetStatus()' - Get the status of the last HTTP request.
 1301  *
 1302  * @since CUPS 1.2/macOS 10.5@
 1303  */
 1304 
 1305 http_status_t               /* O - HTTP status */
 1306 httpGetStatus(http_t *http)     /* I - HTTP connection */
 1307 {
 1308   return (http ? http->status : HTTP_STATUS_ERROR);
 1309 }
 1310 
 1311 
 1312 /*
 1313  * 'httpGetSubField()' - Get a sub-field value.
 1314  *
 1315  * @deprecated@ @exclude all@
 1316  */
 1317 
 1318 char *                  /* O - Value or @code NULL@ */
 1319 httpGetSubField(http_t       *http, /* I - HTTP connection */
 1320                 http_field_t field, /* I - Field index */
 1321                 const char   *name, /* I - Name of sub-field */
 1322         char         *value)    /* O - Value string */
 1323 {
 1324   return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE));
 1325 }
 1326 
 1327 
 1328 /*
 1329  * 'httpGetSubField2()' - Get a sub-field value.
 1330  *
 1331  * @since CUPS 1.2/macOS 10.5@
 1332  */
 1333 
 1334 char *                  /* O - Value or @code NULL@ */
 1335 httpGetSubField2(http_t       *http,    /* I - HTTP connection */
 1336                  http_field_t field,    /* I - Field index */
 1337                  const char   *name,    /* I - Name of sub-field */
 1338          char         *value,   /* O - Value string */
 1339          int          valuelen) /* I - Size of value buffer */
 1340 {
 1341   const char    *fptr;          /* Pointer into field */
 1342   char      temp[HTTP_MAX_VALUE],   /* Temporary buffer for name */
 1343         *ptr,           /* Pointer into string buffer */
 1344         *end;           /* End of value buffer */
 1345 
 1346   DEBUG_printf(("2httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)", (void *)http, field, name, (void *)value, valuelen));
 1347 
 1348   if (!http || !name || !value || valuelen < 2 ||
 1349       field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
 1350     return (NULL);
 1351 
 1352   end = value + valuelen - 1;
 1353 
 1354   for (fptr = http->fields[field]; *fptr;)
 1355   {
 1356    /*
 1357     * Skip leading whitespace...
 1358     */
 1359 
 1360     while (_cups_isspace(*fptr))
 1361       fptr ++;
 1362 
 1363     if (*fptr == ',')
 1364     {
 1365       fptr ++;
 1366       continue;
 1367     }
 1368 
 1369    /*
 1370     * Get the sub-field name...
 1371     */
 1372 
 1373     for (ptr = temp;
 1374          *fptr && *fptr != '=' && !_cups_isspace(*fptr) &&
 1375          ptr < (temp + sizeof(temp) - 1);
 1376          *ptr++ = *fptr++);
 1377 
 1378     *ptr = '\0';
 1379 
 1380     DEBUG_printf(("4httpGetSubField2: name=\"%s\"", temp));
 1381 
 1382    /*
 1383     * Skip trailing chars up to the '='...
 1384     */
 1385 
 1386     while (_cups_isspace(*fptr))
 1387       fptr ++;
 1388 
 1389     if (!*fptr)
 1390       break;
 1391 
 1392     if (*fptr != '=')
 1393       continue;
 1394 
 1395    /*
 1396     * Skip = and leading whitespace...
 1397     */
 1398 
 1399     fptr ++;
 1400 
 1401     while (_cups_isspace(*fptr))
 1402       fptr ++;
 1403 
 1404     if (*fptr == '\"')
 1405     {
 1406      /*
 1407       * Read quoted string...
 1408       */
 1409 
 1410       for (ptr = value, fptr ++;
 1411            *fptr && *fptr != '\"' && ptr < end;
 1412        *ptr++ = *fptr++);
 1413 
 1414       *ptr = '\0';
 1415 
 1416       while (*fptr && *fptr != '\"')
 1417         fptr ++;
 1418 
 1419       if (*fptr)
 1420         fptr ++;
 1421     }
 1422     else
 1423     {
 1424      /*
 1425       * Read unquoted string...
 1426       */
 1427 
 1428       for (ptr = value;
 1429            *fptr && !_cups_isspace(*fptr) && *fptr != ',' && ptr < end;
 1430        *ptr++ = *fptr++);
 1431 
 1432       *ptr = '\0';
 1433 
 1434       while (*fptr && !_cups_isspace(*fptr) && *fptr != ',')
 1435         fptr ++;
 1436     }
 1437 
 1438     DEBUG_printf(("4httpGetSubField2: value=\"%s\"", value));
 1439 
 1440    /*
 1441     * See if this is the one...
 1442     */
 1443 
 1444     if (!strcmp(name, temp))
 1445     {
 1446       DEBUG_printf(("3httpGetSubField2: Returning \"%s\"", value));
 1447       return (value);
 1448     }
 1449   }
 1450 
 1451   value[0] = '\0';
 1452 
 1453   DEBUG_puts("3httpGetSubField2: Returning NULL");
 1454 
 1455   return (NULL);
 1456 }
 1457 
 1458 
 1459 /*
 1460  * 'httpGetVersion()' - Get the HTTP version at the other end.
 1461  */
 1462 
 1463 http_version_t              /* O - Version number */
 1464 httpGetVersion(http_t *http)        /* I - HTTP connection */
 1465 {
 1466   return (http ? http->version : HTTP_VERSION_1_0);
 1467 }
 1468 
 1469 
 1470 /*
 1471  * 'httpHead()' - Send a HEAD request to the server.
 1472  */
 1473 
 1474 int                 /* O - Status of call (0 = success) */
 1475 httpHead(http_t     *http,      /* I - HTTP connection */
 1476          const char *uri)       /* I - URI for head */
 1477 {
 1478   DEBUG_printf(("httpHead(http=%p, uri=\"%s\")", (void *)http, uri));
 1479   return (http_send(http, HTTP_STATE_HEAD, uri));
 1480 }
 1481 
 1482 
 1483 /*
 1484  * 'httpInitialize()' - Initialize the HTTP interface library and set the
 1485  *                      default HTTP proxy (if any).
 1486  */
 1487 
 1488 void
 1489 httpInitialize(void)
 1490 {
 1491   static int    initialized = 0;    /* Have we been called before? */
 1492 #ifdef _WIN32
 1493   WSADATA   winsockdata;        /* WinSock data */
 1494 #endif /* _WIN32 */
 1495 
 1496 
 1497   _cupsGlobalLock();
 1498   if (initialized)
 1499   {
 1500     _cupsGlobalUnlock();
 1501     return;
 1502   }
 1503 
 1504 #ifdef _WIN32
 1505   WSAStartup(MAKEWORD(2,2), &winsockdata);
 1506 
 1507 #elif !defined(SO_NOSIGPIPE)
 1508  /*
 1509   * Ignore SIGPIPE signals...
 1510   */
 1511 
 1512 #  ifdef HAVE_SIGSET
 1513   sigset(SIGPIPE, SIG_IGN);
 1514 
 1515 #  elif defined(HAVE_SIGACTION)
 1516   struct sigaction  action;     /* POSIX sigaction data */
 1517 
 1518 
 1519   memset(&action, 0, sizeof(action));
 1520   action.sa_handler = SIG_IGN;
 1521   sigaction(SIGPIPE, &action, NULL);
 1522 
 1523 #  else
 1524   signal(SIGPIPE, SIG_IGN);
 1525 #  endif /* !SO_NOSIGPIPE */
 1526 #endif /* _WIN32 */
 1527 
 1528 #  ifdef HAVE_SSL
 1529   _httpTLSInitialize();
 1530 #  endif /* HAVE_SSL */
 1531 
 1532   initialized = 1;
 1533   _cupsGlobalUnlock();
 1534 }
 1535 
 1536 
 1537 /*
 1538  * 'httpIsChunked()' - Report whether a message body is chunked.
 1539  *
 1540  * This function returns non-zero if the message body is composed of
 1541  * variable-length chunks.
 1542  *
 1543  * @since CUPS 2.0/OS 10.10@
 1544  */
 1545 
 1546 int                 /* O - 1 if chunked, 0 if not */
 1547 httpIsChunked(http_t *http)     /* I - HTTP connection */
 1548 {
 1549   return (http ? http->data_encoding == HTTP_ENCODING_CHUNKED : 0);
 1550 }
 1551 
 1552 
 1553 /*
 1554  * 'httpIsEncrypted()' - Report whether a connection is encrypted.
 1555  *
 1556  * This function returns non-zero if the connection is currently encrypted.
 1557  *
 1558  * @since CUPS 2.0/OS 10.10@
 1559  */
 1560 
 1561 int                 /* O - 1 if encrypted, 0 if not */
 1562 httpIsEncrypted(http_t *http)       /* I - HTTP connection */
 1563 {
 1564   return (http ? http->tls != NULL : 0);
 1565 }
 1566 
 1567 
 1568 /*
 1569  * 'httpOptions()' - Send an OPTIONS request to the server.
 1570  */
 1571 
 1572 int                 /* O - Status of call (0 = success) */
 1573 httpOptions(http_t     *http,       /* I - HTTP connection */
 1574             const char *uri)        /* I - URI for options */
 1575 {
 1576   return (http_send(http, HTTP_STATE_OPTIONS, uri));
 1577 }
 1578 
 1579 
 1580 /*
 1581  * 'httpPeek()' - Peek at data from a HTTP connection.
 1582  *
 1583  * This function copies available data from the given HTTP connection, reading
 1584  * a buffer as needed.  The data is still available for reading using
 1585  * @link httpRead2@.
 1586  *
 1587  * For non-blocking connections the usual timeouts apply.
 1588  *
 1589  * @since CUPS 1.7/macOS 10.9@
 1590  */
 1591 
 1592 ssize_t                 /* O - Number of bytes copied */
 1593 httpPeek(http_t *http,          /* I - HTTP connection */
 1594          char   *buffer,        /* I - Buffer for data */
 1595      size_t length)         /* I - Maximum number of bytes */
 1596 {
 1597   ssize_t   bytes;          /* Bytes read */
 1598   char      len[32];        /* Length string */
 1599 
 1600 
 1601   DEBUG_printf(("httpPeek(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 1602 
 1603   if (http == NULL || buffer == NULL)
 1604     return (-1);
 1605 
 1606   http->activity = time(NULL);
 1607   http->error    = 0;
 1608 
 1609   if (length <= 0)
 1610     return (0);
 1611 
 1612   if (http->data_encoding == HTTP_ENCODING_CHUNKED &&
 1613       http->data_remaining <= 0)
 1614   {
 1615     DEBUG_puts("2httpPeek: Getting chunk length...");
 1616 
 1617     if (httpGets(len, sizeof(len), http) == NULL)
 1618     {
 1619       DEBUG_puts("1httpPeek: Could not get length!");
 1620       return (0);
 1621     }
 1622 
 1623     if (!len[0])
 1624     {
 1625       DEBUG_puts("1httpPeek: Blank chunk length, trying again...");
 1626       if (!httpGets(len, sizeof(len), http))
 1627       {
 1628     DEBUG_puts("1httpPeek: Could not get chunk length.");
 1629     return (0);
 1630       }
 1631     }
 1632 
 1633     http->data_remaining = strtoll(len, NULL, 16);
 1634 
 1635     if (http->data_remaining < 0)
 1636     {
 1637       DEBUG_puts("1httpPeek: Negative chunk length!");
 1638       return (0);
 1639     }
 1640   }
 1641 
 1642   DEBUG_printf(("2httpPeek: data_remaining=" CUPS_LLFMT,
 1643                 CUPS_LLCAST http->data_remaining));
 1644 
 1645   if (http->data_remaining <= 0 && http->data_encoding != HTTP_ENCODING_FIELDS)
 1646   {
 1647    /*
 1648     * A zero-length chunk ends a transfer; unless we are reading POST
 1649     * data, go idle...
 1650     */
 1651 
 1652 #ifdef HAVE_LIBZ
 1653     if (http->coding >= _HTTP_CODING_GUNZIP)
 1654       http_content_coding_finish(http);
 1655 #endif /* HAVE_LIBZ */
 1656 
 1657     if (http->data_encoding == HTTP_ENCODING_CHUNKED)
 1658       httpGets(len, sizeof(len), http);
 1659 
 1660     if (http->state == HTTP_STATE_POST_RECV)
 1661       http->state ++;
 1662     else
 1663       http->state = HTTP_STATE_STATUS;
 1664 
 1665     DEBUG_printf(("1httpPeek: 0-length chunk, set state to %s.",
 1666                   httpStateString(http->state)));
 1667 
 1668    /*
 1669     * Prevent future reads for this request...
 1670     */
 1671 
 1672     http->data_encoding = HTTP_ENCODING_FIELDS;
 1673 
 1674     return (0);
 1675   }
 1676   else if (length > (size_t)http->data_remaining)
 1677     length = (size_t)http->data_remaining;
 1678 
 1679 #ifdef HAVE_LIBZ
 1680   if (http->used == 0 &&
 1681       (http->coding == _HTTP_CODING_IDENTITY ||
 1682        (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)))
 1683 #else
 1684   if (http->used == 0)
 1685 #endif /* HAVE_LIBZ */
 1686   {
 1687    /*
 1688     * Buffer small reads for better performance...
 1689     */
 1690 
 1691     ssize_t buflen;         /* Length of read for buffer */
 1692 
 1693     if (!http->blocking)
 1694     {
 1695       while (!httpWait(http, http->wait_value))
 1696       {
 1697     if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 1698       continue;
 1699 
 1700     return (0);
 1701       }
 1702     }
 1703 
 1704     if ((size_t)http->data_remaining > sizeof(http->buffer))
 1705       buflen = sizeof(http->buffer);
 1706     else
 1707       buflen = (ssize_t)http->data_remaining;
 1708 
 1709     DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen));
 1710     bytes = http_read(http, http->buffer, (size_t)buflen);
 1711 
 1712     DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.",
 1713                   CUPS_LLCAST bytes));
 1714     if (bytes > 0)
 1715     {
 1716 #ifdef DEBUG
 1717       http_debug_hex("httpPeek", http->buffer, (int)bytes);
 1718 #endif /* DEBUG */
 1719 
 1720       http->used = (int)bytes;
 1721     }
 1722   }
 1723 
 1724 #ifdef HAVE_LIBZ
 1725   if (http->coding >= _HTTP_CODING_GUNZIP)
 1726   {
 1727 #  ifdef HAVE_INFLATECOPY
 1728     int     zerr;           /* Decompressor error */
 1729     z_stream    stream;         /* Copy of decompressor stream */
 1730 
 1731     if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER)
 1732     {
 1733       size_t buflen = buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in;
 1734                     /* Number of bytes to copy */
 1735 
 1736       if (((z_stream *)http->stream)->avail_in > 0 &&
 1737       ((z_stream *)http->stream)->next_in > http->sbuffer)
 1738         memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
 1739 
 1740       ((z_stream *)http->stream)->next_in = http->sbuffer;
 1741 
 1742       if (buflen > (size_t)http->data_remaining)
 1743         buflen = (size_t)http->data_remaining;
 1744 
 1745       if (buflen > (size_t)http->used)
 1746         buflen = (size_t)http->used;
 1747 
 1748       DEBUG_printf(("1httpPeek: Copying %d more bytes of data into "
 1749             "decompression buffer.", (int)buflen));
 1750 
 1751       memcpy(http->sbuffer + ((z_stream *)http->stream)->avail_in, http->buffer, buflen);
 1752       ((z_stream *)http->stream)->avail_in += buflen;
 1753       http->used            -= (int)buflen;
 1754       http->data_remaining  -= (off_t)buflen;
 1755 
 1756       if (http->used > 0)
 1757         memmove(http->buffer, http->buffer + buflen, (size_t)http->used);
 1758     }
 1759 
 1760     DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length,
 1761                   (int)((z_stream *)http->stream)->avail_in));
 1762 
 1763     if (inflateCopy(&stream, (z_stream *)http->stream) != Z_OK)
 1764     {
 1765       DEBUG_puts("2httpPeek: Unable to copy decompressor stream.");
 1766       http->error = ENOMEM;
 1767       return (-1);
 1768     }
 1769 
 1770     stream.next_out  = (Bytef *)buffer;
 1771     stream.avail_out = (uInt)length;
 1772 
 1773     zerr = inflate(&stream, Z_SYNC_FLUSH);
 1774     inflateEnd(&stream);
 1775 
 1776     if (zerr < Z_OK)
 1777     {
 1778       DEBUG_printf(("2httpPeek: zerr=%d", zerr));
 1779 #ifdef DEBUG
 1780       http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
 1781 #endif /* DEBUG */
 1782 
 1783       http->error = EIO;
 1784       return (-1);
 1785     }
 1786 
 1787     bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
 1788 
 1789 #  else
 1790     DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not "
 1791                "work with compressed streams.");
 1792     return (-1);
 1793 #  endif /* HAVE_INFLATECOPY */
 1794   }
 1795   else
 1796 #endif /* HAVE_LIBZ */
 1797   if (http->used > 0)
 1798   {
 1799     if (length > (size_t)http->used)
 1800       length = (size_t)http->used;
 1801 
 1802     bytes = (ssize_t)length;
 1803 
 1804     DEBUG_printf(("2httpPeek: grabbing %d bytes from input buffer...",
 1805                   (int)bytes));
 1806 
 1807     memcpy(buffer, http->buffer, length);
 1808   }
 1809   else
 1810     bytes = 0;
 1811 
 1812   if (bytes < 0)
 1813   {
 1814 #ifdef _WIN32
 1815     if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
 1816       bytes = 0;
 1817     else
 1818       http->error = WSAGetLastError();
 1819 #else
 1820     if (errno == EINTR || errno == EAGAIN)
 1821       bytes = 0;
 1822     else
 1823       http->error = errno;
 1824 #endif /* _WIN32 */
 1825   }
 1826   else if (bytes == 0)
 1827   {
 1828     http->error = EPIPE;
 1829     return (0);
 1830   }
 1831 
 1832   return (bytes);
 1833 }
 1834 
 1835 
 1836 /*
 1837  * 'httpPost()' - Send a POST request to the server.
 1838  */
 1839 
 1840 int                 /* O - Status of call (0 = success) */
 1841 httpPost(http_t     *http,      /* I - HTTP connection */
 1842          const char *uri)       /* I - URI for post */
 1843 {
 1844   return (http_send(http, HTTP_STATE_POST, uri));
 1845 }
 1846 
 1847 
 1848 /*
 1849  * 'httpPrintf()' - Print a formatted string to a HTTP connection.
 1850  *
 1851  * @private@
 1852  */
 1853 
 1854 int                 /* O - Number of bytes written */
 1855 httpPrintf(http_t     *http,        /* I - HTTP connection */
 1856            const char *format,      /* I - printf-style format string */
 1857        ...)             /* I - Additional args as needed */
 1858 {
 1859   ssize_t   bytes;          /* Number of bytes to write */
 1860   char      buf[16384];     /* Buffer for formatted string */
 1861   va_list   ap;         /* Variable argument pointer */
 1862 
 1863 
 1864   DEBUG_printf(("2httpPrintf(http=%p, format=\"%s\", ...)", (void *)http, format));
 1865 
 1866   va_start(ap, format);
 1867   bytes = vsnprintf(buf, sizeof(buf), format, ap);
 1868   va_end(ap);
 1869 
 1870   DEBUG_printf(("3httpPrintf: (" CUPS_LLFMT " bytes) %s", CUPS_LLCAST bytes, buf));
 1871 
 1872   if (http->data_encoding == HTTP_ENCODING_FIELDS)
 1873     return ((int)httpWrite2(http, buf, (size_t)bytes));
 1874   else
 1875   {
 1876     if (http->wused)
 1877     {
 1878       DEBUG_puts("4httpPrintf: flushing existing data...");
 1879 
 1880       if (httpFlushWrite(http) < 0)
 1881     return (-1);
 1882     }
 1883 
 1884     return ((int)http_write(http, buf, (size_t)bytes));
 1885   }
 1886 }
 1887 
 1888 
 1889 /*
 1890  * 'httpPut()' - Send a PUT request to the server.
 1891  */
 1892 
 1893 int                 /* O - Status of call (0 = success) */
 1894 httpPut(http_t     *http,       /* I - HTTP connection */
 1895         const char *uri)        /* I - URI to put */
 1896 {
 1897   DEBUG_printf(("httpPut(http=%p, uri=\"%s\")", (void *)http, uri));
 1898   return (http_send(http, HTTP_STATE_PUT, uri));
 1899 }
 1900 
 1901 
 1902 /*
 1903  * 'httpRead()' - Read data from a HTTP connection.
 1904  *
 1905  * This function is deprecated. Use the httpRead2() function which can
 1906  * read more than 2GB of data.
 1907  *
 1908  * @deprecated@ @exclude all@
 1909  */
 1910 
 1911 int                 /* O - Number of bytes read */
 1912 httpRead(http_t *http,          /* I - HTTP connection */
 1913          char   *buffer,        /* I - Buffer for data */
 1914      int    length)         /* I - Maximum number of bytes */
 1915 {
 1916   return ((int)httpRead2(http, buffer, (size_t)length));
 1917 }
 1918 
 1919 
 1920 /*
 1921  * 'httpRead2()' - Read data from a HTTP connection.
 1922  *
 1923  * @since CUPS 1.2/macOS 10.5@
 1924  */
 1925 
 1926 ssize_t                 /* O - Number of bytes read */
 1927 httpRead2(http_t *http,         /* I - HTTP connection */
 1928           char   *buffer,       /* I - Buffer for data */
 1929       size_t length)        /* I - Maximum number of bytes */
 1930 {
 1931   ssize_t   bytes;          /* Bytes read */
 1932 
 1933 
 1934 #ifdef HAVE_LIBZ
 1935   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));
 1936 #else
 1937   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));
 1938 #endif /* HAVE_LIBZ */
 1939 
 1940   if (http == NULL || buffer == NULL)
 1941     return (-1);
 1942 
 1943   http->activity = time(NULL);
 1944   http->error    = 0;
 1945 
 1946   if (length <= 0)
 1947     return (0);
 1948 
 1949 #ifdef HAVE_LIBZ
 1950   if (http->coding >= _HTTP_CODING_GUNZIP)
 1951   {
 1952     do
 1953     {
 1954       if (((z_stream *)http->stream)->avail_in > 0)
 1955       {
 1956     int zerr;           /* Decompressor error */
 1957 
 1958     DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d",
 1959                   (int)((z_stream *)http->stream)->avail_in, (int)length));
 1960 
 1961     ((z_stream *)http->stream)->next_out  = (Bytef *)buffer;
 1962     ((z_stream *)http->stream)->avail_out = (uInt)length;
 1963 
 1964     if ((zerr = inflate((z_stream *)http->stream, Z_SYNC_FLUSH)) < Z_OK)
 1965     {
 1966       DEBUG_printf(("2httpRead2: zerr=%d", zerr));
 1967 #ifdef DEBUG
 1968           http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in);
 1969 #endif /* DEBUG */
 1970 
 1971       http->error = EIO;
 1972       return (-1);
 1973     }
 1974 
 1975     bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out);
 1976 
 1977     DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d",
 1978               ((z_stream *)http->stream)->avail_in, ((z_stream *)http->stream)->avail_out,
 1979               (int)bytes));
 1980       }
 1981       else
 1982         bytes = 0;
 1983 
 1984       if (bytes == 0)
 1985       {
 1986         ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in;
 1987                     /* Additional bytes for buffer */
 1988 
 1989         if (buflen > 0)
 1990         {
 1991           if (((z_stream *)http->stream)->avail_in > 0 &&
 1992               ((z_stream *)http->stream)->next_in > http->sbuffer)
 1993             memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in);
 1994 
 1995       ((z_stream *)http->stream)->next_in = http->sbuffer;
 1996 
 1997           DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into "
 1998                         "decompression buffer.", (int)buflen));
 1999 
 2000           if (http->data_remaining > 0)
 2001           {
 2002         if (buflen > http->data_remaining)
 2003           buflen = (ssize_t)http->data_remaining;
 2004 
 2005         bytes = http_read_buffered(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
 2006           }
 2007           else if (http->data_encoding == HTTP_ENCODING_CHUNKED)
 2008             bytes = http_read_chunk(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen);
 2009           else
 2010             bytes = 0;
 2011 
 2012           if (bytes < 0)
 2013             return (bytes);
 2014           else if (bytes == 0)
 2015             break;
 2016 
 2017           DEBUG_printf(("1httpRead2: Adding " CUPS_LLFMT " bytes to "
 2018                         "decompression buffer.", CUPS_LLCAST bytes));
 2019 
 2020           http->data_remaining  -= bytes;
 2021           ((z_stream *)http->stream)->avail_in += (uInt)bytes;
 2022 
 2023       if (http->data_remaining <= 0 &&
 2024           http->data_encoding == HTTP_ENCODING_CHUNKED)
 2025       {
 2026        /*
 2027         * Read the trailing blank line now...
 2028         */
 2029 
 2030         char    len[32];        /* Length string */
 2031 
 2032         httpGets(len, sizeof(len), http);
 2033       }
 2034 
 2035           bytes = 0;
 2036         }
 2037         else
 2038           return (0);
 2039       }
 2040     }
 2041     while (bytes == 0);
 2042   }
 2043   else
 2044 #endif /* HAVE_LIBZ */
 2045   if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
 2046   {
 2047     if ((bytes = http_read_chunk(http, buffer, length)) > 0)
 2048     {
 2049       http->data_remaining -= bytes;
 2050 
 2051       if (http->data_remaining <= 0)
 2052       {
 2053        /*
 2054         * Read the trailing blank line now...
 2055         */
 2056 
 2057         char    len[32];        /* Length string */
 2058 
 2059         httpGets(len, sizeof(len), http);
 2060       }
 2061     }
 2062   }
 2063   else if (http->data_remaining <= 0)
 2064   {
 2065    /*
 2066     * No more data to read...
 2067     */
 2068 
 2069     return (0);
 2070   }
 2071   else
 2072   {
 2073     DEBUG_printf(("1httpRead2: Reading up to %d bytes into buffer.",
 2074                   (int)length));
 2075 
 2076     if (length > (size_t)http->data_remaining)
 2077       length = (size_t)http->data_remaining;
 2078 
 2079     if ((bytes = http_read_buffered(http, buffer, length)) > 0)
 2080     {
 2081       http->data_remaining -= bytes;
 2082 
 2083       if (http->data_remaining <= 0 &&
 2084           http->data_encoding == HTTP_ENCODING_CHUNKED)
 2085       {
 2086        /*
 2087         * Read the trailing blank line now...
 2088         */
 2089 
 2090         char    len[32];        /* Length string */
 2091 
 2092         httpGets(len, sizeof(len), http);
 2093       }
 2094     }
 2095   }
 2096 
 2097   if (
 2098 #ifdef HAVE_LIBZ
 2099       (http->coding == _HTTP_CODING_IDENTITY ||
 2100        (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)) &&
 2101 #endif /* HAVE_LIBZ */
 2102       ((http->data_remaining <= 0 &&
 2103         http->data_encoding == HTTP_ENCODING_LENGTH) ||
 2104        (http->data_encoding == HTTP_ENCODING_CHUNKED && bytes == 0)))
 2105   {
 2106 #ifdef HAVE_LIBZ
 2107     if (http->coding >= _HTTP_CODING_GUNZIP)
 2108       http_content_coding_finish(http);
 2109 #endif /* HAVE_LIBZ */
 2110 
 2111     if (http->state == HTTP_STATE_POST_RECV)
 2112       http->state ++;
 2113     else if (http->state == HTTP_STATE_GET_SEND ||
 2114              http->state == HTTP_STATE_POST_SEND)
 2115       http->state = HTTP_STATE_WAITING;
 2116     else
 2117       http->state = HTTP_STATE_STATUS;
 2118 
 2119     DEBUG_printf(("1httpRead2: End of content, set state to %s.",
 2120           httpStateString(http->state)));
 2121   }
 2122 
 2123   return (bytes);
 2124 }
 2125 
 2126 
 2127 /*
 2128  * 'httpReadRequest()' - Read a HTTP request from a connection.
 2129  *
 2130  * @since CUPS 1.7/macOS 10.9@
 2131  */
 2132 
 2133 http_state_t                /* O - New state of connection */
 2134 httpReadRequest(http_t *http,       /* I - HTTP connection */
 2135                 char   *uri,        /* I - URI buffer */
 2136         size_t urilen)      /* I - Size of URI buffer */
 2137 {
 2138   char  line[4096],         /* HTTP request line */
 2139     *req_method,            /* HTTP request method */
 2140     *req_uri,           /* HTTP request URI */
 2141     *req_version;           /* HTTP request version number string */
 2142 
 2143 
 2144  /*
 2145   * Range check input...
 2146   */
 2147 
 2148   DEBUG_printf(("httpReadRequest(http=%p, uri=%p, urilen=" CUPS_LLFMT ")", (void *)http, (void *)uri, CUPS_LLCAST urilen));
 2149 
 2150   if (uri)
 2151     *uri = '\0';
 2152 
 2153   if (!http || !uri || urilen < 1)
 2154   {
 2155     DEBUG_puts("1httpReadRequest: Bad arguments, returning HTTP_STATE_ERROR.");
 2156     return (HTTP_STATE_ERROR);
 2157   }
 2158   else if (http->state != HTTP_STATE_WAITING)
 2159   {
 2160     DEBUG_printf(("1httpReadRequest: Bad state %s, returning HTTP_STATE_ERROR.",
 2161                   httpStateString(http->state)));
 2162     return (HTTP_STATE_ERROR);
 2163   }
 2164 
 2165  /*
 2166   * Reset state...
 2167   */
 2168 
 2169   httpClearFields(http);
 2170 
 2171   http->activity       = time(NULL);
 2172   http->data_encoding  = HTTP_ENCODING_FIELDS;
 2173   http->data_remaining = 0;
 2174   http->keep_alive     = HTTP_KEEPALIVE_OFF;
 2175   http->status         = HTTP_STATUS_OK;
 2176   http->version        = HTTP_VERSION_1_1;
 2177 
 2178  /*
 2179   * Read a line from the socket...
 2180   */
 2181 
 2182   if (!httpGets(line, sizeof(line), http))
 2183   {
 2184     DEBUG_puts("1httpReadRequest: Unable to read, returning HTTP_STATE_ERROR");
 2185     return (HTTP_STATE_ERROR);
 2186   }
 2187 
 2188   if (!line[0])
 2189   {
 2190     DEBUG_puts("1httpReadRequest: Blank line, returning HTTP_STATE_WAITING");
 2191     return (HTTP_STATE_WAITING);
 2192   }
 2193 
 2194   DEBUG_printf(("1httpReadRequest: %s", line));
 2195 
 2196  /*
 2197   * Parse it...
 2198   */
 2199 
 2200   req_method = line;
 2201   req_uri    = line;
 2202 
 2203   while (*req_uri && !isspace(*req_uri & 255))
 2204     req_uri ++;
 2205 
 2206   if (!*req_uri)
 2207   {
 2208     DEBUG_puts("1httpReadRequest: No request URI.");
 2209     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request URI."), 1);
 2210     return (HTTP_STATE_ERROR);
 2211   }
 2212 
 2213   *req_uri++ = '\0';
 2214 
 2215   while (*req_uri && isspace(*req_uri & 255))
 2216     req_uri ++;
 2217 
 2218   req_version = req_uri;
 2219 
 2220   while (*req_version && !isspace(*req_version & 255))
 2221     req_version ++;
 2222 
 2223   if (!*req_version)
 2224   {
 2225     DEBUG_puts("1httpReadRequest: No request protocol version.");
 2226     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No request protocol version."), 1);
 2227     return (HTTP_STATE_ERROR);
 2228   }
 2229 
 2230   *req_version++ = '\0';
 2231 
 2232   while (*req_version && isspace(*req_version & 255))
 2233     req_version ++;
 2234 
 2235  /*
 2236   * Validate...
 2237   */
 2238 
 2239   if (!strcmp(req_method, "OPTIONS"))
 2240     http->state = HTTP_STATE_OPTIONS;
 2241   else if (!strcmp(req_method, "GET"))
 2242     http->state = HTTP_STATE_GET;
 2243   else if (!strcmp(req_method, "HEAD"))
 2244     http->state = HTTP_STATE_HEAD;
 2245   else if (!strcmp(req_method, "POST"))
 2246     http->state = HTTP_STATE_POST;
 2247   else if (!strcmp(req_method, "PUT"))
 2248     http->state = HTTP_STATE_PUT;
 2249   else if (!strcmp(req_method, "DELETE"))
 2250     http->state = HTTP_STATE_DELETE;
 2251   else if (!strcmp(req_method, "TRACE"))
 2252     http->state = HTTP_STATE_TRACE;
 2253   else if (!strcmp(req_method, "CONNECT"))
 2254     http->state = HTTP_STATE_CONNECT;
 2255   else
 2256   {
 2257     DEBUG_printf(("1httpReadRequest: Unknown method \"%s\".", req_method));
 2258     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request method."), 1);
 2259     return (HTTP_STATE_UNKNOWN_METHOD);
 2260   }
 2261 
 2262   DEBUG_printf(("1httpReadRequest: Set state to %s.",
 2263                 httpStateString(http->state)));
 2264 
 2265   if (!strcmp(req_version, "HTTP/1.0"))
 2266   {
 2267     http->version    = HTTP_VERSION_1_0;
 2268     http->keep_alive = HTTP_KEEPALIVE_OFF;
 2269   }
 2270   else if (!strcmp(req_version, "HTTP/1.1"))
 2271   {
 2272     http->version    = HTTP_VERSION_1_1;
 2273     http->keep_alive = HTTP_KEEPALIVE_ON;
 2274   }
 2275   else
 2276   {
 2277     DEBUG_printf(("1httpReadRequest: Unknown version \"%s\".", req_version));
 2278     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown request version."), 1);
 2279     return (HTTP_STATE_UNKNOWN_VERSION);
 2280   }
 2281 
 2282   DEBUG_printf(("1httpReadRequest: URI is \"%s\".", req_uri));
 2283   strlcpy(uri, req_uri, urilen);
 2284 
 2285   return (http->state);
 2286 }
 2287 
 2288 
 2289 /*
 2290  * 'httpReconnect()' - Reconnect to a HTTP server.
 2291  *
 2292  * This function is deprecated. Please use the @link httpReconnect2@ function
 2293  * instead.
 2294  *
 2295  * @deprecated@ @exclude all@
 2296  */
 2297 
 2298 int                 /* O - 0 on success, non-zero on failure */
 2299 httpReconnect(http_t *http)     /* I - HTTP connection */
 2300 {
 2301   DEBUG_printf(("httpReconnect(http=%p)", (void *)http));
 2302 
 2303   return (httpReconnect2(http, 30000, NULL));
 2304 }
 2305 
 2306 
 2307 /*
 2308  * 'httpReconnect2()' - Reconnect to a HTTP server with timeout and optional
 2309  *                      cancel.
 2310  */
 2311 
 2312 int                 /* O - 0 on success, non-zero on failure */
 2313 httpReconnect2(http_t *http,        /* I - HTTP connection */
 2314            int    msec,     /* I - Timeout in milliseconds */
 2315            int    *cancel)      /* I - Pointer to "cancel" variable */
 2316 {
 2317   http_addrlist_t   *addr;      /* Connected address */
 2318 #ifdef DEBUG
 2319   http_addrlist_t   *current;   /* Current address */
 2320   char          temp[256];  /* Temporary address string */
 2321 #endif /* DEBUG */
 2322 
 2323 
 2324   DEBUG_printf(("httpReconnect2(http=%p, msec=%d, cancel=%p)", (void *)http, msec, (void *)cancel));
 2325 
 2326   if (!http)
 2327   {
 2328     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
 2329     return (-1);
 2330   }
 2331 
 2332 #ifdef HAVE_SSL
 2333   if (http->tls)
 2334   {
 2335     DEBUG_puts("2httpReconnect2: Shutting down SSL/TLS...");
 2336     _httpTLSStop(http);
 2337   }
 2338 #endif /* HAVE_SSL */
 2339 
 2340  /*
 2341   * Close any previously open socket...
 2342   */
 2343 
 2344   if (http->fd >= 0)
 2345   {
 2346     DEBUG_printf(("2httpReconnect2: Closing socket %d...", http->fd));
 2347 
 2348     httpAddrClose(NULL, http->fd);
 2349 
 2350     http->fd = -1;
 2351   }
 2352 
 2353  /*
 2354   * Reset all state (except fields, which may be reused)...
 2355   */
 2356 
 2357   http->state           = HTTP_STATE_WAITING;
 2358   http->version         = HTTP_VERSION_1_1;
 2359   http->keep_alive      = HTTP_KEEPALIVE_OFF;
 2360   memset(&http->_hostaddr, 0, sizeof(http->_hostaddr));
 2361   http->data_encoding   = HTTP_ENCODING_FIELDS;
 2362   http->_data_remaining = 0;
 2363   http->used            = 0;
 2364   http->data_remaining  = 0;
 2365   http->hostaddr        = NULL;
 2366   http->wused           = 0;
 2367 
 2368  /*
 2369   * Connect to the server...
 2370   */
 2371 
 2372 #ifdef DEBUG
 2373   for (current = http->addrlist; current; current = current->next)
 2374     DEBUG_printf(("2httpReconnect2: Address %s:%d",
 2375                   httpAddrString(&(current->addr), temp, sizeof(temp)),
 2376                   httpAddrPort(&(current->addr))));
 2377 #endif /* DEBUG */
 2378 
 2379   if ((addr = httpAddrConnect2(http->addrlist, &(http->fd), msec, cancel)) == NULL)
 2380   {
 2381    /*
 2382     * Unable to connect...
 2383     */
 2384 
 2385 #ifdef _WIN32
 2386     http->error  = WSAGetLastError();
 2387 #else
 2388     http->error  = errno;
 2389 #endif /* _WIN32 */
 2390     http->status = HTTP_STATUS_ERROR;
 2391 
 2392     DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s",
 2393                   strerror(http->error)));
 2394 
 2395     return (-1);
 2396   }
 2397 
 2398   DEBUG_printf(("2httpReconnect2: New socket=%d", http->fd));
 2399 
 2400   if (http->timeout_value > 0)
 2401     http_set_timeout(http->fd, http->timeout_value);
 2402 
 2403   http->hostaddr = &(addr->addr);
 2404   http->error    = 0;
 2405 
 2406 #ifdef HAVE_SSL
 2407   if (http->encryption == HTTP_ENCRYPTION_ALWAYS)
 2408   {
 2409    /*
 2410     * Always do encryption via SSL.
 2411     */
 2412 
 2413     if (_httpTLSStart(http) != 0)
 2414     {
 2415       httpAddrClose(NULL, http->fd);
 2416 
 2417       return (-1);
 2418     }
 2419   }
 2420   else if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls_upgrade)
 2421     return (http_tls_upgrade(http));
 2422 #endif /* HAVE_SSL */
 2423 
 2424   DEBUG_printf(("1httpReconnect2: Connected to %s:%d...",
 2425         httpAddrString(http->hostaddr, temp, sizeof(temp)),
 2426         httpAddrPort(http->hostaddr)));
 2427 
 2428   return (0);
 2429 }
 2430 
 2431 
 2432 /*
 2433  * 'httpSetAuthString()' - Set the current authorization string.
 2434  *
 2435  * This function just stores a copy of the current authorization string in
 2436  * the HTTP connection object.  You must still call @link httpSetField@ to set
 2437  * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using
 2438  * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or
 2439  * @link httpPut@.
 2440  *
 2441  * @since CUPS 1.3/macOS 10.5@
 2442  */
 2443 
 2444 void
 2445 httpSetAuthString(http_t     *http, /* I - HTTP connection */
 2446                   const char *scheme,   /* I - Auth scheme (NULL to clear it) */
 2447           const char *data) /* I - Auth data (NULL for none) */
 2448 {
 2449  /*
 2450   * Range check input...
 2451   */
 2452 
 2453   if (!http)
 2454     return;
 2455 
 2456   if (http->authstring && http->authstring != http->_authstring)
 2457     free(http->authstring);
 2458 
 2459   http->authstring = http->_authstring;
 2460 
 2461   if (scheme)
 2462   {
 2463    /*
 2464     * Set the current authorization string...
 2465     */
 2466 
 2467     size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
 2468     char *temp;
 2469 
 2470     if (len > sizeof(http->_authstring))
 2471     {
 2472       if ((temp = malloc(len)) == NULL)
 2473         len = sizeof(http->_authstring);
 2474       else
 2475         http->authstring = temp;
 2476     }
 2477 
 2478     if (data)
 2479       snprintf(http->authstring, len, "%s %s", scheme, data);
 2480     else
 2481       strlcpy(http->authstring, scheme, len);
 2482   }
 2483   else
 2484   {
 2485    /*
 2486     * Clear the current authorization string...
 2487     */
 2488 
 2489     http->_authstring[0] = '\0';
 2490   }
 2491 }
 2492 
 2493 
 2494 /*
 2495  * 'httpSetCredentials()' - Set the credentials associated with an encrypted
 2496  *              connection.
 2497  *
 2498  * @since CUPS 1.5/macOS 10.7@
 2499  */
 2500 
 2501 int                     /* O - Status of call (0 = success) */
 2502 httpSetCredentials(http_t   *http,      /* I - HTTP connection */
 2503            cups_array_t *credentials)   /* I - Array of credentials */
 2504 {
 2505   if (!http || cupsArrayCount(credentials) < 1)
 2506     return (-1);
 2507 
 2508 #ifdef HAVE_SSL
 2509   _httpFreeCredentials(http->tls_credentials);
 2510 
 2511   http->tls_credentials = _httpCreateCredentials(credentials);
 2512 #endif /* HAVE_SSL */
 2513 
 2514   return (http->tls_credentials ? 0 : -1);
 2515 }
 2516 
 2517 
 2518 /*
 2519  * 'httpSetCookie()' - Set the cookie value(s).
 2520  *
 2521  * @since CUPS 1.1.19/macOS 10.3@
 2522  */
 2523 
 2524 void
 2525 httpSetCookie(http_t     *http,     /* I - Connection */
 2526               const char *cookie)   /* I - Cookie string */
 2527 {
 2528   if (!http)
 2529     return;
 2530 
 2531   if (http->cookie)
 2532     free(http->cookie);
 2533 
 2534   if (cookie)
 2535     http->cookie = strdup(cookie);
 2536   else
 2537     http->cookie = NULL;
 2538 }
 2539 
 2540 
 2541 /*
 2542  * 'httpSetDefaultField()' - Set the default value of an HTTP header.
 2543  *
 2544  * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
 2545  * and @code HTTP_FIELD_USER_AGENT@ can be set.
 2546  *
 2547  * @since CUPS 1.7/macOS 10.9@
 2548  */
 2549 
 2550 void
 2551 httpSetDefaultField(http_t       *http, /* I - HTTP connection */
 2552                     http_field_t field, /* I - Field index */
 2553                 const char   *value)/* I - Value */
 2554 {
 2555   DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
 2556 
 2557   if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX)
 2558     return;
 2559 
 2560   if (http->default_fields[field])
 2561     free(http->default_fields[field]);
 2562 
 2563   http->default_fields[field] = value ? strdup(value) : NULL;
 2564 }
 2565 
 2566 
 2567 /*
 2568  * 'httpSetExpect()' - Set the Expect: header in a request.
 2569  *
 2570  * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
 2571  * argument.
 2572  *
 2573  * @since CUPS 1.2/macOS 10.5@
 2574  */
 2575 
 2576 void
 2577 httpSetExpect(http_t        *http,  /* I - HTTP connection */
 2578               http_status_t expect) /* I - HTTP status to expect
 2579                                    (@code HTTP_STATUS_CONTINUE@) */
 2580 {
 2581   DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
 2582 
 2583   if (http)
 2584     http->expect = expect;
 2585 }
 2586 
 2587 
 2588 /*
 2589  * 'httpSetField()' - Set the value of an HTTP header.
 2590  */
 2591 
 2592 void
 2593 httpSetField(http_t       *http,    /* I - HTTP connection */
 2594              http_field_t field,    /* I - Field index */
 2595          const char   *value)   /* I - Value */
 2596 {
 2597   DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
 2598 
 2599   if (!http || field <= HTTP_FIELD_UNKNOWN || field >= HTTP_FIELD_MAX || !value)
 2600     return;
 2601 
 2602   http_add_field(http, field, value, 0);
 2603 }
 2604 
 2605 
 2606 /*
 2607  * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
 2608  *
 2609  * @since CUPS 2.0/OS 10.10@
 2610  */
 2611 
 2612 void
 2613 httpSetKeepAlive(
 2614     http_t           *http,     /* I - HTTP connection */
 2615     http_keepalive_t keep_alive)    /* I - New Keep-Alive value */
 2616 {
 2617   if (http)
 2618     http->keep_alive = keep_alive;
 2619 }
 2620 
 2621 
 2622 /*
 2623  * 'httpSetLength()' - Set the content-length and content-encoding.
 2624  *
 2625  * @since CUPS 1.2/macOS 10.5@
 2626  */
 2627 
 2628 void
 2629 httpSetLength(http_t *http,     /* I - HTTP connection */
 2630               size_t length)        /* I - Length (0 for chunked) */
 2631 {
 2632   DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
 2633 
 2634   if (!http)
 2635     return;
 2636 
 2637   if (!length)
 2638   {
 2639     httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked");
 2640     httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "");
 2641   }
 2642   else
 2643   {
 2644     char len[32];           /* Length string */
 2645 
 2646 
 2647     snprintf(len, sizeof(len), CUPS_LLFMT, CUPS_LLCAST length);
 2648     httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "");
 2649     httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, len);
 2650   }
 2651 }
 2652 
 2653 
 2654 /*
 2655  * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
 2656  *
 2657  * The optional timeout callback receives both the HTTP connection and a user
 2658  * data pointer and must return 1 to continue or 0 to error (time) out.
 2659  *
 2660  * @since CUPS 1.5/macOS 10.7@
 2661  */
 2662 
 2663 void
 2664 httpSetTimeout(
 2665     http_t            *http,        /* I - HTTP connection */
 2666     double            timeout,      /* I - Number of seconds for timeout,
 2667                                                must be greater than 0 */
 2668     http_timeout_cb_t cb,       /* I - Callback function or @code NULL@ */
 2669     void              *user_data)   /* I - User data pointer */
 2670 {
 2671   if (!http || timeout <= 0.0)
 2672     return;
 2673 
 2674   http->timeout_cb    = cb;
 2675   http->timeout_data  = user_data;
 2676   http->timeout_value = timeout;
 2677 
 2678   if (http->fd >= 0)
 2679     http_set_timeout(http->fd, timeout);
 2680 
 2681   http_set_wait(http);
 2682 }
 2683 
 2684 
 2685 /*
 2686  * 'httpShutdown()' - Shutdown one side of an HTTP connection.
 2687  *
 2688  * @since CUPS 2.0/OS 10.10@
 2689  */
 2690 
 2691 void
 2692 httpShutdown(http_t *http)      /* I - HTTP connection */
 2693 {
 2694   if (!http || http->fd < 0)
 2695     return;
 2696 
 2697 #ifdef HAVE_SSL
 2698   if (http->tls)
 2699     _httpTLSStop(http);
 2700 #endif /* HAVE_SSL */
 2701 
 2702 #ifdef _WIN32
 2703   shutdown(http->fd, SD_RECEIVE);   /* Microsoft-ism... */
 2704 #else
 2705   shutdown(http->fd, SHUT_RD);
 2706 #endif /* _WIN32 */
 2707 }
 2708 
 2709 
 2710 /*
 2711  * 'httpTrace()' - Send an TRACE request to the server.
 2712  *
 2713  * @exclude all@
 2714  */
 2715 
 2716 int                 /* O - Status of call (0 = success) */
 2717 httpTrace(http_t     *http,     /* I - HTTP connection */
 2718           const char *uri)      /* I - URI for trace */
 2719 {
 2720   return (http_send(http, HTTP_STATE_TRACE, uri));
 2721 }
 2722 
 2723 
 2724 /*
 2725  * '_httpUpdate()' - Update the current HTTP status for incoming data.
 2726  *
 2727  * Note: Unlike httpUpdate(), this function does not flush pending write data
 2728  * and only retrieves a single status line from the HTTP connection.
 2729  */
 2730 
 2731 int                 /* O - 1 to continue, 0 to stop */
 2732 _httpUpdate(http_t        *http,    /* I - HTTP connection */
 2733             http_status_t *status)  /* O - Current HTTP status */
 2734 {
 2735   char      line[32768],        /* Line from connection... */
 2736         *value;         /* Pointer to value on line */
 2737   http_field_t  field;          /* Field index */
 2738   int       major, minor;       /* HTTP version numbers */
 2739 
 2740 
 2741   DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
 2742 
 2743  /*
 2744   * Grab a single line from the connection...
 2745   */
 2746 
 2747   if (!httpGets(line, sizeof(line), http))
 2748   {
 2749     *status = HTTP_STATUS_ERROR;
 2750     return (0);
 2751   }
 2752 
 2753   DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
 2754 
 2755   if (line[0] == '\0')
 2756   {
 2757    /*
 2758     * Blank line means the start of the data section (if any).  Return
 2759     * the result code, too...
 2760     *
 2761     * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
 2762     * states.  Instead, we just return HTTP_STATUS_CONTINUE to the caller and
 2763     * keep on tryin'...
 2764     */
 2765 
 2766     if (http->status == HTTP_STATUS_CONTINUE)
 2767     {
 2768       *status = http->status;
 2769       return (0);
 2770     }
 2771 
 2772     if (http->status < HTTP_STATUS_BAD_REQUEST)
 2773       http->digest_tries = 0;
 2774 
 2775 #ifdef HAVE_SSL
 2776     if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
 2777     {
 2778       if (_httpTLSStart(http) != 0)
 2779       {
 2780         httpAddrClose(NULL, http->fd);
 2781 
 2782     *status = http->status = HTTP_STATUS_ERROR;
 2783     return (0);
 2784       }
 2785 
 2786       *status = HTTP_STATUS_CONTINUE;
 2787       return (0);
 2788     }
 2789 #endif /* HAVE_SSL */
 2790 
 2791     if (http_set_length(http) < 0)
 2792     {
 2793       DEBUG_puts("1_httpUpdate: Bad Content-Length.");
 2794       http->error  = EINVAL;
 2795       http->status = *status = HTTP_STATUS_ERROR;
 2796       return (0);
 2797     }
 2798 
 2799     switch (http->state)
 2800     {
 2801       case HTTP_STATE_GET :
 2802       case HTTP_STATE_POST :
 2803       case HTTP_STATE_POST_RECV :
 2804       case HTTP_STATE_PUT :
 2805       http->state ++;
 2806 
 2807       DEBUG_printf(("1_httpUpdate: Set state to %s.",
 2808                     httpStateString(http->state)));
 2809 
 2810       case HTTP_STATE_POST_SEND :
 2811       case HTTP_STATE_HEAD :
 2812       break;
 2813 
 2814       default :
 2815       http->state = HTTP_STATE_WAITING;
 2816 
 2817       DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
 2818       break;
 2819     }
 2820 
 2821 #ifdef HAVE_LIBZ
 2822     DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
 2823     http_content_coding_start(http,
 2824                               httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
 2825 #endif /* HAVE_LIBZ */
 2826 
 2827     *status = http->status;
 2828     return (0);
 2829   }
 2830   else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
 2831   {
 2832    /*
 2833     * Got the beginning of a response...
 2834     */
 2835 
 2836     int intstatus;          /* Status value as an integer */
 2837 
 2838     if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
 2839     {
 2840       *status = http->status = HTTP_STATUS_ERROR;
 2841       return (0);
 2842     }
 2843 
 2844     httpClearFields(http);
 2845 
 2846     http->version = (http_version_t)(major * 100 + minor);
 2847     *status       = http->status = (http_status_t)intstatus;
 2848   }
 2849   else if ((value = strchr(line, ':')) != NULL)
 2850   {
 2851    /*
 2852     * Got a value...
 2853     */
 2854 
 2855     *value++ = '\0';
 2856     while (_cups_isspace(*value))
 2857       value ++;
 2858 
 2859     DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
 2860 
 2861    /*
 2862     * Be tolerants of servers that send unknown attribute fields...
 2863     */
 2864 
 2865     if (!_cups_strcasecmp(line, "expect"))
 2866     {
 2867      /*
 2868       * "Expect: 100-continue" or similar...
 2869       */
 2870 
 2871       http->expect = (http_status_t)atoi(value);
 2872     }
 2873     else if (!_cups_strcasecmp(line, "cookie"))
 2874     {
 2875      /*
 2876       * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
 2877       */
 2878 
 2879       httpSetCookie(http, value);
 2880     }
 2881     else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
 2882     {
 2883       http_add_field(http, field, value, 1);
 2884 
 2885       if (field == HTTP_FIELD_AUTHENTICATION_INFO)
 2886         httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce));
 2887     }
 2888 #ifdef DEBUG
 2889     else
 2890       DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
 2891 #endif /* DEBUG */
 2892   }
 2893   else
 2894   {
 2895     DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
 2896     http->error  = EINVAL;
 2897     http->status = *status = HTTP_STATUS_ERROR;
 2898     return (0);
 2899   }
 2900 
 2901   return (1);
 2902 }
 2903 
 2904 
 2905 /*
 2906  * 'httpUpdate()' - Update the current HTTP state for incoming data.
 2907  */
 2908 
 2909 http_status_t               /* O - HTTP status */
 2910 httpUpdate(http_t *http)        /* I - HTTP connection */
 2911 {
 2912   http_status_t status;         /* Request status */
 2913 
 2914 
 2915   DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
 2916 
 2917  /*
 2918   * Flush pending data, if any...
 2919   */
 2920 
 2921   if (http->wused)
 2922   {
 2923     DEBUG_puts("2httpUpdate: flushing buffer...");
 2924 
 2925     if (httpFlushWrite(http) < 0)
 2926       return (HTTP_STATUS_ERROR);
 2927   }
 2928 
 2929  /*
 2930   * If we haven't issued any commands, then there is nothing to "update"...
 2931   */
 2932 
 2933   if (http->state == HTTP_STATE_WAITING)
 2934     return (HTTP_STATUS_CONTINUE);
 2935 
 2936  /*
 2937   * Grab all of the lines we can from the connection...
 2938   */
 2939 
 2940   while (_httpUpdate(http, &status));
 2941 
 2942  /*
 2943   * See if there was an error...
 2944   */
 2945 
 2946   if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
 2947   {
 2948     DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
 2949     return (http->status);
 2950   }
 2951 
 2952   if (http->error)
 2953   {
 2954     DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
 2955                   strerror(http->error)));
 2956     http->status = HTTP_STATUS_ERROR;
 2957     return (HTTP_STATUS_ERROR);
 2958   }
 2959 
 2960  /*
 2961   * Return the current status...
 2962   */
 2963 
 2964   return (status);
 2965 }
 2966 
 2967 
 2968 /*
 2969  * '_httpWait()' - Wait for data available on a connection (no flush).
 2970  */
 2971 
 2972 int                 /* O - 1 if data is available, 0 otherwise */
 2973 _httpWait(http_t *http,         /* I - HTTP connection */
 2974           int    msec,          /* I - Milliseconds to wait */
 2975       int    usessl)        /* I - Use SSL context? */
 2976 {
 2977 #ifdef HAVE_POLL
 2978   struct pollfd     pfd;        /* Polled file descriptor */
 2979 #else
 2980   fd_set        input_set;  /* select() input set */
 2981   struct timeval    timeout;    /* Timeout */
 2982 #endif /* HAVE_POLL */
 2983   int           nfds;       /* Result from select()/poll() */
 2984 
 2985 
 2986   DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
 2987 
 2988   if (http->fd < 0)
 2989   {
 2990     DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
 2991     return (0);
 2992   }
 2993 
 2994  /*
 2995   * Check the SSL/TLS buffers for data first...
 2996   */
 2997 
 2998 #ifdef HAVE_SSL
 2999   if (http->tls && _httpTLSPending(http))
 3000   {
 3001     DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
 3002     return (1);
 3003   }
 3004 #endif /* HAVE_SSL */
 3005 
 3006  /*
 3007   * Then try doing a select() or poll() to poll the socket...
 3008   */
 3009 
 3010 #ifdef HAVE_POLL
 3011   pfd.fd     = http->fd;
 3012   pfd.events = POLLIN;
 3013 
 3014   do
 3015   {
 3016     nfds = poll(&pfd, 1, msec);
 3017   }
 3018   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
 3019 
 3020 #else
 3021   do
 3022   {
 3023     FD_ZERO(&input_set);
 3024     FD_SET(http->fd, &input_set);
 3025 
 3026     DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
 3027 
 3028     if (msec >= 0)
 3029     {
 3030       timeout.tv_sec  = msec / 1000;
 3031       timeout.tv_usec = (msec % 1000) * 1000;
 3032 
 3033       nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
 3034     }
 3035     else
 3036       nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
 3037 
 3038     DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
 3039   }
 3040 #  ifdef _WIN32
 3041   while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
 3042                       WSAGetLastError() == WSAEWOULDBLOCK));
 3043 #  else
 3044   while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
 3045 #  endif /* _WIN32 */
 3046 #endif /* HAVE_POLL */
 3047 
 3048   DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
 3049                 errno));
 3050 
 3051   return (nfds > 0);
 3052 }
 3053 
 3054 
 3055 /*
 3056  * 'httpWait()' - Wait for data available on a connection.
 3057  *
 3058  * @since CUPS 1.1.19/macOS 10.3@
 3059  */
 3060 
 3061 int                 /* O - 1 if data is available, 0 otherwise */
 3062 httpWait(http_t *http,          /* I - HTTP connection */
 3063          int    msec)           /* I - Milliseconds to wait */
 3064 {
 3065  /*
 3066   * First see if there is data in the buffer...
 3067   */
 3068 
 3069   DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
 3070 
 3071   if (http == NULL)
 3072     return (0);
 3073 
 3074   if (http->used)
 3075   {
 3076     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
 3077     return (1);
 3078   }
 3079 
 3080 #ifdef HAVE_LIBZ
 3081   if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0)
 3082   {
 3083     DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
 3084     return (1);
 3085   }
 3086 #endif /* HAVE_LIBZ */
 3087 
 3088  /*
 3089   * Flush pending data, if any...
 3090   */
 3091 
 3092   if (http->wused)
 3093   {
 3094     DEBUG_puts("3httpWait: Flushing write buffer.");
 3095 
 3096     if (httpFlushWrite(http) < 0)
 3097       return (0);
 3098   }
 3099 
 3100  /*
 3101   * If not, check the SSL/TLS buffers and do a select() on the connection...
 3102   */
 3103 
 3104   return (_httpWait(http, msec, 1));
 3105 }
 3106 
 3107 
 3108 /*
 3109  * 'httpWrite()' - Write data to a HTTP connection.
 3110  *
 3111  * This function is deprecated. Use the httpWrite2() function which can
 3112  * write more than 2GB of data.
 3113  *
 3114  * @deprecated@ @exclude all@
 3115  */
 3116 
 3117 int                 /* O - Number of bytes written */
 3118 httpWrite(http_t     *http,     /* I - HTTP connection */
 3119           const char *buffer,       /* I - Buffer for data */
 3120       int        length)        /* I - Number of bytes to write */
 3121 {
 3122   return ((int)httpWrite2(http, buffer, (size_t)length));
 3123 }
 3124 
 3125 
 3126 /*
 3127  * 'httpWrite2()' - Write data to a HTTP connection.
 3128  *
 3129  * @since CUPS 1.2/macOS 10.5@
 3130  */
 3131 
 3132 ssize_t                 /* O - Number of bytes written */
 3133 httpWrite2(http_t     *http,        /* I - HTTP connection */
 3134            const char *buffer,      /* I - Buffer for data */
 3135        size_t     length)       /* I - Number of bytes to write */
 3136 {
 3137   ssize_t   bytes;          /* Bytes written */
 3138 
 3139 
 3140   DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 3141 
 3142  /*
 3143   * Range check input...
 3144   */
 3145 
 3146   if (!http || !buffer)
 3147   {
 3148     DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
 3149     return (-1);
 3150   }
 3151 
 3152  /*
 3153   * Mark activity on the connection...
 3154   */
 3155 
 3156   http->activity = time(NULL);
 3157 
 3158  /*
 3159   * Buffer small writes for better performance...
 3160   */
 3161 
 3162 #ifdef HAVE_LIBZ
 3163   if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
 3164   {
 3165     DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
 3166 
 3167     if (length == 0)
 3168     {
 3169       http_content_coding_finish(http);
 3170       bytes = 0;
 3171     }
 3172     else
 3173     {
 3174       size_t    slen;           /* Bytes to write */
 3175       ssize_t   sret;           /* Bytes written */
 3176 
 3177       ((z_stream *)http->stream)->next_in   = (Bytef *)buffer;
 3178       ((z_stream *)http->stream)->avail_in  = (uInt)length;
 3179 
 3180       while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK)
 3181       {
 3182         DEBUG_printf(("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out));
 3183 
 3184         if (((z_stream *)http->stream)->avail_out > 0)
 3185       continue;
 3186 
 3187     slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
 3188 
 3189         DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
 3190 
 3191     if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
 3192       sret = http_write_chunk(http, (char *)http->sbuffer, slen);
 3193     else if (slen > 0)
 3194       sret = http_write(http, (char *)http->sbuffer, slen);
 3195     else
 3196       sret = 0;
 3197 
 3198         if (sret < 0)
 3199     {
 3200       DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
 3201       return (-1);
 3202     }
 3203 
 3204     ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
 3205     ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
 3206       }
 3207 
 3208       bytes = (ssize_t)length;
 3209     }
 3210   }
 3211   else
 3212 #endif /* HAVE_LIBZ */
 3213   if (length > 0)
 3214   {
 3215     if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
 3216     {
 3217       DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
 3218                     CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));
 3219 
 3220       httpFlushWrite(http);
 3221     }
 3222 
 3223     if ((length + (size_t)http->wused) <= sizeof(http->wbuffer) && length < sizeof(http->wbuffer))
 3224     {
 3225      /*
 3226       * Write to buffer...
 3227       */
 3228 
 3229       DEBUG_printf(("2httpWrite2: Copying " CUPS_LLFMT " bytes to wbuffer...",
 3230                     CUPS_LLCAST length));
 3231 
 3232       memcpy(http->wbuffer + http->wused, buffer, length);
 3233       http->wused += (int)length;
 3234       bytes = (ssize_t)length;
 3235     }
 3236     else
 3237     {
 3238      /*
 3239       * Otherwise write the data directly...
 3240       */
 3241 
 3242       DEBUG_printf(("2httpWrite2: Writing " CUPS_LLFMT " bytes to socket...",
 3243                     CUPS_LLCAST length));
 3244 
 3245       if (http->data_encoding == HTTP_ENCODING_CHUNKED)
 3246     bytes = (ssize_t)http_write_chunk(http, buffer, length);
 3247       else
 3248     bytes = (ssize_t)http_write(http, buffer, length);
 3249 
 3250       DEBUG_printf(("2httpWrite2: Wrote " CUPS_LLFMT " bytes...",
 3251                     CUPS_LLCAST bytes));
 3252     }
 3253 
 3254     if (http->data_encoding == HTTP_ENCODING_LENGTH)
 3255       http->data_remaining -= bytes;
 3256   }
 3257   else
 3258     bytes = 0;
 3259 
 3260  /*
 3261   * Handle end-of-request processing...
 3262   */
 3263 
 3264   if ((http->data_encoding == HTTP_ENCODING_CHUNKED && length == 0) ||
 3265       (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0))
 3266   {
 3267    /*
 3268     * Finished with the transfer; unless we are sending POST or PUT
 3269     * data, go idle...
 3270     */
 3271 
 3272 #ifdef HAVE_LIBZ
 3273     if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
 3274       http_content_coding_finish(http);
 3275 #endif /* HAVE_LIBZ */
 3276 
 3277     if (http->wused)
 3278     {
 3279       if (httpFlushWrite(http) < 0)
 3280         return (-1);
 3281     }
 3282 
 3283     if (http->data_encoding == HTTP_ENCODING_CHUNKED)
 3284     {
 3285      /*
 3286       * Send a 0-length chunk at the end of the request...
 3287       */
 3288 
 3289       http_write(http, "0\r\n\r\n", 5);
 3290 
 3291      /*
 3292       * Reset the data state...
 3293       */
 3294 
 3295       http->data_encoding  = HTTP_ENCODING_FIELDS;
 3296       http->data_remaining = 0;
 3297     }
 3298 
 3299     if (http->state == HTTP_STATE_POST_RECV)
 3300       http->state ++;
 3301     else if (http->state == HTTP_STATE_POST_SEND ||
 3302              http->state == HTTP_STATE_GET_SEND)
 3303       http->state = HTTP_STATE_WAITING;
 3304     else
 3305       http->state = HTTP_STATE_STATUS;
 3306 
 3307     DEBUG_printf(("2httpWrite2: Changed state to %s.",
 3308           httpStateString(http->state)));
 3309   }
 3310 
 3311   DEBUG_printf(("1httpWrite2: Returning " CUPS_LLFMT ".", CUPS_LLCAST bytes));
 3312 
 3313   return (bytes);
 3314 }
 3315 
 3316 
 3317 /*
 3318  * 'httpWriteResponse()' - Write a HTTP response to a client connection.
 3319  *
 3320  * @since CUPS 1.7/macOS 10.9@
 3321  */
 3322 
 3323 int                 /* O - 0 on success, -1 on error */
 3324 httpWriteResponse(http_t        *http,  /* I - HTTP connection */
 3325           http_status_t status) /* I - Status code */
 3326 {
 3327   http_encoding_t   old_encoding;   /* Old data_encoding value */
 3328   off_t         old_remaining;  /* Old data_remaining value */
 3329 
 3330 
 3331  /*
 3332   * Range check input...
 3333   */
 3334 
 3335   DEBUG_printf(("httpWriteResponse(http=%p, status=%d)", (void *)http, status));
 3336 
 3337   if (!http || status < HTTP_STATUS_CONTINUE)
 3338   {
 3339     DEBUG_puts("1httpWriteResponse: Bad input.");
 3340     return (-1);
 3341   }
 3342 
 3343  /*
 3344   * Set the various standard fields if they aren't already...
 3345   */
 3346 
 3347   if (!http->fields[HTTP_FIELD_DATE])
 3348     httpSetField(http, HTTP_FIELD_DATE, httpGetDateString(time(NULL)));
 3349 
 3350   if (status >= HTTP_STATUS_BAD_REQUEST && http->keep_alive)
 3351   {
 3352     http->keep_alive = HTTP_KEEPALIVE_OFF;
 3353     httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "");
 3354   }
 3355 
 3356   if (http->version == HTTP_VERSION_1_1)
 3357   {
 3358     if (!http->fields[HTTP_FIELD_CONNECTION])
 3359     {
 3360       if (http->keep_alive)
 3361     httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive");
 3362       else
 3363     httpSetField(http, HTTP_FIELD_CONNECTION, "close");
 3364     }
 3365 
 3366     if (http->keep_alive && !http->fields[HTTP_FIELD_KEEP_ALIVE])
 3367       httpSetField(http, HTTP_FIELD_KEEP_ALIVE, "timeout=10");
 3368   }
 3369 
 3370 #ifdef HAVE_SSL
 3371   if (status == HTTP_STATUS_UPGRADE_REQUIRED ||
 3372       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
 3373   {
 3374     if (!http->fields[HTTP_FIELD_CONNECTION])
 3375       httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
 3376 
 3377     if (!http->fields[HTTP_FIELD_UPGRADE])
 3378       httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
 3379 
 3380     if (!http->fields[HTTP_FIELD_CONTENT_LENGTH])
 3381       httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, "0");
 3382   }
 3383 #endif /* HAVE_SSL */
 3384 
 3385   if (!http->fields[HTTP_FIELD_SERVER])
 3386     httpSetField(http, HTTP_FIELD_SERVER, http->default_fields[HTTP_FIELD_SERVER] ? http->default_fields[HTTP_FIELD_SERVER] : CUPS_MINIMAL);
 3387 
 3388  /*
 3389   * Set the Accept-Encoding field if it isn't already...
 3390   */
 3391 
 3392   if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING])
 3393     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] ? http->default_fields[HTTP_FIELD_ACCEPT_ENCODING] :
 3394 #ifdef HAVE_LIBZ
 3395                                                  "gzip, deflate, identity");
 3396 #else
 3397                                                  "identity");
 3398 #endif /* HAVE_LIBZ */
 3399 
 3400  /*
 3401   * Send the response header...
 3402   */
 3403 
 3404   old_encoding        = http->data_encoding;
 3405   old_remaining       = http->data_remaining;
 3406   http->data_encoding = HTTP_ENCODING_FIELDS;
 3407 
 3408   if (httpPrintf(http, "HTTP/%d.%d %d %s\r\n", http->version / 100, http->version % 100, (int)status, httpStatus(status)) < 0)
 3409   {
 3410     http->status = HTTP_STATUS_ERROR;
 3411     return (-1);
 3412   }
 3413 
 3414   if (status != HTTP_STATUS_CONTINUE)
 3415   {
 3416    /*
 3417     * 100 Continue doesn't have the rest of the response headers...
 3418     */
 3419 
 3420     int     i;          /* Looping var */
 3421     const char  *value;         /* Field value */
 3422 
 3423     for (i = 0; i < HTTP_FIELD_MAX; i ++)
 3424     {
 3425       if ((value = httpGetField(http, i)) != NULL && *value)
 3426       {
 3427     if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
 3428     {
 3429       http->status = HTTP_STATUS_ERROR;
 3430       return (-1);
 3431     }
 3432       }
 3433     }
 3434 
 3435     if (http->cookie)
 3436     {
 3437       if (strchr(http->cookie, ';'))
 3438       {
 3439         if (httpPrintf(http, "Set-Cookie: %s\r\n", http->cookie) < 1)
 3440     {
 3441       http->status = HTTP_STATUS_ERROR;
 3442       return (-1);
 3443     }
 3444       }
 3445       else if (httpPrintf(http, "Set-Cookie: %s; path=/; httponly;%s\r\n", http->cookie, http->tls ? " secure;" : "") < 1)
 3446       {
 3447     http->status = HTTP_STATUS_ERROR;
 3448     return (-1);
 3449       }
 3450     }
 3451 
 3452    /*
 3453     * "Click-jacking" defense (STR #4492)...
 3454     */
 3455 
 3456     if (httpPrintf(http, "X-Frame-Options: DENY\r\n"
 3457                          "Content-Security-Policy: frame-ancestors 'none'\r\n") < 1)
 3458     {
 3459       http->status = HTTP_STATUS_ERROR;
 3460       return (-1);
 3461     }
 3462   }
 3463 
 3464   if (httpWrite2(http, "\r\n", 2) < 2)
 3465   {
 3466     http->status = HTTP_STATUS_ERROR;
 3467     return (-1);
 3468   }
 3469 
 3470   if (httpFlushWrite(http) < 0)
 3471   {
 3472     http->status = HTTP_STATUS_ERROR;
 3473     return (-1);
 3474   }
 3475 
 3476   if (status == HTTP_STATUS_CONTINUE ||
 3477       status == HTTP_STATUS_SWITCHING_PROTOCOLS)
 3478   {
 3479    /*
 3480     * Restore the old data_encoding and data_length values...
 3481     */
 3482 
 3483     http->data_encoding  = old_encoding;
 3484     http->data_remaining = old_remaining;
 3485 
 3486     if (old_remaining <= INT_MAX)
 3487       http->_data_remaining = (int)old_remaining;
 3488     else
 3489       http->_data_remaining = INT_MAX;
 3490   }
 3491   else if (http->state == HTTP_STATE_OPTIONS ||
 3492            http->state == HTTP_STATE_HEAD ||
 3493            http->state == HTTP_STATE_PUT ||
 3494            http->state == HTTP_STATE_TRACE ||
 3495            http->state == HTTP_STATE_CONNECT ||
 3496            http->state == HTTP_STATE_STATUS)
 3497   {
 3498     DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
 3499                   "was %s.", httpStateString(http->state)));
 3500     http->state = HTTP_STATE_WAITING;
 3501   }
 3502   else
 3503   {
 3504    /*
 3505     * Force data_encoding and data_length to be set according to the response
 3506     * headers...
 3507     */
 3508 
 3509     http_set_length(http);
 3510 
 3511     if (http->data_encoding == HTTP_ENCODING_LENGTH && http->data_remaining == 0)
 3512     {
 3513       DEBUG_printf(("1httpWriteResponse: Resetting state to HTTP_STATE_WAITING, "
 3514                     "was %s.", httpStateString(http->state)));
 3515       http->state = HTTP_STATE_WAITING;
 3516       return (0);
 3517     }
 3518 
 3519     if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
 3520       http->state ++;
 3521 
 3522 #ifdef HAVE_LIBZ
 3523    /*
 3524     * Then start any content encoding...
 3525     */
 3526 
 3527     DEBUG_puts("1httpWriteResponse: Calling http_content_coding_start.");
 3528     http_content_coding_start(http,
 3529                   httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
 3530 #endif /* HAVE_LIBZ */
 3531 
 3532   }
 3533 
 3534   return (0);
 3535 }
 3536 
 3537 
 3538 /*
 3539  * 'http_add_field()' - Add a value for a HTTP field, appending if needed.
 3540  */
 3541 
 3542 static void
 3543 http_add_field(http_t       *http,  /* I - HTTP connection */
 3544                http_field_t field,  /* I - HTTP field */
 3545                const char   *value, /* I - Value string */
 3546                int          append) /* I - Append value? */
 3547 {
 3548   char      temp[1024];     /* Temporary value string */
 3549   size_t    fieldlen,       /* Length of existing value */
 3550         valuelen,       /* Length of value string */
 3551         total;          /* Total length of string */
 3552 
 3553 
 3554   if (field == HTTP_FIELD_HOST)
 3555   {
 3556    /*
 3557     * Special-case for Host: as we don't want a trailing "." on the hostname and
 3558     * need to bracket IPv6 numeric addresses.
 3559     */
 3560 
 3561     char *ptr = strchr(value, ':');
 3562 
 3563     if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
 3564     {
 3565      /*
 3566       * Bracket IPv6 numeric addresses...
 3567       *
 3568       * This is slightly inefficient (basically copying twice), but is an edge
 3569       * case and not worth optimizing...
 3570       */
 3571 
 3572       snprintf(temp, sizeof(temp), "[%s]", value);
 3573       value = temp;
 3574     }
 3575     else if (*value)
 3576     {
 3577      /*
 3578       * Check for a trailing dot on the hostname...
 3579       */
 3580 
 3581       strlcpy(temp, value, sizeof(temp));
 3582       value = temp;
 3583       ptr   = temp + strlen(temp) - 1;
 3584 
 3585       if (*ptr == '.')
 3586     *ptr = '\0';
 3587     }
 3588   }
 3589 
 3590   if (append && field != HTTP_FIELD_ACCEPT_ENCODING && field != HTTP_FIELD_ACCEPT_LANGUAGE && field != HTTP_FIELD_ACCEPT_RANGES && field != HTTP_FIELD_ALLOW && field != HTTP_FIELD_LINK && field != HTTP_FIELD_TRANSFER_ENCODING && field != HTTP_FIELD_UPGRADE && field != HTTP_FIELD_WWW_AUTHENTICATE)
 3591     append = 0;
 3592 
 3593   if (!append && http->fields[field])
 3594   {
 3595     if (http->fields[field] != http->_fields[field])
 3596       free(http->fields[field]);
 3597 
 3598     http->fields[field] = NULL;
 3599   }
 3600 
 3601   valuelen = strlen(value);
 3602 
 3603   if (!valuelen)
 3604   {
 3605     http->_fields[field][0] = '\0';
 3606     return;
 3607   }
 3608 
 3609   if (http->fields[field])
 3610   {
 3611     fieldlen = strlen(http->fields[field]);
 3612     total    = fieldlen + 2 + valuelen;
 3613   }
 3614   else
 3615   {
 3616     fieldlen = 0;
 3617     total    = valuelen;
 3618   }
 3619 
 3620   if (total < HTTP_MAX_VALUE && field < HTTP_FIELD_ACCEPT_ENCODING)
 3621   {
 3622    /*
 3623     * Copy short values to legacy char arrays (maintained for binary
 3624     * compatibility with CUPS 1.2.x and earlier applications...)
 3625     */
 3626 
 3627     if (fieldlen)
 3628     {
 3629       char  combined[HTTP_MAX_VALUE];
 3630                     /* Combined value string */
 3631 
 3632       snprintf(combined, sizeof(combined), "%s, %s", http->_fields[field], value);
 3633       value = combined;
 3634     }
 3635 
 3636     strlcpy(http->_fields[field], value, sizeof(http->_fields[field]));
 3637     http->fields[field] = http->_fields[field];
 3638   }
 3639   else if (fieldlen)
 3640   {
 3641    /*
 3642     * Expand the field value...
 3643     */
 3644 
 3645     char    *combined;      /* New value string */
 3646 
 3647     if (http->fields[field] == http->_fields[field])
 3648     {
 3649       if ((combined = malloc(total + 1)) != NULL)
 3650       {
 3651     http->fields[field] = combined;
 3652     snprintf(combined, total + 1, "%s, %s", http->_fields[field], value);
 3653       }
 3654     }
 3655     else if ((combined = realloc(http->fields[field], total + 1)) != NULL)
 3656     {
 3657       http->fields[field] = combined;
 3658       strlcat(combined, ", ", total + 1);
 3659       strlcat(combined, value, total + 1);
 3660     }
 3661   }
 3662   else
 3663   {
 3664    /*
 3665     * Allocate the field value...
 3666     */
 3667 
 3668     http->fields[field] = strdup(value);
 3669   }
 3670 
 3671 #ifdef HAVE_LIBZ
 3672   if (field == HTTP_FIELD_CONTENT_ENCODING && http->data_encoding != HTTP_ENCODING_FIELDS)
 3673   {
 3674     DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
 3675     http_content_coding_start(http, value);
 3676   }
 3677 #endif /* HAVE_LIBZ */
 3678 }
 3679 
 3680 
 3681 #ifdef HAVE_LIBZ
 3682 /*
 3683  * 'http_content_coding_finish()' - Finish doing any content encoding.
 3684  */
 3685 
 3686 static void
 3687 http_content_coding_finish(
 3688     http_t *http)           /* I - HTTP connection */
 3689 {
 3690   int       zerr;           /* Compression status */
 3691   Byte      dummy[1];       /* Dummy read buffer */
 3692   size_t    bytes;          /* Number of bytes to write */
 3693 
 3694 
 3695   DEBUG_printf(("http_content_coding_finish(http=%p)", (void *)http));
 3696   DEBUG_printf(("1http_content_coding_finishing: http->coding=%d", http->coding));
 3697 
 3698   switch (http->coding)
 3699   {
 3700     case _HTTP_CODING_DEFLATE :
 3701     case _HTTP_CODING_GZIP :
 3702         ((z_stream *)http->stream)->next_in  = dummy;
 3703         ((z_stream *)http->stream)->avail_in = 0;
 3704 
 3705         do
 3706         {
 3707           zerr  = deflate((z_stream *)http->stream, Z_FINISH);
 3708       bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out;
 3709 
 3710           if (bytes > 0)
 3711       {
 3712         DEBUG_printf(("1http_content_coding_finish: Writing trailing chunk, len=%d", (int)bytes));
 3713 
 3714         if (http->data_encoding == HTTP_ENCODING_CHUNKED)
 3715           http_write_chunk(http, (char *)http->sbuffer, bytes);
 3716         else
 3717           http_write(http, (char *)http->sbuffer, bytes);
 3718           }
 3719 
 3720           ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
 3721           ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
 3722     }
 3723         while (zerr == Z_OK);
 3724 
 3725         deflateEnd((z_stream *)http->stream);
 3726 
 3727         free(http->sbuffer);
 3728         free(http->stream);
 3729 
 3730         http->sbuffer = NULL;
 3731         http->stream  = NULL;
 3732 
 3733         if (http->wused)
 3734           httpFlushWrite(http);
 3735         break;
 3736 
 3737     case _HTTP_CODING_INFLATE :
 3738     case _HTTP_CODING_GUNZIP :
 3739         inflateEnd((z_stream *)http->stream);
 3740 
 3741         free(http->sbuffer);
 3742         free(http->stream);
 3743 
 3744         http->sbuffer = NULL;
 3745         http->stream  = NULL;
 3746         break;
 3747 
 3748     default :
 3749         break;
 3750   }
 3751 
 3752   http->coding = _HTTP_CODING_IDENTITY;
 3753 }
 3754 
 3755 
 3756 /*
 3757  * 'http_content_coding_start()' - Start doing content encoding.
 3758  */
 3759 
 3760 static void
 3761 http_content_coding_start(
 3762     http_t     *http,           /* I - HTTP connection */
 3763     const char *value)          /* I - Value of Content-Encoding */
 3764 {
 3765   int           zerr;       /* Error/status */
 3766   _http_coding_t    coding;     /* Content coding value */
 3767 
 3768 
 3769   DEBUG_printf(("http_content_coding_start(http=%p, value=\"%s\")", (void *)http, value));
 3770 
 3771   if (http->coding != _HTTP_CODING_IDENTITY)
 3772   {
 3773     DEBUG_printf(("1http_content_coding_start: http->coding already %d.",
 3774                   http->coding));
 3775     return;
 3776   }
 3777   else if (!strcmp(value, "x-gzip") || !strcmp(value, "gzip"))
 3778   {
 3779     if (http->state == HTTP_STATE_GET_SEND ||
 3780         http->state == HTTP_STATE_POST_SEND)
 3781       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_GZIP :
 3782                                                  _HTTP_CODING_GUNZIP;
 3783     else if (http->state == HTTP_STATE_POST_RECV ||
 3784              http->state == HTTP_STATE_PUT_RECV)
 3785       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_GZIP :
 3786                                                  _HTTP_CODING_GUNZIP;
 3787     else
 3788     {
 3789       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
 3790       return;
 3791     }
 3792   }
 3793   else if (!strcmp(value, "x-deflate") || !strcmp(value, "deflate"))
 3794   {
 3795     if (http->state == HTTP_STATE_GET_SEND ||
 3796         http->state == HTTP_STATE_POST_SEND)
 3797       coding = http->mode == _HTTP_MODE_SERVER ? _HTTP_CODING_DEFLATE :
 3798                                                  _HTTP_CODING_INFLATE;
 3799     else if (http->state == HTTP_STATE_POST_RECV ||
 3800              http->state == HTTP_STATE_PUT_RECV)
 3801       coding = http->mode == _HTTP_MODE_CLIENT ? _HTTP_CODING_DEFLATE :
 3802                                                  _HTTP_CODING_INFLATE;
 3803     else
 3804     {
 3805       DEBUG_puts("1http_content_coding_start: Not doing content coding.");
 3806       return;
 3807     }
 3808   }
 3809   else
 3810   {
 3811     DEBUG_puts("1http_content_coding_start: Not doing content coding.");
 3812     return;
 3813   }
 3814 
 3815   switch (coding)
 3816   {
 3817     case _HTTP_CODING_DEFLATE :
 3818     case _HTTP_CODING_GZIP :
 3819         if (http->wused)
 3820           httpFlushWrite(http);
 3821 
 3822         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
 3823         {
 3824           http->status = HTTP_STATUS_ERROR;
 3825           http->error  = errno;
 3826           return;
 3827         }
 3828 
 3829        /*
 3830         * Window size for compression is 11 bits - optimal based on PWG Raster
 3831         * sample files on pwg.org.  -11 is raw deflate, 27 is gzip, per ZLIB
 3832         * documentation.
 3833         */
 3834 
 3835     if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
 3836     {
 3837           free(http->sbuffer);
 3838 
 3839           http->sbuffer = NULL;
 3840           http->status  = HTTP_STATUS_ERROR;
 3841           http->error   = errno;
 3842           return;
 3843     }
 3844 
 3845         if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK)
 3846         {
 3847           free(http->sbuffer);
 3848           free(http->stream);
 3849 
 3850           http->sbuffer = NULL;
 3851           http->stream  = NULL;
 3852           http->status  = HTTP_STATUS_ERROR;
 3853           http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
 3854           return;
 3855         }
 3856 
 3857     ((z_stream *)http->stream)->next_out  = (Bytef *)http->sbuffer;
 3858     ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER;
 3859         break;
 3860 
 3861     case _HTTP_CODING_INFLATE :
 3862     case _HTTP_CODING_GUNZIP :
 3863         if ((http->sbuffer = malloc(_HTTP_MAX_SBUFFER)) == NULL)
 3864         {
 3865           http->status = HTTP_STATUS_ERROR;
 3866           http->error  = errno;
 3867           return;
 3868         }
 3869 
 3870        /*
 3871         * Window size for decompression is up to 15 bits (maximum supported).
 3872         * -15 is raw inflate, 31 is gunzip, per ZLIB documentation.
 3873         */
 3874 
 3875     if ((http->stream = calloc(1, sizeof(z_stream))) == NULL)
 3876     {
 3877           free(http->sbuffer);
 3878 
 3879           http->sbuffer = NULL;
 3880           http->status  = HTTP_STATUS_ERROR;
 3881           http->error   = errno;
 3882           return;
 3883     }
 3884 
 3885         if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK)
 3886         {
 3887           free(http->sbuffer);
 3888           free(http->stream);
 3889 
 3890           http->sbuffer = NULL;
 3891           http->stream  = NULL;
 3892           http->status  = HTTP_STATUS_ERROR;
 3893           http->error   = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL;
 3894           return;
 3895         }
 3896 
 3897         ((z_stream *)http->stream)->avail_in = 0;
 3898         ((z_stream *)http->stream)->next_in  = http->sbuffer;
 3899         break;
 3900 
 3901     default :
 3902         break;
 3903   }
 3904 
 3905   http->coding = coding;
 3906 
 3907   DEBUG_printf(("1http_content_coding_start: http->coding now %d.",
 3908         http->coding));
 3909 }
 3910 #endif /* HAVE_LIBZ */
 3911 
 3912 
 3913 /*
 3914  * 'http_create()' - Create an unconnected HTTP connection.
 3915  */
 3916 
 3917 static http_t *             /* O - HTTP connection */
 3918 http_create(
 3919     const char        *host,        /* I - Hostname */
 3920     int               port,     /* I - Port number */
 3921     http_addrlist_t   *addrlist,    /* I - Address list or @code NULL@ */
 3922     int               family,       /* I - Address family or AF_UNSPEC */
 3923     http_encryption_t encryption,   /* I - Encryption to use */
 3924     int               blocking,     /* I - 1 for blocking mode */
 3925     _http_mode_t      mode)     /* I - _HTTP_MODE_CLIENT or _SERVER */
 3926 {
 3927   http_t    *http;          /* New HTTP connection */
 3928   char      service[255];       /* Service name */
 3929   http_addrlist_t *myaddrlist = NULL;   /* My address list */
 3930 
 3931 
 3932   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));
 3933 
 3934   if (!host && mode == _HTTP_MODE_CLIENT)
 3935     return (NULL);
 3936 
 3937   httpInitialize();
 3938 
 3939  /*
 3940   * Lookup the host...
 3941   */
 3942 
 3943   if (addrlist)
 3944   {
 3945     myaddrlist = httpAddrCopyList(addrlist);
 3946   }
 3947   else
 3948   {
 3949     snprintf(service, sizeof(service), "%d", port);
 3950 
 3951     myaddrlist = httpAddrGetList(host, family, service);
 3952   }
 3953 
 3954   if (!myaddrlist)
 3955     return (NULL);
 3956 
 3957  /*
 3958   * Allocate memory for the structure...
 3959   */
 3960 
 3961   if ((http = calloc(sizeof(http_t), 1)) == NULL)
 3962   {
 3963     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
 3964     httpAddrFreeList(myaddrlist);
 3965     return (NULL);
 3966   }
 3967 
 3968  /*
 3969   * Initialize the HTTP data...
 3970   */
 3971 
 3972   http->mode     = mode;
 3973   http->activity = time(NULL);
 3974   http->addrlist = myaddrlist;
 3975   http->blocking = blocking;
 3976   http->fd       = -1;
 3977 #ifdef HAVE_GSSAPI
 3978   http->gssctx   = GSS_C_NO_CONTEXT;
 3979   http->gssname  = GSS_C_NO_NAME;
 3980 #endif /* HAVE_GSSAPI */
 3981   http->status   = HTTP_STATUS_CONTINUE;
 3982   http->version  = HTTP_VERSION_1_1;
 3983 
 3984   if (host)
 3985     strlcpy(http->hostname, host, sizeof(http->hostname));
 3986 
 3987   if (port == 443)          /* Always use encryption for https */
 3988     http->encryption = HTTP_ENCRYPTION_ALWAYS;
 3989   else
 3990     http->encryption = encryption;
 3991 
 3992   http_set_wait(http);
 3993 
 3994  /*
 3995   * Return the new structure...
 3996   */
 3997 
 3998   return (http);
 3999 }
 4000 
 4001 
 4002 #ifdef DEBUG
 4003 /*
 4004  * 'http_debug_hex()' - Do a hex dump of a buffer.
 4005  */
 4006 
 4007 static void
 4008 http_debug_hex(const char *prefix,  /* I - Prefix for line */
 4009                const char *buffer,  /* I - Buffer to dump */
 4010                int        bytes)    /* I - Bytes to dump */
 4011 {
 4012   int   i, j,               /* Looping vars */
 4013     ch;             /* Current character */
 4014   char  line[255],          /* Line buffer */
 4015     *start,             /* Start of line after prefix */
 4016     *ptr;               /* Pointer into line */
 4017 
 4018 
 4019   if (_cups_debug_fd < 0 || _cups_debug_level < 6)
 4020     return;
 4021 
 4022   DEBUG_printf(("6%s: %d bytes:", prefix, bytes));
 4023 
 4024   snprintf(line, sizeof(line), "6%s: ", prefix);
 4025   start = line + strlen(line);
 4026 
 4027   for (i = 0; i < bytes; i += 16)
 4028   {
 4029     for (j = 0, ptr = start; j < 16 && (i + j) < bytes; j ++, ptr += 2)
 4030       snprintf(ptr, 3, "%02X", buffer[i + j] & 255);
 4031 
 4032     while (j < 16)
 4033     {
 4034       memcpy(ptr, "  ", 3);
 4035       ptr += 2;
 4036       j ++;
 4037     }
 4038 
 4039     memcpy(ptr, "  ", 3);
 4040     ptr += 2;
 4041 
 4042     for (j = 0; j < 16 && (i + j) < bytes; j ++)
 4043     {
 4044       ch = buffer[i + j] & 255;
 4045 
 4046       if (ch < ' ' || ch >= 127)
 4047     ch = '.';
 4048 
 4049       *ptr++ = (char)ch;
 4050     }
 4051 
 4052     *ptr = '\0';
 4053     DEBUG_puts(line);
 4054   }
 4055 }
 4056 #endif /* DEBUG */
 4057 
 4058 
 4059 /*
 4060  * 'http_read()' - Read a buffer from a HTTP connection.
 4061  *
 4062  * This function does the low-level read from the socket, retrying and timing
 4063  * out as needed.
 4064  */
 4065 
 4066 static ssize_t              /* O - Number of bytes read or -1 on error */
 4067 http_read(http_t *http,         /* I - HTTP connection */
 4068           char   *buffer,       /* I - Buffer */
 4069           size_t length)        /* I - Maximum bytes to read */
 4070 {
 4071   ssize_t   bytes;          /* Bytes read */
 4072 
 4073 
 4074   DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 4075 
 4076   if (!http->blocking || http->timeout_value > 0.0)
 4077   {
 4078     while (!httpWait(http, http->wait_value))
 4079     {
 4080       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 4081     continue;
 4082 
 4083       DEBUG_puts("2http_read: Timeout.");
 4084       return (0);
 4085     }
 4086   }
 4087 
 4088   DEBUG_printf(("2http_read: Reading %d bytes into buffer.", (int)length));
 4089 
 4090   do
 4091   {
 4092 #ifdef HAVE_SSL
 4093     if (http->tls)
 4094       bytes = _httpTLSRead(http, buffer, (int)length);
 4095     else
 4096 #endif /* HAVE_SSL */
 4097     bytes = recv(http->fd, buffer, length, 0);
 4098 
 4099     if (bytes < 0)
 4100     {
 4101 #ifdef _WIN32
 4102       if (WSAGetLastError() != WSAEINTR)
 4103       {
 4104     http->error = WSAGetLastError();
 4105     return (-1);
 4106       }
 4107       else if (WSAGetLastError() == WSAEWOULDBLOCK)
 4108       {
 4109     if (!http->timeout_cb ||
 4110         !(*http->timeout_cb)(http, http->timeout_data))
 4111     {
 4112       http->error = WSAEWOULDBLOCK;
 4113       return (-1);
 4114     }
 4115       }
 4116 #else
 4117       DEBUG_printf(("2http_read: %s", strerror(errno)));
 4118 
 4119       if (errno == EWOULDBLOCK || errno == EAGAIN)
 4120       {
 4121     if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
 4122     {
 4123       http->error = errno;
 4124       return (-1);
 4125     }
 4126     else if (!http->timeout_cb && errno != EAGAIN)
 4127     {
 4128       http->error = errno;
 4129       return (-1);
 4130     }
 4131       }
 4132       else if (errno != EINTR)
 4133       {
 4134     http->error = errno;
 4135     return (-1);
 4136       }
 4137 #endif /* _WIN32 */
 4138     }
 4139   }
 4140   while (bytes < 0);
 4141 
 4142   DEBUG_printf(("2http_read: Read " CUPS_LLFMT " bytes into buffer.",
 4143         CUPS_LLCAST bytes));
 4144 #ifdef DEBUG
 4145   if (bytes > 0)
 4146     http_debug_hex("http_read", buffer, (int)bytes);
 4147 #endif /* DEBUG */
 4148 
 4149   if (bytes < 0)
 4150   {
 4151 #ifdef _WIN32
 4152     if (WSAGetLastError() == WSAEINTR)
 4153       bytes = 0;
 4154     else
 4155       http->error = WSAGetLastError();
 4156 #else
 4157     if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
 4158       bytes = 0;
 4159     else
 4160       http->error = errno;
 4161 #endif /* _WIN32 */
 4162   }
 4163   else if (bytes == 0)
 4164   {
 4165     http->error = EPIPE;
 4166     return (0);
 4167   }
 4168 
 4169   return (bytes);
 4170 }
 4171 
 4172 
 4173 /*
 4174  * 'http_read_buffered()' - Do a buffered read from a HTTP connection.
 4175  *
 4176  * This function reads data from the HTTP buffer or from the socket, as needed.
 4177  */
 4178 
 4179 static ssize_t              /* O - Number of bytes read or -1 on error */
 4180 http_read_buffered(http_t *http,    /* I - HTTP connection */
 4181                    char   *buffer,  /* I - Buffer */
 4182                    size_t length)   /* I - Maximum bytes to read */
 4183 {
 4184   ssize_t   bytes;          /* Bytes read */
 4185 
 4186 
 4187   DEBUG_printf(("http_read_buffered(http=%p, buffer=%p, length=" CUPS_LLFMT ") used=%d", (void *)http, (void *)buffer, CUPS_LLCAST length, http->used));
 4188 
 4189   if (http->used > 0)
 4190   {
 4191     if (length > (size_t)http->used)
 4192       bytes = (ssize_t)http->used;
 4193     else
 4194       bytes = (ssize_t)length;
 4195 
 4196     DEBUG_printf(("2http_read: Grabbing %d bytes from input buffer.",
 4197                   (int)bytes));
 4198 
 4199     memcpy(buffer, http->buffer, (size_t)bytes);
 4200     http->used -= (int)bytes;
 4201 
 4202     if (http->used > 0)
 4203       memmove(http->buffer, http->buffer + bytes, (size_t)http->used);
 4204   }
 4205   else
 4206     bytes = http_read(http, buffer, length);
 4207 
 4208   return (bytes);
 4209 }
 4210 
 4211 
 4212 /*
 4213  * 'http_read_chunk()' - Read a chunk from a HTTP connection.
 4214  *
 4215  * This function reads and validates the chunk length, then does a buffered read
 4216  * returning the number of bytes placed in the buffer.
 4217  */
 4218 
 4219 static ssize_t              /* O - Number of bytes read or -1 on error */
 4220 http_read_chunk(http_t *http,       /* I - HTTP connection */
 4221         char   *buffer,     /* I - Buffer */
 4222         size_t length)      /* I - Maximum bytes to read */
 4223 {
 4224   DEBUG_printf(("http_read_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 4225 
 4226   if (http->data_remaining <= 0)
 4227   {
 4228     char    len[32];        /* Length string */
 4229 
 4230     if (!httpGets(len, sizeof(len), http))
 4231     {
 4232       DEBUG_puts("1http_read_chunk: Could not get chunk length.");
 4233       return (0);
 4234     }
 4235 
 4236     if (!len[0])
 4237     {
 4238       DEBUG_puts("1http_read_chunk: Blank chunk length, trying again...");
 4239       if (!httpGets(len, sizeof(len), http))
 4240       {
 4241     DEBUG_puts("1http_read_chunk: Could not get chunk length.");
 4242     return (0);
 4243       }
 4244     }
 4245 
 4246     http->data_remaining = strtoll(len, NULL, 16);
 4247 
 4248     if (http->data_remaining < 0)
 4249     {
 4250       DEBUG_printf(("1http_read_chunk: Negative chunk length \"%s\" ("
 4251                     CUPS_LLFMT ")", len, CUPS_LLCAST http->data_remaining));
 4252       return (0);
 4253     }
 4254 
 4255     DEBUG_printf(("2http_read_chunk: Got chunk length \"%s\" (" CUPS_LLFMT ")",
 4256                   len, CUPS_LLCAST http->data_remaining));
 4257 
 4258     if (http->data_remaining == 0)
 4259     {
 4260      /*
 4261       * 0-length chunk, grab trailing blank line...
 4262       */
 4263 
 4264       httpGets(len, sizeof(len), http);
 4265     }
 4266   }
 4267 
 4268   DEBUG_printf(("2http_read_chunk: data_remaining=" CUPS_LLFMT,
 4269                 CUPS_LLCAST http->data_remaining));
 4270 
 4271   if (http->data_remaining <= 0)
 4272     return (0);
 4273   else if (length > (size_t)http->data_remaining)
 4274     length = (size_t)http->data_remaining;
 4275 
 4276   return (http_read_buffered(http, buffer, length));
 4277 }
 4278 
 4279 
 4280 /*
 4281  * 'http_send()' - Send a request with all fields and the trailing blank line.
 4282  */
 4283 
 4284 static int              /* O - 0 on success, non-zero on error */
 4285 http_send(http_t       *http,       /* I - HTTP connection */
 4286           http_state_t request,     /* I - Request code */
 4287       const char   *uri)        /* I - URI */
 4288 {
 4289   int       i;          /* Looping var */
 4290   char      buf[1024];      /* Encoded URI buffer */
 4291   const char    *value;         /* Field value */
 4292   static const char * const codes[] =   /* Request code strings */
 4293         {
 4294           NULL,
 4295           "OPTIONS",
 4296           "GET",
 4297           NULL,
 4298           "HEAD",
 4299           "POST",
 4300           NULL,
 4301           NULL,
 4302           "PUT",
 4303           NULL,
 4304           "DELETE",
 4305           "TRACE",
 4306           "CLOSE",
 4307           NULL,
 4308           NULL
 4309         };
 4310 
 4311 
 4312   DEBUG_printf(("4http_send(http=%p, request=HTTP_%s, uri=\"%s\")", (void *)http, codes[request], uri));
 4313 
 4314   if (http == NULL || uri == NULL)
 4315     return (-1);
 4316 
 4317  /*
 4318   * Set the User-Agent field if it isn't already...
 4319   */
 4320 
 4321   if (!http->fields[HTTP_FIELD_USER_AGENT])
 4322   {
 4323     if (http->default_fields[HTTP_FIELD_USER_AGENT])
 4324       httpSetField(http, HTTP_FIELD_USER_AGENT, http->default_fields[HTTP_FIELD_USER_AGENT]);
 4325     else
 4326       httpSetField(http, HTTP_FIELD_USER_AGENT, cupsUserAgent());
 4327   }
 4328 
 4329  /*
 4330   * Set the Accept-Encoding field if it isn't already...
 4331   */
 4332 
 4333   if (!http->fields[HTTP_FIELD_ACCEPT_ENCODING] && http->default_fields[HTTP_FIELD_ACCEPT_ENCODING])
 4334     httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, http->default_fields[HTTP_FIELD_ACCEPT_ENCODING]);
 4335 
 4336  /*
 4337   * Encode the URI as needed...
 4338   */
 4339 
 4340   _httpEncodeURI(buf, uri, sizeof(buf));
 4341 
 4342  /*
 4343   * See if we had an error the last time around; if so, reconnect...
 4344   */
 4345 
 4346   if (http->fd < 0 || http->status == HTTP_STATUS_ERROR ||
 4347       http->status >= HTTP_STATUS_BAD_REQUEST)
 4348   {
 4349     DEBUG_printf(("5http_send: Reconnecting, fd=%d, status=%d, tls_upgrade=%d",
 4350                   http->fd, http->status, http->tls_upgrade));
 4351 
 4352     if (httpReconnect2(http, 30000, NULL))
 4353       return (-1);
 4354   }
 4355 
 4356  /*
 4357   * Flush any written data that is pending...
 4358   */
 4359 
 4360   if (http->wused)
 4361   {
 4362     if (httpFlushWrite(http) < 0)
 4363       if (httpReconnect2(http, 30000, NULL))
 4364         return (-1);
 4365   }
 4366 
 4367  /*
 4368   * Send the request header...
 4369   */
 4370 
 4371   http->state         = request;
 4372   http->data_encoding = HTTP_ENCODING_FIELDS;
 4373 
 4374   if (request == HTTP_STATE_POST || request == HTTP_STATE_PUT)
 4375     http->state ++;
 4376 
 4377   http->status = HTTP_STATUS_CONTINUE;
 4378 
 4379 #ifdef HAVE_SSL
 4380   if (http->encryption == HTTP_ENCRYPTION_REQUIRED && !http->tls)
 4381   {
 4382     httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
 4383     httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
 4384   }
 4385 #endif /* HAVE_SSL */
 4386 
 4387   if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
 4388   {
 4389     http->status = HTTP_STATUS_ERROR;
 4390     return (-1);
 4391   }
 4392 
 4393   for (i = 0; i < HTTP_FIELD_MAX; i ++)
 4394     if ((value = httpGetField(http, i)) != NULL && *value)
 4395     {
 4396       DEBUG_printf(("5http_send: %s: %s", http_fields[i], value));
 4397 
 4398       if (i == HTTP_FIELD_HOST)
 4399       {
 4400     if (httpPrintf(http, "Host: %s:%d\r\n", value,
 4401                    httpAddrPort(http->hostaddr)) < 1)
 4402     {
 4403       http->status = HTTP_STATUS_ERROR;
 4404       return (-1);
 4405     }
 4406       }
 4407       else if (httpPrintf(http, "%s: %s\r\n", http_fields[i], value) < 1)
 4408       {
 4409     http->status = HTTP_STATUS_ERROR;
 4410     return (-1);
 4411       }
 4412     }
 4413 
 4414   if (http->cookie)
 4415     if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1)
 4416     {
 4417       http->status = HTTP_STATUS_ERROR;
 4418       return (-1);
 4419     }
 4420 
 4421   DEBUG_printf(("5http_send: expect=%d, mode=%d, state=%d", http->expect,
 4422                 http->mode, http->state));
 4423 
 4424   if (http->expect == HTTP_STATUS_CONTINUE && http->mode == _HTTP_MODE_CLIENT &&
 4425       (http->state == HTTP_STATE_POST_RECV ||
 4426        http->state == HTTP_STATE_PUT_RECV))
 4427     if (httpPrintf(http, "Expect: 100-continue\r\n") < 1)
 4428     {
 4429       http->status = HTTP_STATUS_ERROR;
 4430       return (-1);
 4431     }
 4432 
 4433   if (httpPrintf(http, "\r\n") < 1)
 4434   {
 4435     http->status = HTTP_STATUS_ERROR;
 4436     return (-1);
 4437   }
 4438 
 4439   if (httpFlushWrite(http) < 0)
 4440     return (-1);
 4441 
 4442   http_set_length(http);
 4443   httpClearFields(http);
 4444 
 4445  /*
 4446   * The Kerberos and AuthRef authentication strings can only be used once...
 4447   */
 4448 
 4449   if (http->fields[HTTP_FIELD_AUTHORIZATION] && http->authstring &&
 4450       (!strncmp(http->authstring, "Negotiate", 9) ||
 4451        !strncmp(http->authstring, "AuthRef", 7)))
 4452   {
 4453     http->_authstring[0] = '\0';
 4454 
 4455     if (http->authstring != http->_authstring)
 4456       free(http->authstring);
 4457 
 4458     http->authstring = http->_authstring;
 4459   }
 4460 
 4461   return (0);
 4462 }
 4463 
 4464 
 4465 /*
 4466  * 'http_set_length()' - Set the data_encoding and data_remaining values.
 4467  */
 4468 
 4469 static off_t                /* O - Remainder or -1 on error */
 4470 http_set_length(http_t *http)       /* I - Connection */
 4471 {
 4472   off_t remaining;          /* Remainder */
 4473 
 4474 
 4475   DEBUG_printf(("http_set_length(http=%p) mode=%d state=%s", (void *)http, http->mode, httpStateString(http->state)));
 4476 
 4477   if ((remaining = httpGetLength2(http)) >= 0)
 4478   {
 4479     if (http->mode == _HTTP_MODE_SERVER &&
 4480     http->state != HTTP_STATE_GET_SEND &&
 4481     http->state != HTTP_STATE_PUT &&
 4482     http->state != HTTP_STATE_POST &&
 4483     http->state != HTTP_STATE_POST_SEND)
 4484     {
 4485       DEBUG_puts("1http_set_length: Not setting data_encoding/remaining.");
 4486       return (remaining);
 4487     }
 4488 
 4489     if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_TRANSFER_ENCODING), "chunked"))
 4490     {
 4491       DEBUG_puts("1http_set_length: Setting data_encoding to "
 4492                  "HTTP_ENCODING_CHUNKED.");
 4493       http->data_encoding = HTTP_ENCODING_CHUNKED;
 4494     }
 4495     else
 4496     {
 4497       DEBUG_puts("1http_set_length: Setting data_encoding to "
 4498                  "HTTP_ENCODING_LENGTH.");
 4499       http->data_encoding = HTTP_ENCODING_LENGTH;
 4500     }
 4501 
 4502     DEBUG_printf(("1http_set_length: Setting data_remaining to " CUPS_LLFMT ".",
 4503                   CUPS_LLCAST remaining));
 4504     http->data_remaining = remaining;
 4505 
 4506     if (remaining <= INT_MAX)
 4507       http->_data_remaining = (int)remaining;
 4508     else
 4509       http->_data_remaining = INT_MAX;
 4510   }
 4511 
 4512   return (remaining);
 4513 }
 4514 
 4515 /*
 4516  * 'http_set_timeout()' - Set the socket timeout values.
 4517  */
 4518 
 4519 static void
 4520 http_set_timeout(int    fd,     /* I - File descriptor */
 4521                  double timeout)    /* I - Timeout in seconds */
 4522 {
 4523 #ifdef _WIN32
 4524   DWORD tv = (DWORD)(timeout * 1000);
 4525                       /* Timeout in milliseconds */
 4526 
 4527   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
 4528   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
 4529 
 4530 #else
 4531   struct timeval tv;            /* Timeout in secs and usecs */
 4532 
 4533   tv.tv_sec  = (int)timeout;
 4534   tv.tv_usec = (int)(1000000 * fmod(timeout, 1.0));
 4535 
 4536   setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv));
 4537   setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv));
 4538 #endif /* _WIN32 */
 4539 }
 4540 
 4541 
 4542 /*
 4543  * 'http_set_wait()' - Set the default wait value for reads.
 4544  */
 4545 
 4546 static void
 4547 http_set_wait(http_t *http)     /* I - HTTP connection */
 4548 {
 4549   if (http->blocking)
 4550   {
 4551     http->wait_value = (int)(http->timeout_value * 1000);
 4552 
 4553     if (http->wait_value <= 0)
 4554       http->wait_value = 60000;
 4555   }
 4556   else
 4557     http->wait_value = 10000;
 4558 }
 4559 
 4560 
 4561 #ifdef HAVE_SSL
 4562 /*
 4563  * 'http_tls_upgrade()' - Force upgrade to TLS encryption.
 4564  */
 4565 
 4566 static int              /* O - Status of connection */
 4567 http_tls_upgrade(http_t *http)      /* I - HTTP connection */
 4568 {
 4569   int       ret;            /* Return value */
 4570   http_t    myhttp;         /* Local copy of HTTP data */
 4571 
 4572 
 4573   DEBUG_printf(("7http_tls_upgrade(%p)", (void *)http));
 4574 
 4575  /*
 4576   * Flush the connection to make sure any previous "Upgrade" message
 4577   * has been read.
 4578   */
 4579 
 4580   httpFlush(http);
 4581 
 4582  /*
 4583   * Copy the HTTP data to a local variable so we can do the OPTIONS
 4584   * request without interfering with the existing request data...
 4585   */
 4586 
 4587   memcpy(&myhttp, http, sizeof(myhttp));
 4588 
 4589  /*
 4590   * Send an OPTIONS request to the server, requiring SSL or TLS
 4591   * encryption on the link...
 4592   */
 4593 
 4594   http->tls_upgrade = 1;
 4595   memset(http->fields, 0, sizeof(http->fields));
 4596   http->expect = (http_status_t)0;
 4597 
 4598   if (http->hostname[0] == '/')
 4599     httpSetField(http, HTTP_FIELD_HOST, "localhost");
 4600   else
 4601     httpSetField(http, HTTP_FIELD_HOST, http->hostname);
 4602 
 4603   httpSetField(http, HTTP_FIELD_CONNECTION, "upgrade");
 4604   httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.2,TLS/1.1,TLS/1.0");
 4605 
 4606   if ((ret = httpOptions(http, "*")) == 0)
 4607   {
 4608    /*
 4609     * Wait for the secure connection...
 4610     */
 4611 
 4612     while (httpUpdate(http) == HTTP_STATUS_CONTINUE);
 4613   }
 4614 
 4615  /*
 4616   * Restore the HTTP request data...
 4617   */
 4618 
 4619   memcpy(http->_fields, myhttp._fields, sizeof(http->_fields));
 4620   memcpy(http->fields, myhttp.fields, sizeof(http->fields));
 4621 
 4622   http->data_encoding   = myhttp.data_encoding;
 4623   http->data_remaining  = myhttp.data_remaining;
 4624   http->_data_remaining = myhttp._data_remaining;
 4625   http->expect          = myhttp.expect;
 4626   http->digest_tries    = myhttp.digest_tries;
 4627   http->tls_upgrade     = 0;
 4628 
 4629  /*
 4630   * See if we actually went secure...
 4631   */
 4632 
 4633   if (!http->tls)
 4634   {
 4635    /*
 4636     * Server does not support HTTP upgrade...
 4637     */
 4638 
 4639     DEBUG_puts("8http_tls_upgrade: Server does not support HTTP upgrade!");
 4640 
 4641     _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, _("Encryption is not supported."), 1);
 4642     httpAddrClose(NULL, http->fd);
 4643 
 4644     http->fd = -1;
 4645 
 4646     return (-1);
 4647   }
 4648   else
 4649     return (ret);
 4650 }
 4651 #endif /* HAVE_SSL */
 4652 
 4653 
 4654 /*
 4655  * 'http_write()' - Write a buffer to a HTTP connection.
 4656  */
 4657 
 4658 static ssize_t              /* O - Number of bytes written */
 4659 http_write(http_t     *http,        /* I - HTTP connection */
 4660            const char *buffer,      /* I - Buffer for data */
 4661        size_t     length)       /* I - Number of bytes to write */
 4662 {
 4663   ssize_t   tbytes,         /* Total bytes sent */
 4664         bytes;          /* Bytes sent */
 4665 
 4666 
 4667   DEBUG_printf(("2http_write(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 4668   http->error = 0;
 4669   tbytes      = 0;
 4670 
 4671   while (length > 0)
 4672   {
 4673     DEBUG_printf(("3http_write: About to write %d bytes.", (int)length));
 4674 
 4675     if (http->timeout_value > 0.0)
 4676     {
 4677 #ifdef HAVE_POLL
 4678       struct pollfd pfd;        /* Polled file descriptor */
 4679 #else
 4680       fd_set        output_set; /* Output ready for write? */
 4681       struct timeval    timeout;    /* Timeout value */
 4682 #endif /* HAVE_POLL */
 4683       int       nfds;       /* Result from select()/poll() */
 4684 
 4685       do
 4686       {
 4687 #ifdef HAVE_POLL
 4688     pfd.fd     = http->fd;
 4689     pfd.events = POLLOUT;
 4690 
 4691     while ((nfds = poll(&pfd, 1, http->wait_value)) < 0 &&
 4692            (errno == EINTR || errno == EAGAIN))
 4693       /* do nothing */;
 4694 
 4695 #else
 4696     do
 4697     {
 4698       FD_ZERO(&output_set);
 4699       FD_SET(http->fd, &output_set);
 4700 
 4701       timeout.tv_sec  = http->wait_value / 1000;
 4702       timeout.tv_usec = 1000 * (http->wait_value % 1000);
 4703 
 4704       nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout);
 4705     }
 4706 #  ifdef _WIN32
 4707     while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
 4708                 WSAGetLastError() == WSAEWOULDBLOCK));
 4709 #  else
 4710     while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
 4711 #  endif /* _WIN32 */
 4712 #endif /* HAVE_POLL */
 4713 
 4714         if (nfds < 0)
 4715     {
 4716       http->error = errno;
 4717       return (-1);
 4718     }
 4719     else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data)))
 4720     {
 4721 #ifdef _WIN32
 4722       http->error = WSAEWOULDBLOCK;
 4723 #else
 4724       http->error = EWOULDBLOCK;
 4725 #endif /* _WIN32 */
 4726       return (-1);
 4727     }
 4728       }
 4729       while (nfds <= 0);
 4730     }
 4731 
 4732 #ifdef HAVE_SSL
 4733     if (http->tls)
 4734       bytes = _httpTLSWrite(http, buffer, (int)length);
 4735     else
 4736 #endif /* HAVE_SSL */
 4737     bytes = send(http->fd, buffer, length, 0);
 4738 
 4739     DEBUG_printf(("3http_write: Write of " CUPS_LLFMT " bytes returned "
 4740                   CUPS_LLFMT ".", CUPS_LLCAST length, CUPS_LLCAST bytes));
 4741 
 4742     if (bytes < 0)
 4743     {
 4744 #ifdef _WIN32
 4745       if (WSAGetLastError() == WSAEINTR)
 4746         continue;
 4747       else if (WSAGetLastError() == WSAEWOULDBLOCK)
 4748       {
 4749         if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 4750           continue;
 4751 
 4752         http->error = WSAGetLastError();
 4753       }
 4754       else if (WSAGetLastError() != http->error &&
 4755                WSAGetLastError() != WSAECONNRESET)
 4756       {
 4757         http->error = WSAGetLastError();
 4758     continue;
 4759       }
 4760 
 4761 #else
 4762       if (errno == EINTR)
 4763         continue;
 4764       else if (errno == EWOULDBLOCK || errno == EAGAIN)
 4765       {
 4766     if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
 4767           continue;
 4768         else if (!http->timeout_cb && errno == EAGAIN)
 4769       continue;
 4770 
 4771         http->error = errno;
 4772       }
 4773       else if (errno != http->error && errno != ECONNRESET)
 4774       {
 4775         http->error = errno;
 4776     continue;
 4777       }
 4778 #endif /* _WIN32 */
 4779 
 4780       DEBUG_printf(("3http_write: error writing data (%s).",
 4781                     strerror(http->error)));
 4782 
 4783       return (-1);
 4784     }
 4785 
 4786     buffer += bytes;
 4787     tbytes += bytes;
 4788     length -= (size_t)bytes;
 4789   }
 4790 
 4791 #ifdef DEBUG
 4792   http_debug_hex("http_write", buffer - tbytes, (int)tbytes);
 4793 #endif /* DEBUG */
 4794 
 4795   DEBUG_printf(("3http_write: Returning " CUPS_LLFMT ".", CUPS_LLCAST tbytes));
 4796 
 4797   return (tbytes);
 4798 }
 4799 
 4800 
 4801 /*
 4802  * 'http_write_chunk()' - Write a chunked buffer.
 4803  */
 4804 
 4805 static ssize_t              /* O - Number bytes written */
 4806 http_write_chunk(http_t     *http,  /* I - HTTP connection */
 4807                  const char *buffer,    /* I - Buffer to write */
 4808          size_t        length)  /* I - Length of buffer */
 4809 {
 4810   char      header[16];     /* Chunk header */
 4811   ssize_t   bytes;          /* Bytes written */
 4812 
 4813 
 4814   DEBUG_printf(("7http_write_chunk(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
 4815 
 4816  /*
 4817   * Write the chunk header, data, and trailer.
 4818   */
 4819 
 4820   snprintf(header, sizeof(header), "%x\r\n", (unsigned)length);
 4821   if (http_write(http, header, strlen(header)) < 0)
 4822   {
 4823     DEBUG_puts("8http_write_chunk: http_write of length failed.");
 4824     return (-1);
 4825   }
 4826 
 4827   if ((bytes = http_write(http, buffer, length)) < 0)
 4828   {
 4829     DEBUG_puts("8http_write_chunk: http_write of buffer failed.");
 4830     return (-1);
 4831   }
 4832 
 4833   if (http_write(http, "\r\n", 2) < 0)
 4834   {
 4835     DEBUG_puts("8http_write_chunk: http_write of CR LF failed.");
 4836     return (-1);
 4837   }
 4838 
 4839   return (bytes);
 4840 }