+ HashTable *selected;
+ zval zsupported;
+
+ HTTP_G->send.deflate.encoding = 0;
+
+ INIT_PZVAL(&zsupported);
+ array_init(&zsupported);
+ add_next_index_stringl(&zsupported, "gzip", lenof("gzip"), 1);
+ add_next_index_stringl(&zsupported, "x-gzip", lenof("x-gzip"), 1);
+ add_next_index_stringl(&zsupported, "deflate", lenof("deflate"), 1);
+
+ if ((selected = http_negotiate_encoding(&zsupported))) {
+ STATUS hs = FAILURE;
+ char *encoding = NULL;
+ ulong idx;
+
+ if (HASH_KEY_IS_STRING == zend_hash_get_current_key(selected, &encoding, &idx, 0) && encoding) {
+ if (!strcmp(encoding, "gzip") || !strcmp(encoding, "x-gzip")) {
+ if (SUCCESS == (hs = http_send_header_string("Content-Encoding: gzip"))) {
+ HTTP_G->send.deflate.encoding = HTTP_ENCODING_GZIP;
+ }
+ } else if (!strcmp(encoding, "deflate")) {
+ if (SUCCESS == (hs = http_send_header_string("Content-Encoding: deflate"))) {
+ HTTP_G->send.deflate.encoding = HTTP_ENCODING_DEFLATE;
+ }
+ }
+ if (SUCCESS == hs) {
+ http_send_header_string("Vary: Accept-Encoding");
+ }
+ }
+
+ zend_hash_destroy(selected);
+ FREE_HASHTABLE(selected);
+ }
+
+ zval_dtor(&zsupported);
+#else
+ HTTP_G->send.deflate.encoding = 0;
+ php_start_ob_buffer_named("ob_gzhandler", 0, 0 TSRMLS_CC);
+#endif /* HTTP_HAVE_ZLIB */
+ } else if (content_length && !ohandler) {
+ /* emit a content-length header */
+ phpstr header;
+
+ phpstr_init(&header);
+ phpstr_appendf(&header, "Content-Length: %zu", content_length);
+ phpstr_fix(&header);
+ http_send_header_string_ex(PHPSTR_VAL(&header), PHPSTR_LEN(&header), 1);
+ phpstr_dtor(&header);
+ } else {
+ HTTP_G->send.deflate.encoding = 0;
+ }
+
+ return HTTP_G->send.deflate.encoding;
+}
+/* }}} */
+
+#ifdef HTTP_HAVE_ZLIB
+
+/* {{{ inline int http_inflate_rounds */
+static inline int http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
+{
+ int status = 0, round = 0;
+ phpstr buffer;
+
+ *buf = NULL;
+ *len = 0;
+
+ phpstr_init_ex(&buffer, Z->avail_in, PHPSTR_INIT_PREALLOC);
+
+ do {
+ if (PHPSTR_NOMEM == phpstr_resize_ex(&buffer, buffer.size, 0, 1)) {
+ status = Z_MEM_ERROR;
+ } else {
+ Z->avail_out = buffer.free;
+ Z->next_out = (Bytef *) buffer.data + buffer.used;
+#if 0
+ fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+ status = inflate(Z, flush);
+
+ buffer.used += buffer.free - Z->avail_out;
+ buffer.free = Z->avail_out;
+#if 0
+ fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
+#endif
+ HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
+ }
+ } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < HTTP_INFLATE_ROUNDS);
+
+ if (status == Z_OK || status == Z_STREAM_END) {
+ phpstr_shrink(&buffer);
+ phpstr_fix(&buffer);
+ *buf = buffer.data;
+ *len = buffer.used;
+ } else {
+ phpstr_dtor(&buffer);
+ }
+
+ return status;
+}
+/* }}} */
+
+/* {{{ STATUS http_encoding_deflate(int, char *, size_t, char **, size_t *) */
+PHP_HTTP_API STATUS _http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)