From: mike Date: Tue, 13 Nov 2012 19:22:57 +0000 (+0000) Subject: Add new httpGetContentEncoding API. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e597c45070b0dab25b125ead85fc5c19708fcbd3;p=thirdparty%2Fcups.git Add new httpGetContentEncoding API. Support Accept-Encoding in ippserver. git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@10694 7a7537e8-13f0-0310-91df-b6672ffda945 --- diff --git a/cups/http-private.h b/cups/http-private.h index f8a1e38ddf..af6b3a47ad 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -403,7 +403,9 @@ extern void _cups_freeifaddrs(struct ifaddrs *addrs); */ #define _httpAddrFamily(addrp) (addrp)->addr.sa_family -extern int _httpAddrPort(http_addr_t *addr) _CUPS_DEPRECATED_MSG("Use httpAddrPort instead."); +extern int _httpAddrPort(http_addr_t *addr) + _CUPS_DEPRECATED_MSG("Use httpAddrPort " + "instead."); extern void _httpAddrSetPort(http_addr_t *addr, int port); extern char *_httpAssembleUUID(const char *server, int port, const char *name, int number, @@ -421,7 +423,7 @@ extern char *_httpEncodeURI(char *dst, const char *src, size_t dstsize); extern void _httpFreeCredentials(http_tls_credentials_t credentials); extern ssize_t _httpPeek(http_t *http, char *buffer, size_t length) - _CUPS_DEPRECATED; + _CUPS_DEPRECATED_MSG("Use httpPeek instead."); extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), diff --git a/cups/http.c b/cups/http.c index f4d48b8ad3..80d687d4a5 100644 --- a/cups/http.c +++ b/cups/http.c @@ -48,6 +48,8 @@ * _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. @@ -1021,7 +1023,8 @@ httpFlushWrite(http_t *http) /* I - Connection to server */ 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) { @@ -1106,6 +1109,94 @@ httpGet(http_t *http, /* I - Connection to server */ } +/* + * '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. * @@ -1265,6 +1356,10 @@ httpGetLength(http_t *http) /* I - Connection to server */ 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])); @@ -1275,12 +1370,12 @@ httpGetLength2(http_t *http) /* I - Connection to server */ { 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 @@ -1298,25 +1393,35 @@ httpGetLength2(http_t *http) /* I - Connection to server */ */ 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); } @@ -3309,6 +3414,8 @@ _httpUpdate(http_t *http, /* I - Connection to server */ while (_cups_isspace(*value)) value ++; + DEBUG_printf(("1_httpUpdate: Header %s: %s", line, value)); + /* * Be tolerants of servers that send unknown attribute fields... */ @@ -3953,6 +4060,11 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ return (-1); } + /* + * Force data_encoding and data_length to be set according to the response + * headers... + */ + (void)httpGetLength2(http); http_content_coding_start(http, diff --git a/cups/http.h b/cups/http.h index f2ce0dde11..53dcffea76 100644 --- a/cups/http.h +++ b/cups/http.h @@ -585,8 +585,6 @@ extern int httpReconnect2(http_t *http, int msec, int *cancel) /**** New in CUPS 1.7 ****/ -//extern int httpAcceptsEncoding(http_t *http, const char *coding) -// _CUPS_API_1_7; extern http_t *httpAcceptConnection(int fd, int blocking) _CUPS_API_1_7; extern http_addrlist_t *httpAddrCopyList(http_addrlist_t *src) _CUPS_API_1_7; @@ -598,6 +596,7 @@ extern http_t *httpConnect2(const char *host, int port, int family, http_encryption_t encryption, int blocking, int msec, int *cancel) _CUPS_API_1_7; +extern const char *httpGetContentEncoding(http_t *http) _CUPS_API_1_7; extern http_status_t httpGetExpect(http_t *http) _CUPS_API_1_7; extern ssize_t httpPeek(http_t *http, char *buffer, size_t length) _CUPS_API_1_7; diff --git a/test/ippserver.c b/test/ippserver.c index e4bd264c22..2c8fc84e8a 100644 --- a/test/ippserver.c +++ b/test/ippserver.c @@ -334,6 +334,7 @@ static int register_printer(_ipp_printer_t *printer, 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, ...) @@ -3922,6 +3923,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ hostname[HTTP_MAX_HOST]; /* Hostname */ int port; /* Port number */ + const char *encoding; /* Content-Encoding value */ /* @@ -3952,19 +3954,19 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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); } @@ -3978,7 +3980,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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); } @@ -3997,7 +3999,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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); } @@ -4008,7 +4010,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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); } @@ -4019,7 +4021,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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); } @@ -4037,7 +4039,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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 @@ -4046,7 +4048,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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); } } @@ -4055,6 +4057,8 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * Handle new transfers... */ + encoding = httpGetContentEncoding(client->http); + switch (client->operation) { case HTTP_STATE_OPTIONS : @@ -4062,15 +4066,15 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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 : @@ -4090,7 +4094,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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); @@ -4105,7 +4109,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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, "/")) { @@ -4113,7 +4117,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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, @@ -4141,7 +4145,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ 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 : @@ -4152,7 +4156,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ * 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)); } /* @@ -4168,7 +4172,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ { 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); } } @@ -4336,7 +4340,7 @@ process_ipp(_ipp_client_t *client) /* I - Client */ * 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); } @@ -4398,7 +4402,7 @@ process_ipp(_ipp_client_t *client) /* I - Client */ 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))); } @@ -4597,10 +4601,12 @@ register_printer( */ 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 */ @@ -4647,6 +4653,9 @@ respond_http(_ipp_client_t *client, /* I - Client */ "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);