+/*
+ * 'httpSetAuthString()' - Set the current authorization string.
+ *
+ * This function just stores a copy of the current authorization string in
+ * the HTTP connection object. You must still call httpSetField() to set
+ * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
+ * httpHead(), httpOptions(), httpPost, or httpPut().
+ *
+ * @since CUPS 1.3/macOS 10.5@
+ */
+
+void
+httpSetAuthString(http_t *http, /* I - HTTP connection */
+ const char *scheme, /* I - Auth scheme (NULL to clear it) */
+ const char *data) /* I - Auth data (NULL for none) */
+{
+ /*
+ * Range check input...
+ */
+
+ if (!http)
+ return;
+
+ if (http->authstring && http->authstring != http->_authstring)
+ free(http->authstring);
+
+ http->authstring = http->_authstring;
+
+ if (scheme)
+ {
+ /*
+ * Set the current authorization string...
+ */
+
+ size_t len = strlen(scheme) + (data ? strlen(data) + 1 : 0) + 1;
+ char *temp;
+
+ if (len > sizeof(http->_authstring))
+ {
+ if ((temp = malloc(len)) == NULL)
+ len = sizeof(http->_authstring);
+ else
+ http->authstring = temp;
+ }
+
+ if (data)
+ snprintf(http->authstring, len, "%s %s", scheme, data);
+ else
+ strlcpy(http->authstring, scheme, len);
+ }
+ else
+ {
+ /*
+ * Clear the current authorization string...
+ */
+
+ http->_authstring[0] = '\0';
+ }
+}
+
+
+/*
+ * 'httpSetCredentials()' - Set the credentials associated with an encrypted
+ * connection.
+ *
+ * @since CUPS 1.5/macOS 10.7@
+ */
+
+int /* O - Status of call (0 = success) */
+httpSetCredentials(http_t *http, /* I - HTTP connection */
+ cups_array_t *credentials) /* I - Array of credentials */
+{
+ if (!http || cupsArrayCount(credentials) < 1)
+ return (-1);
+
+#ifdef HAVE_SSL
+ _httpFreeCredentials(http->tls_credentials);
+
+ http->tls_credentials = _httpCreateCredentials(credentials);
+#endif /* HAVE_SSL */
+
+ return (http->tls_credentials ? 0 : -1);
+}
+
+
+/*
+ * 'httpSetCookie()' - Set the cookie value(s).
+ *
+ * @since CUPS 1.1.19/macOS 10.3@
+ */
+
+void
+httpSetCookie(http_t *http, /* I - Connection */
+ const char *cookie) /* I - Cookie string */
+{
+ if (!http)
+ return;
+
+ if (http->cookie)
+ free(http->cookie);
+
+ if (cookie)
+ http->cookie = strdup(cookie);
+ else
+ http->cookie = NULL;
+}
+
+
+/*
+ * 'httpSetDefaultField()' - Set the default value of an HTTP header.
+ *
+ * Currently only @code HTTP_FIELD_ACCEPT_ENCODING@, @code HTTP_FIELD_SERVER@,
+ * and @code HTTP_FIELD_USER_AGENT@ can be set.
+ *
+ * @since CUPS 1.7/macOS 10.9@
+ */
+
+void
+httpSetDefaultField(http_t *http, /* I - HTTP connection */
+ http_field_t field, /* I - Field index */
+ const char *value)/* I - Value */
+{
+ DEBUG_printf(("httpSetDefaultField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
+
+ if (!http)
+ return;
+
+ switch (field)
+ {
+ case HTTP_FIELD_ACCEPT_ENCODING :
+ if (http->default_accept_encoding)
+ _cupsStrFree(http->default_accept_encoding);
+
+ http->default_accept_encoding = value ? _cupsStrAlloc(value) : NULL;
+ break;
+
+ case HTTP_FIELD_SERVER :
+ if (http->default_server)
+ _cupsStrFree(http->default_server);
+
+ http->default_server = value ? _cupsStrAlloc(value) : NULL;
+ break;
+
+ case HTTP_FIELD_USER_AGENT :
+ if (http->default_user_agent)
+ _cupsStrFree(http->default_user_agent);
+
+ http->default_user_agent = value ? _cupsStrAlloc(value) : NULL;
+ break;
+
+ default :
+ DEBUG_puts("1httpSetDefaultField: Ignored.");
+ break;
+ }
+}
+
+
+/*
+ * 'httpSetExpect()' - Set the Expect: header in a request.
+ *
+ * Currently only @code HTTP_STATUS_CONTINUE@ is supported for the "expect"
+ * argument.
+ *
+ * @since CUPS 1.2/macOS 10.5@
+ */
+
+void
+httpSetExpect(http_t *http, /* I - HTTP connection */
+ http_status_t expect) /* I - HTTP status to expect
+ (@code HTTP_STATUS_CONTINUE@) */
+{
+ DEBUG_printf(("httpSetExpect(http=%p, expect=%d)", (void *)http, expect));
+
+ if (http)
+ http->expect = expect;
+}
+
+
+/*
+ * 'httpSetField()' - Set the value of an HTTP header.
+ */
+
+void
+httpSetField(http_t *http, /* I - HTTP connection */
+ http_field_t field, /* I - Field index */
+ const char *value) /* I - Value */
+{
+ DEBUG_printf(("httpSetField(http=%p, field=%d(%s), value=\"%s\")", (void *)http, field, http_fields[field], value));
+
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field >= HTTP_FIELD_MAX ||
+ value == NULL)
+ return;
+
+ switch (field)
+ {
+ case HTTP_FIELD_ACCEPT_ENCODING :
+ if (http->accept_encoding)
+ _cupsStrFree(http->accept_encoding);
+
+ http->accept_encoding = _cupsStrAlloc(value);
+ break;
+
+ case HTTP_FIELD_ALLOW :
+ if (http->allow)
+ _cupsStrFree(http->allow);
+
+ http->allow = _cupsStrAlloc(value);
+ break;
+
+ case HTTP_FIELD_SERVER :
+ if (http->server)
+ _cupsStrFree(http->server);
+
+ http->server = _cupsStrAlloc(value);
+ break;
+
+ case HTTP_FIELD_WWW_AUTHENTICATE :
+ /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */
+ if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] &&
+ _cups_strncasecmp(value, "Basic ", 6) &&
+ _cups_strncasecmp(value, "Digest ", 7) &&
+ _cups_strncasecmp(value, "Negotiate ", 10))
+ {
+ DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value));
+ return;
+ }
+
+ /* Fall through to copy */
+
+ default :
+ strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
+ break;
+ }
+
+ if (field == HTTP_FIELD_AUTHORIZATION)
+ {
+ /*
+ * Special case for Authorization: as its contents can be
+ * longer than HTTP_MAX_VALUE
+ */
+
+ if (http->field_authorization)
+ free(http->field_authorization);
+
+ http->field_authorization = strdup(value);
+ }
+ else if (field == HTTP_FIELD_HOST)
+ {
+ /*
+ * Special-case for Host: as we don't want a trailing "." on the hostname and
+ * need to bracket IPv6 numeric addresses.
+ */
+
+ char *ptr = strchr(value, ':');
+
+ if (value[0] != '[' && ptr && strchr(ptr + 1, ':'))
+ {
+ /*
+ * Bracket IPv6 numeric addresses...
+ *
+ * This is slightly inefficient (basically copying twice), but is an edge
+ * case and not worth optimizing...
+ */
+
+ snprintf(http->fields[HTTP_FIELD_HOST],
+ sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value);
+ }
+ else
+ {
+ /*
+ * Check for a trailing dot on the hostname...
+ */
+
+ ptr = http->fields[HTTP_FIELD_HOST];
+
+ if (*ptr)
+ {
+ ptr += strlen(ptr) - 1;
+
+ if (*ptr == '.')
+ *ptr = '\0';
+ }
+ }
+ }
+#ifdef HAVE_LIBZ
+ else if (field == HTTP_FIELD_CONTENT_ENCODING &&
+ http->data_encoding != HTTP_ENCODING_FIELDS)
+ {
+ DEBUG_puts("1httpSetField: Calling http_content_coding_start.");
+ http_content_coding_start(http, value);
+ }
+#endif /* HAVE_LIBZ */
+}
+
+
+/*
+ * 'httpSetKeepAlive()' - Set the current Keep-Alive state of a connection.
+ *
+ * @since CUPS 2.0/OS 10.10@
+ */
+
+void
+httpSetKeepAlive(
+ http_t *http, /* I - HTTP connection */
+ http_keepalive_t keep_alive) /* I - New Keep-Alive value */
+{
+ if (http)
+ http->keep_alive = keep_alive;
+}
+
+
+/*
+ * 'httpSetLength()' - Set the content-length and content-encoding.
+ *
+ * @since CUPS 1.2/macOS 10.5@
+ */
+
+void
+httpSetLength(http_t *http, /* I - HTTP connection */
+ size_t length) /* I - Length (0 for chunked) */
+{
+ DEBUG_printf(("httpSetLength(http=%p, length=" CUPS_LLFMT ")", (void *)http, CUPS_LLCAST length));
+
+ if (!http)
+ return;
+
+ if (!length)
+ {
+ strlcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked",
+ HTTP_MAX_VALUE);
+ http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0';
+ }
+ else
+ {
+ http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0';
+ snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE,
+ CUPS_LLFMT, CUPS_LLCAST length);
+ }
+}
+
+
+/*
+ * 'httpSetTimeout()' - Set read/write timeouts and an optional callback.
+ *
+ * The optional timeout callback receives both the HTTP connection and a user
+ * data pointer and must return 1 to continue or 0 to error (time) out.
+ *
+ * @since CUPS 1.5/macOS 10.7@
+ */
+
+void
+httpSetTimeout(
+ http_t *http, /* I - HTTP connection */
+ double timeout, /* I - Number of seconds for timeout,
+ must be greater than 0 */
+ http_timeout_cb_t cb, /* I - Callback function or NULL */
+ void *user_data) /* I - User data pointer */
+{
+ if (!http || timeout <= 0.0)
+ return;
+
+ http->timeout_cb = cb;
+ http->timeout_data = user_data;
+ http->timeout_value = timeout;
+
+ if (http->fd >= 0)
+ http_set_timeout(http->fd, timeout);
+
+ http_set_wait(http);
+}
+
+
+/*
+ * 'httpShutdown()' - Shutdown one side of an HTTP connection.
+ *
+ * @since CUPS 2.0/OS 10.10@
+ */
+
+void
+httpShutdown(http_t *http) /* I - HTTP connection */
+{
+ if (!http || http->fd < 0)
+ return;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ _httpTLSStop(http);
+#endif /* HAVE_SSL */
+
+#ifdef WIN32
+ shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */
+#else
+ shutdown(http->fd, SHUT_RD);
+#endif /* WIN32 */
+}
+
+
+/*
+ * 'httpTrace()' - Send an TRACE request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpTrace(http_t *http, /* I - HTTP connection */
+ const char *uri) /* I - URI for trace */
+{
+ return (http_send(http, HTTP_STATE_TRACE, uri));
+}
+
+
+/*
+ * '_httpUpdate()' - Update the current HTTP status for incoming data.
+ *
+ * Note: Unlike httpUpdate(), this function does not flush pending write data
+ * and only retrieves a single status line from the HTTP connection.
+ */
+
+int /* O - 1 to continue, 0 to stop */
+_httpUpdate(http_t *http, /* I - HTTP connection */
+ http_status_t *status) /* O - Current HTTP status */
+{
+ char line[32768], /* Line from connection... */
+ *value; /* Pointer to value on line */
+ http_field_t field; /* Field index */
+ int major, minor; /* HTTP version numbers */
+
+
+ DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state)));
+
+ /*
+ * Grab a single line from the connection...
+ */
+
+ if (!httpGets(line, sizeof(line), http))
+ {
+ *status = HTTP_STATUS_ERROR;
+ return (0);
+ }
+
+ DEBUG_printf(("2_httpUpdate: Got \"%s\"", line));
+
+ if (line[0] == '\0')
+ {
+ /*
+ * Blank line means the start of the data section (if any). Return
+ * the result code, too...
+ *
+ * If we get status 100 (HTTP_STATUS_CONTINUE), then we *don't* change
+ * states. Instead, we just return HTTP_STATUS_CONTINUE to the caller and
+ * keep on tryin'...
+ */
+
+ if (http->status == HTTP_STATUS_CONTINUE)
+ {
+ *status = http->status;
+ return (0);
+ }
+
+ if (http->status < HTTP_STATUS_BAD_REQUEST)
+ http->digest_tries = 0;
+
+#ifdef HAVE_SSL
+ if (http->status == HTTP_STATUS_SWITCHING_PROTOCOLS && !http->tls)
+ {
+ if (_httpTLSStart(http) != 0)
+ {
+ httpAddrClose(NULL, http->fd);
+
+ *status = http->status = HTTP_STATUS_ERROR;
+ return (0);
+ }
+
+ *status = HTTP_STATUS_CONTINUE;
+ return (0);
+ }
+#endif /* HAVE_SSL */
+
+ if (http_set_length(http) < 0)
+ {
+ DEBUG_puts("1_httpUpdate: Bad Content-Length.");
+ http->error = EINVAL;
+ http->status = *status = HTTP_STATUS_ERROR;
+ return (0);
+ }
+
+ switch (http->state)
+ {
+ case HTTP_STATE_GET :
+ case HTTP_STATE_POST :
+ case HTTP_STATE_POST_RECV :
+ case HTTP_STATE_PUT :
+ http->state ++;
+
+ DEBUG_printf(("1_httpUpdate: Set state to %s.",
+ httpStateString(http->state)));
+
+ case HTTP_STATE_POST_SEND :
+ case HTTP_STATE_HEAD :
+ break;
+
+ default :
+ http->state = HTTP_STATE_WAITING;
+
+ DEBUG_puts("1_httpUpdate: Reset state to HTTP_STATE_WAITING.");
+ break;
+ }
+
+#ifdef HAVE_LIBZ
+ DEBUG_puts("1_httpUpdate: Calling http_content_coding_start.");
+ http_content_coding_start(http,
+ httpGetField(http, HTTP_FIELD_CONTENT_ENCODING));
+#endif /* HAVE_LIBZ */
+
+ *status = http->status;
+ return (0);
+ }
+ else if (!strncmp(line, "HTTP/", 5) && http->mode == _HTTP_MODE_CLIENT)
+ {
+ /*
+ * Got the beginning of a response...
+ */
+
+ int intstatus; /* Status value as an integer */
+
+ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &intstatus) != 3)
+ {
+ *status = http->status = HTTP_STATUS_ERROR;
+ return (0);
+ }
+
+ httpClearFields(http);
+
+ http->version = (http_version_t)(major * 100 + minor);
+ *status = http->status = (http_status_t)intstatus;
+ }
+ else if ((value = strchr(line, ':')) != NULL)
+ {
+ /*
+ * Got a value...
+ */
+
+ *value++ = '\0';
+ while (_cups_isspace(*value))
+ value ++;
+
+ DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
+
+ /*
+ * Be tolerants of servers that send unknown attribute fields...
+ */
+
+ if (!_cups_strcasecmp(line, "expect"))
+ {
+ /*
+ * "Expect: 100-continue" or similar...
+ */
+
+ http->expect = (http_status_t)atoi(value);
+ }
+ else if (!_cups_strcasecmp(line, "cookie"))
+ {
+ /*
+ * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
+ */
+
+ httpSetCookie(http, value);
+ }
+ else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN)
+ httpSetField(http, field, value);
+#ifdef DEBUG
+ else
+ DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line));
+#endif /* DEBUG */
+ }
+ else
+ {
+ DEBUG_printf(("1_httpUpdate: Bad response line \"%s\"!", line));
+ http->error = EINVAL;
+ http->status = *status = HTTP_STATUS_ERROR;
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'httpUpdate()' - Update the current HTTP state for incoming data.
+ */
+
+http_status_t /* O - HTTP status */
+httpUpdate(http_t *http) /* I - HTTP connection */
+{
+ http_status_t status; /* Request status */
+
+
+ DEBUG_printf(("httpUpdate(http=%p), state=%s", (void *)http, httpStateString(http->state)));
+
+ /*
+ * Flush pending data, if any...
+ */
+
+ if (http->wused)
+ {
+ DEBUG_puts("2httpUpdate: flushing buffer...");
+
+ if (httpFlushWrite(http) < 0)
+ return (HTTP_STATUS_ERROR);
+ }
+
+ /*
+ * If we haven't issued any commands, then there is nothing to "update"...
+ */
+
+ if (http->state == HTTP_STATE_WAITING)
+ return (HTTP_STATUS_CONTINUE);
+
+ /*
+ * Grab all of the lines we can from the connection...
+ */
+
+ while (_httpUpdate(http, &status));
+
+ /*
+ * See if there was an error...
+ */
+
+ if (http->error == EPIPE && http->status > HTTP_STATUS_CONTINUE)
+ {
+ DEBUG_printf(("1httpUpdate: Returning status %d...", http->status));
+ return (http->status);
+ }
+
+ if (http->error)
+ {
+ DEBUG_printf(("1httpUpdate: socket error %d - %s", http->error,
+ strerror(http->error)));
+ http->status = HTTP_STATUS_ERROR;
+ return (HTTP_STATUS_ERROR);
+ }
+
+ /*
+ * Return the current status...
+ */
+
+ return (status);
+}
+
+
+/*
+ * '_httpWait()' - Wait for data available on a connection (no flush).
+ */
+
+int /* O - 1 if data is available, 0 otherwise */
+_httpWait(http_t *http, /* I - HTTP connection */
+ int msec, /* I - Milliseconds to wait */
+ int usessl) /* I - Use SSL context? */
+{
+#ifdef HAVE_POLL
+ struct pollfd pfd; /* Polled file descriptor */
+#else
+ fd_set input_set; /* select() input set */
+ struct timeval timeout; /* Timeout */
+#endif /* HAVE_POLL */
+ int nfds; /* Result from select()/poll() */
+
+
+ DEBUG_printf(("4_httpWait(http=%p, msec=%d, usessl=%d)", (void *)http, msec, usessl));
+
+ if (http->fd < 0)
+ {
+ DEBUG_printf(("5_httpWait: Returning 0 since fd=%d", http->fd));
+ return (0);
+ }
+
+ /*
+ * Check the SSL/TLS buffers for data first...
+ */
+
+#ifdef HAVE_SSL
+ if (http->tls && _httpTLSPending(http))
+ {
+ DEBUG_puts("5_httpWait: Return 1 since there is pending TLS data.");
+ return (1);
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Then try doing a select() or poll() to poll the socket...
+ */
+
+#ifdef HAVE_POLL
+ pfd.fd = http->fd;
+ pfd.events = POLLIN;
+
+ do
+ {
+ nfds = poll(&pfd, 1, msec);
+ }
+ while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
+
+#else
+ do
+ {
+ FD_ZERO(&input_set);
+ FD_SET(http->fd, &input_set);
+
+ DEBUG_printf(("6_httpWait: msec=%d, http->fd=%d", msec, http->fd));
+
+ if (msec >= 0)
+ {
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ nfds = select(http->fd + 1, &input_set, NULL, NULL, &timeout);
+ }
+ else
+ nfds = select(http->fd + 1, &input_set, NULL, NULL, NULL);
+
+ DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
+ }
+# ifdef WIN32
+ while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
+ WSAGetLastError() == WSAEWOULDBLOCK));
+# else
+ while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
+# endif /* WIN32 */
+#endif /* HAVE_POLL */
+
+ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds,
+ errno));
+
+ return (nfds > 0);
+}
+
+
+/*
+ * 'httpWait()' - Wait for data available on a connection.
+ *
+ * @since CUPS 1.1.19/macOS 10.3@
+ */
+
+int /* O - 1 if data is available, 0 otherwise */
+httpWait(http_t *http, /* I - HTTP connection */
+ int msec) /* I - Milliseconds to wait */
+{
+ /*
+ * First see if there is data in the buffer...
+ */
+
+ DEBUG_printf(("2httpWait(http=%p, msec=%d)", (void *)http, msec));
+
+ if (http == NULL)
+ return (0);
+
+ if (http->used)
+ {
+ DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
+ return (1);
+ }
+
+#ifdef HAVE_LIBZ
+ if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0)
+ {
+ DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready.");
+ return (1);
+ }
+#endif /* HAVE_LIBZ */
+
+ /*
+ * Flush pending data, if any...
+ */
+
+ if (http->wused)
+ {
+ DEBUG_puts("3httpWait: Flushing write buffer.");
+
+ if (httpFlushWrite(http) < 0)
+ return (0);
+ }
+
+ /*
+ * If not, check the SSL/TLS buffers and do a select() on the connection...
+ */
+
+ return (_httpWait(http, msec, 1));
+}
+
+
+/*
+ * 'httpWrite()' - Write data to a HTTP connection.
+ *
+ * This function is deprecated. Use the httpWrite2() function which can
+ * write more than 2GB of data.
+ *
+ * @deprecated@
+ */
+
+int /* O - Number of bytes written */
+httpWrite(http_t *http, /* I - HTTP connection */
+ const char *buffer, /* I - Buffer for data */
+ int length) /* I - Number of bytes to write */
+{
+ return ((int)httpWrite2(http, buffer, (size_t)length));
+}
+
+
+/*
+ * 'httpWrite2()' - Write data to a HTTP connection.
+ *
+ * @since CUPS 1.2/macOS 10.5@
+ */
+
+ssize_t /* O - Number of bytes written */
+httpWrite2(http_t *http, /* I - HTTP connection */
+ const char *buffer, /* I - Buffer for data */
+ size_t length) /* I - Number of bytes to write */
+{
+ ssize_t bytes; /* Bytes written */
+
+
+ DEBUG_printf(("httpWrite2(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length));
+
+ /*
+ * Range check input...
+ */
+
+ if (!http || !buffer)
+ {
+ DEBUG_puts("1httpWrite2: Returning -1 due to bad input.");
+ return (-1);
+ }
+
+ /*
+ * Mark activity on the connection...
+ */
+
+ http->activity = time(NULL);
+
+ /*
+ * Buffer small writes for better performance...
+ */
+
+#ifdef HAVE_LIBZ
+ if (http->coding == _HTTP_CODING_GZIP || http->coding == _HTTP_CODING_DEFLATE)
+ {
+ DEBUG_printf(("1httpWrite2: http->coding=%d", http->coding));
+
+ if (length == 0)
+ {
+ http_content_coding_finish(http);
+ bytes = 0;
+ }
+ else
+ {
+ size_t slen; /* Bytes to write */
+ ssize_t sret; /* Bytes written */
+
+ http->stream.next_in = (Bytef *)buffer;
+ http->stream.avail_in = (uInt)length;
+
+ while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK)
+ {
+ DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out));
+
+ if (http->stream.avail_out > 0)
+ continue;
+
+ slen = _HTTP_MAX_SBUFFER - http->stream.avail_out;
+
+ DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen));
+
+ if (slen > 0 && http->data_encoding == HTTP_ENCODING_CHUNKED)
+ sret = http_write_chunk(http, (char *)http->sbuffer, slen);
+ else if (slen > 0)
+ sret = http_write(http, (char *)http->sbuffer, slen);
+ else
+ sret = 0;
+
+ if (sret < 0)
+ {
+ DEBUG_puts("1httpWrite2: Unable to write, returning -1.");
+ return (-1);
+ }
+
+ http->stream.next_out = (Bytef *)http->sbuffer;
+ http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER;
+ }
+
+ bytes = (ssize_t)length;
+ }
+ }
+ else
+#endif /* HAVE_LIBZ */
+ if (length > 0)
+ {
+ if (http->wused && (length + (size_t)http->wused) > sizeof(http->wbuffer))
+ {
+ DEBUG_printf(("2httpWrite2: Flushing buffer (wused=%d, length="
+ CUPS_LLFMT ")", http->wused, CUPS_LLCAST length));