* _httpFreeCredentials() - Free internal credentials.
* httpFreeCredentials() - Free an array of credentials.
* httpGet() - Send a GET request to the server.
+ * httpGetContentEncoding() - Get a common content encoding, if any,
+ * between the client and server.
* httpGetAuthString() - Get the current authorization string.
* httpGetBlocking() - Get the blocking/non-block state of a
* connection.
int bytes; /* Bytes written */
- DEBUG_printf(("httpFlushWrite(http=%p)", http));
+ DEBUG_printf(("httpFlushWrite(http=%p) data_encoding=%d", http,
+ http ? http->data_encoding : -1));
if (!http || !http->wused)
{
}
+/*
+ * 'httpGetContentEncoding()' - Get a common content encoding, if any, between
+ * the client and server.
+ *
+ * This function uses the value of the Accepts-Encoding HTTP header and must be
+ * called after receiving a response from the server or a request from the
+ * client. The value returned can be use in subsequent requests (for clients)
+ * or in the response (for servers) in order to compress the content stream.
+ *
+ * @since CUPS 1.7@
+ */
+
+const char * /* O - Content-Coding value or
+ @code NULL@ for the identity
+ coding. */
+httpGetContentEncoding(http_t *http) /* I - Connection to client/server */
+{
+#ifdef HAVE_LIBZ
+ if (http && http->accept_encoding)
+ {
+ int i; /* Looping var */
+ char temp[HTTP_MAX_VALUE], /* Copy of Accepts-Encoding value */
+ *start, /* Start of coding value */
+ *end; /* End of coding value */
+ double qvalue; /* "qvalue" for coding */
+ struct lconv *loc = localeconv(); /* Locale data */
+ static const char * const codings[] =
+ { /* Supported content codings */
+ "deflate",
+ "gzip",
+ "x-deflate",
+ "x-gzip"
+ };
+
+ strlcpy(temp, http->accept_encoding, sizeof(temp));
+
+ for (start = temp; *start; start = end)
+ {
+ /*
+ * Find the end of the coding name...
+ */
+
+ qvalue = 1.0;
+ end = start;
+ while (*end && *end != ';' && *end != ',' && !isspace(*end & 255))
+ end ++;
+
+ if (*end == ';')
+ {
+ /*
+ * Grab the qvalue as needed...
+ */
+
+ if (!strncmp(end, ";q=", 3))
+ qvalue = _cupsStrScand(end + 3, NULL, loc);
+
+ /*
+ * Skip past all attributes...
+ */
+
+ *end++ = '\0';
+ while (*end && *end != ',' && !isspace(*end & 255))
+ end ++;
+ }
+ else if (*end)
+ *end++ = '\0';
+
+ while (*end && isspace(*end & 255))
+ end ++;
+
+ /*
+ * Check value if it matches something we support...
+ */
+
+ if (qvalue <= 0.0)
+ continue;
+
+ for (i = 0; i < (int)(sizeof(codings) / sizeof(codings[0])); i ++)
+ if (!strcmp(start, codings[i]))
+ return (codings[i]);
+ }
+ }
+#endif /* HAVE_LIBZ */
+
+ return (NULL);
+}
+
+
/*
* 'httpGetAuthString()' - Get the current authorization string.
*
off_t /* O - Content length */
httpGetLength2(http_t *http) /* I - Connection to server */
{
+ http_encoding_t encoding; /* Data encoding */
+ off_t remaining; /* Remaining length */
+
+
DEBUG_printf(("2httpGetLength2(http=%p), state=%s", http,
http_states[http->state + 1]));
{
DEBUG_puts("4httpGetLength2: chunked request!");
- http->data_encoding = HTTP_ENCODING_CHUNKED;
- http->data_remaining = 0;
+ encoding = HTTP_ENCODING_CHUNKED;
+ remaining = 0;
}
else
{
- http->data_encoding = HTTP_ENCODING_LENGTH;
+ encoding = HTTP_ENCODING_LENGTH;
/*
* The following is a hack for HTTP servers that don't send a
*/
if (http->status >= HTTP_MULTIPLE_CHOICES)
- http->data_remaining = 0;
+ remaining = 0;
else
- http->data_remaining = 2147483647;
+ remaining = 2147483647;
}
- else if ((http->data_remaining =
- strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
- NULL, 10)) < 0)
+ else if ((remaining = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH],
+ NULL, 10)) < 0)
return (-1);
DEBUG_printf(("4httpGetLength2: content_length=" CUPS_LLFMT,
- CUPS_LLCAST http->data_remaining));
+ CUPS_LLCAST remaining));
}
- if (http->data_remaining <= INT_MAX)
- http->_data_remaining = (int)http->data_remaining;
- else
- http->_data_remaining = INT_MAX;
+ if ((http->mode == _HTTP_MODE_CLIENT &&
+ (http->state == HTTP_STATE_GET || http->state == HTTP_STATE_POST ||
+ http->state == HTTP_STATE_PUT)) ||
+ (http->mode == _HTTP_MODE_SERVER &&
+ (http->state == HTTP_STATE_GET_SEND ||
+ http->state == HTTP_STATE_POST_SEND)))
+ {
+ http->data_encoding = encoding;
+ http->data_remaining = remaining;
+
+ if (remaining <= INT_MAX)
+ http->_data_remaining = (int)remaining;
+ else
+ http->_data_remaining = INT_MAX;
+ }
- return (http->data_remaining);
+ return (remaining);
}
while (_cups_isspace(*value))
value ++;
+ DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value));
+
/*
* Be tolerants of servers that send unknown attribute fields...
*/
return (-1);
}
+ /*
+ * Force data_encoding and data_length to be set according to the response
+ * headers...
+ */
+
(void)httpGetLength2(http);
http_content_coding_start(http,
int duplex, const char *regtype);
#endif /* HAVE_DNSSD */
static int respond_http(_ipp_client_t *client, http_status_t code,
+ const char *content_coding,
const char *type, size_t length);
static void respond_ipp(_ipp_client_t *client, ipp_status_t status,
const char *message, ...)
hostname[HTTP_MAX_HOST];
/* Hostname */
int port; /* Port number */
+ const char *encoding; /* Content-Encoding value */
/*
if (http_state == HTTP_STATE_ERROR)
{
fprintf(stderr, "%s Bad request line.\n", client->hostname);
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
else if (http_state == HTTP_STATE_UNKNOWN_METHOD)
{
fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname);
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
else if (http_state == HTTP_STATE_UNKNOWN_VERSION)
{
fprintf(stderr, "%s Bad HTTP version.\n", client->hostname);
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK)
{
fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri);
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
if (http_status != HTTP_STATUS_OK)
{
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
* HTTP/1.1 and higher require the "Host:" field...
*/
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
if (!_cups_strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION),
"Upgrade"))
{
- if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0))
return (0);
}
* Send 100-continue header...
*/
- if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0))
return (0);
}
else
* Send 417-expectation-failed header...
*/
- if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0))
return (0);
}
}
* Handle new transfers...
*/
+ encoding = httpGetContentEncoding(client->http);
+
switch (client->operation)
{
case HTTP_STATE_OPTIONS :
* Do HEAD/OPTIONS command...
*/
- return (respond_http(client, HTTP_STATUS_OK, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0));
case HTTP_STATE_HEAD :
if (!strcmp(client->uri, "/icon.png"))
- return (respond_http(client, HTTP_STATUS_OK, "image/png", 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0));
else if (!strcmp(client->uri, "/"))
- return (respond_http(client, HTTP_STATUS_OK, "text/html", 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0));
else
- return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
break;
case HTTP_STATE_GET :
if (!stat(client->printer->icon, &fileinfo) &&
(fd = open(client->printer->icon, O_RDONLY)) >= 0)
{
- if (!respond_http(client, HTTP_STATUS_OK, "image/png",
+ if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png",
fileinfo.st_size))
{
close(fd);
close(fd);
}
else
- return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
}
else if (!strcmp(client->uri, "/"))
{
* Show web status page...
*/
- if (!respond_http(client, HTTP_STATUS_OK, "text/html", 0))
+ if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0))
return (0);
html_printf(client,
return (1);
}
else
- return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
break;
case HTTP_STATE_POST :
* Not an IPP request...
*/
- return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0));
}
/*
{
fprintf(stderr, "%s IPP read error (%s).\n", client->hostname,
cupsLastErrorString());
- respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
}
* Send 100-continue header...
*/
- if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0))
return (0);
}
if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
httpFlush(client->http); /* Flush trailing (junk) data */
- return (respond_http(client, HTTP_STATUS_OK, "application/ipp",
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp",
ippLength(client->response)));
}
*/
int /* O - 1 on success, 0 on failure */
-respond_http(_ipp_client_t *client, /* I - Client */
- http_status_t code, /* I - HTTP status of response */
- const char *type, /* I - MIME type of response */
- size_t length) /* I - Length of response */
+respond_http(
+ _ipp_client_t *client, /* I - Client */
+ http_status_t code, /* I - HTTP status of response */
+ const char *content_encoding, /* I - Content-Encoding of response */
+ const char *type, /* I - MIME media type of response */
+ size_t length) /* I - Length of response */
{
char message[1024]; /* Text message */
"text/html; charset=utf-8");
else
httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type);
+
+ if (content_encoding)
+ httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding);
}
httpSetLength(client->http, length);