From bf1f90a96a6cffbbad051ca518a9f8575bc41cb5 Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 15 Apr 2013 12:36:27 +0200 Subject: [PATCH] added the ability to store cache items in gzip --- core/utils.c | 9 +++++++- core/zlib.c | 32 +++++++++++++++++++++++++++++ plugins/router_cache/router_cache.c | 27 ++++++++++++++++++++++++ uwsgi.h | 2 ++ 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/core/utils.c b/core/utils.c index 14c16bed..b59bdce4 100644 --- a/core/utils.c +++ b/core/utils.c @@ -628,9 +628,16 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) { if (wsgi_req->cached_response && wsgi_req->status == 200 && wsgi_req->response_size > 0) { uwsgi_cache_magic_set(wsgi_req->cache_it->buf, wsgi_req->cache_it->pos, wsgi_req->cached_response->buf, wsgi_req->cached_response->pos, wsgi_req->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, wsgi_req->cache_it_to ? wsgi_req->cache_it_to->buf : NULL); + if (wsgi_req->cache_it_gzip) { + struct uwsgi_buffer *gzipped = uwsgi_gzip(wsgi_req->cached_response->buf, wsgi_req->cached_response->pos); + if (gzipped) { + uwsgi_cache_magic_set(wsgi_req->cache_it_gzip->buf, wsgi_req->cache_it_gzip->pos, + gzipped->buf, gzipped->pos, wsgi_req->cache_it_expires, UWSGI_CACHE_FLAG_UPDATE, wsgi_req->cache_it_to ? wsgi_req->cache_it_to->buf : NULL); + uwsgi_buffer_destroy(gzipped); + } + } } uwsgi_buffer_destroy(wsgi_req->cache_it); - } if (wsgi_req->cache_it_to) { diff --git a/core/zlib.c b/core/zlib.c index 32c0a02d..1dd4b5cc 100644 --- a/core/zlib.c +++ b/core/zlib.c @@ -1,5 +1,37 @@ #include +static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; + +struct uwsgi_buffer *uwsgi_gzip(char *buf, size_t len) { + z_stream z; + struct uwsgi_buffer *ub = NULL; + uint32_t gzip_crc32 = 0; + char *gzipped = NULL; + char *gzipped0 = NULL; + size_t dlen = 0; + size_t dlen0 = 0; + + uwsgi_crc32(&gzip_crc32, NULL, 0); + if (uwsgi_deflate_init(&z, NULL, 0)) return NULL; + uwsgi_crc32(&gzip_crc32, buf, len); + + gzipped = uwsgi_deflate(&z, buf, len, &dlen); + if (!gzipped) goto end; + gzipped0 = uwsgi_deflate(&z, NULL, 0, &dlen0); + if (!gzipped0) goto end; + + ub = uwsgi_buffer_new(10 + dlen + dlen0 + 8); + if (uwsgi_buffer_append(ub, gzheader, 10)) goto end; + if (uwsgi_buffer_append(ub, gzipped, dlen)) goto end; + if (uwsgi_buffer_append(ub, gzipped0, dlen0)) goto end; + if (uwsgi_buffer_u32le(ub, gzip_crc32)) goto end; + if (uwsgi_buffer_u32le(ub, len)) goto end; +end: + if (gzipped) free(gzipped); + if (gzipped0) free(gzipped0); + deflateEnd(&z); + return ub; +} int uwsgi_deflate_init(z_stream *z, char *dict, size_t dict_len) { z->zalloc = Z_NULL; diff --git a/plugins/router_cache/router_cache.c b/plugins/router_cache/router_cache.c index 649880e8..4203bf1e 100644 --- a/plugins/router_cache/router_cache.c +++ b/plugins/router_cache/router_cache.c @@ -23,6 +23,9 @@ struct uwsgi_router_cache_conf { char *key; size_t key_len; + char *gzip; + size_t gzip_len; + char *content_type; size_t content_type_len; @@ -46,6 +49,11 @@ static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct wsgi_req->cache_it = NULL; } + if (wsgi_req->cache_it_gzip) { + uwsgi_buffer_destroy(wsgi_req->cache_it_gzip); + wsgi_req->cache_it_gzip = NULL; + } + if (wsgi_req->cache_it_to) { uwsgi_buffer_destroy(wsgi_req->cache_it_to); wsgi_req->cache_it_to = NULL; @@ -63,6 +71,20 @@ static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct if (!wsgi_req->cache_it_to) { uwsgi_buffer_destroy(wsgi_req->cache_it); wsgi_req->cache_it = NULL; + return UWSGI_ROUTE_NEXT; + } + } + + if (urcc->gzip) { + wsgi_req->cache_it_gzip = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->gzip, urcc->gzip_len); + if (!wsgi_req->cache_it_gzip) { + uwsgi_buffer_destroy(wsgi_req->cache_it); + wsgi_req->cache_it = NULL; + if (wsgi_req->cache_it_to) { + uwsgi_buffer_destroy(wsgi_req->cache_it_to); + wsgi_req->cache_it_to = NULL; + } + return UWSGI_ROUTE_NEXT; } } @@ -111,6 +133,7 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) { struct uwsgi_router_cache_conf *urcc = uwsgi_calloc(sizeof(struct uwsgi_router_cache_conf)); if (uwsgi_kvlist_parse(ur->data, ur->data_len, ',', '=', "key", &urcc->key, + "gzip", &urcc->gzip, "name", &urcc->name, "expires", &urcc->expires_str, NULL)) { uwsgi_log("invalid cachestore route syntax: %s\n", args); @@ -121,6 +144,10 @@ static int uwsgi_router_cache_store(struct uwsgi_route *ur, char *args) { urcc->key_len = strlen(urcc->key); } + if (urcc->gzip) { + urcc->gzip_len = strlen(urcc->gzip); + } + if (urcc->name) { urcc->name_len = strlen(urcc->name); } diff --git a/uwsgi.h b/uwsgi.h index 8e09727d..0dc45dcf 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1396,6 +1396,7 @@ struct wsgi_request { uint32_t route_goto; struct uwsgi_buffer *cache_it; + struct uwsgi_buffer *cache_it_gzip; struct uwsgi_buffer *cache_it_to; uint64_t cache_it_expires; struct uwsgi_buffer *cached_response; @@ -3897,6 +3898,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *); int uwsgi_deflate_init(z_stream *, char *, size_t); char *uwsgi_deflate(z_stream *, char *, size_t, size_t *); void uwsgi_crc32(uint32_t *, char *, size_t); +struct uwsgi_buffer *uwsgi_gzip(char *, size_t); #endif char *uwsgi_get_cookie(struct wsgi_request *, char *, uint16_t, uint16_t *);