#include #include #include #include #include struct hf_content_uncompress { /* MODE AND CALLBACKS */ unsigned int content_encode; hf_private_cb * data_cb; void * data_cb_user; /* ZLIB STREAM */ z_stream * z_stream_ptr; unsigned char * chunk; size_t sz_chunk; }; struct hf_content_compress { z_stream * z_stream_ptr; unsigned int content_encode; }; void hf_content_uncompress_destroy(struct hf_content_uncompress * cv_object) { (void) inflateEnd(cv_object->z_stream_ptr); free(cv_object->z_stream_ptr); cv_object->z_stream_ptr = NULL; free(cv_object); } struct hf_content_uncompress * hf_content_uncompress_create(unsigned int content_encode, hf_private_cb * data_cb, void * data_cb_user) { struct hf_content_uncompress * cv_object = ALLOC(struct hf_content_uncompress, 1); assert(data_cb != NULL); cv_object->content_encode = content_encode; cv_object->data_cb = data_cb; cv_object->data_cb_user = data_cb_user; /* ZSTREAM */ cv_object->z_stream_ptr = ALLOC(z_stream, 1); cv_object->z_stream_ptr->zalloc = NULL; cv_object->z_stream_ptr->zfree = NULL; cv_object->z_stream_ptr->opaque = NULL; cv_object->z_stream_ptr->avail_in = 0; cv_object->z_stream_ptr->next_in = Z_NULL; /* CHUNK, 4K */ #define CHUNK_SIZE (1024 * 1024 * 4) cv_object->chunk = (unsigned char *) malloc(CHUNK_SIZE); cv_object->sz_chunk = CHUNK_SIZE; int ret = 0; if (content_encode == HTTP_ACCEPT_ENCODING_GZIP) { ret = inflateInit2(cv_object->z_stream_ptr, MAX_WBITS + 16); } else if (content_encode == HTTP_ACCEPT_ENCODING_DEFLATE) { ret = inflateInit2(cv_object->z_stream_ptr, -MAX_WBITS); } if (ret != Z_OK) goto __errout; return cv_object; __errout: free(cv_object->z_stream_ptr); free(cv_object->chunk); free(cv_object); return NULL; } int hf_content_uncompress_write(struct hf_content_uncompress * cv_object, struct http_half_private * hf_private, tfe_http_event http_ev, const unsigned char * data, size_t datalen) { z_stream * z_stream_ptr = cv_object->z_stream_ptr; z_stream_ptr->avail_in = (unsigned int) datalen; z_stream_ptr->next_in = (unsigned char *) data; if (z_stream_ptr->avail_in == 0) { (void) inflateEnd(z_stream_ptr); return Z_ERRNO; } int ret = 0; do { z_stream_ptr->avail_out = (unsigned int) cv_object->sz_chunk; z_stream_ptr->next_out = cv_object->chunk; ret = inflate(z_stream_ptr, Z_NO_FLUSH); assert(ret != Z_STREAM_ERROR); /* state not clobbered */ if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { goto __error; } unsigned int have = (unsigned int) cv_object->sz_chunk - z_stream_ptr->avail_out; if (have > 0 && cv_object->data_cb != NULL) { cv_object->data_cb(hf_private, http_ev, cv_object->chunk, (size_t) have, cv_object->data_cb_user); } } while (z_stream_ptr->avail_out == 0); return ret; __error: (void) inflateEnd(z_stream_ptr); return ret; } struct hf_content_compress * hf_content_compress_create(unsigned int content_encode) { struct hf_content_compress * cv_object = ALLOC(struct hf_content_compress, 1); cv_object->content_encode = content_encode; /* ZSTREAM */ cv_object->z_stream_ptr = ALLOC(z_stream, 1); cv_object->z_stream_ptr->zalloc = NULL; cv_object->z_stream_ptr->zfree = NULL; cv_object->z_stream_ptr->opaque = NULL; cv_object->z_stream_ptr->avail_in = 0; cv_object->z_stream_ptr->next_in = Z_NULL; int __windows_bits = 0; if (content_encode == HTTP_ACCEPT_ENCODING_GZIP) { __windows_bits = MAX_WBITS + 16; } if (content_encode == HTTP_ACCEPT_ENCODING_DEFLATE) { __windows_bits = -MAX_WBITS; } int ret = deflateInit2(cv_object->z_stream_ptr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, __windows_bits, 8, Z_DEFAULT_STRATEGY); if (ret != Z_OK) goto __errout; return cv_object; __errout: free(cv_object->z_stream_ptr); free(cv_object); return NULL; } int hf_content_compress_write(struct hf_content_compress * cv_object, const unsigned char * in_data, size_t sz_in_data, struct evbuffer * out_ev_buf, int end) { #define SZ_IOVEC 2 struct evbuffer_iovec v[SZ_IOVEC]; /* Reserve the space, because the length of the compressed data will be short * than uncompressed data in usually, we set the reserve space as much as sz_in_data */ size_t __sz_reserve_space = sz_in_data > 512 ? sz_in_data : 512; int iov_count = evbuffer_reserve_space(out_ev_buf, __sz_reserve_space, v, SZ_IOVEC); if (iov_count < 1 || iov_count > SZ_IOVEC) return -1; z_stream * z = cv_object->z_stream_ptr; z->next_in = (unsigned char *) in_data; z->avail_in = (unsigned int) sz_in_data; unsigned int iov_offset = 0; z->next_out = (unsigned char *) v[iov_offset].iov_base; z->avail_out = (unsigned int) v[iov_offset].iov_len; int flush = end ? Z_FINISH : Z_NO_FLUSH; int ret = 0; do { ret = deflate(z, flush); assert(ret != Z_STREAM_ERROR); assert(iov_offset < SZ_IOVEC); if (z->avail_out == 0 || z->avail_in == 0) { unsigned int len = (unsigned int) v[iov_offset].iov_len - z->avail_out; v[iov_offset].iov_len = (size_t) len; iov_offset++; z->next_out = (unsigned char *) v[iov_offset].iov_base; z->avail_out = (unsigned int) v[iov_offset].iov_len; } } while (z->avail_in > 0); assert(end == 0 || ret == Z_STREAM_END); return evbuffer_commit_space(out_ev_buf, v, iov_count); } void hf_content_compress_destroy(hf_content_compress * cv_object) { return; }