Skip to content

Commit 0ca33a9

Browse files
fix(ulfius): add gzip compression for /compression endpoint
- Include zlib.h and link -lz - Pre-compress large JSON at startup with deflateInit2 (gzip mode) - Serve gzipped response when Accept-Encoding includes gzip - Add zlib1g to runtime image
1 parent f2d87fe commit 0ca33a9

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

frameworks/ulfius/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ WORKDIR /app
3030
COPY src/server.c ./
3131
RUN gcc -O3 -flto -march=native -o server server.c \
3232
$(pkg-config --cflags --libs libulfius) \
33-
-ljansson -lsqlite3 -lm -lpthread
33+
-ljansson -lsqlite3 -lz -lm -lpthread
3434

3535
FROM ubuntu:24.04
3636
RUN apt-get update && apt-get install -y --no-install-recommends \
37-
libmicrohttpd12t64 libjansson4 libgnutls30t64 libsqlite3-0 && \
37+
libmicrohttpd12t64 libjansson4 libgnutls30t64 libsqlite3-0 zlib1g && \
3838
rm -rf /var/lib/apt/lists/*
3939
COPY --from=build /usr/local/lib/libulfius.so* /usr/local/lib/
4040
COPY --from=build /usr/local/lib/liborcania.so* /usr/local/lib/

frameworks/ulfius/src/server.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <ulfius.h>
22
#include <jansson.h>
33
#include <sqlite3.h>
4+
#include <zlib.h>
45
#include <stdio.h>
56
#include <stdlib.h>
67
#include <string.h>
@@ -19,6 +20,8 @@
1920
static json_t *dataset_items = NULL;
2021
static char *json_large_response = NULL;
2122
static size_t json_large_len = 0;
23+
static unsigned char *json_large_gzipped = NULL;
24+
static size_t json_large_gzip_len = 0;
2225

2326
typedef struct {
2427
char name[256];
@@ -99,6 +102,26 @@ static void load_dataset(void) {
99102
dataset_items = root;
100103
}
101104

105+
static unsigned char *gzip_compress(const char *input, size_t in_len, size_t *out_len) {
106+
uLongf bound = compressBound(in_len) + 32;
107+
unsigned char *buf = malloc(bound);
108+
if (!buf) return NULL;
109+
110+
z_stream strm = {0};
111+
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
112+
free(buf);
113+
return NULL;
114+
}
115+
strm.next_in = (Bytef *)input;
116+
strm.avail_in = in_len;
117+
strm.next_out = buf;
118+
strm.avail_out = bound;
119+
deflate(&strm, Z_FINISH);
120+
*out_len = strm.total_out;
121+
deflateEnd(&strm);
122+
return buf;
123+
}
124+
102125
static void load_dataset_large(void) {
103126
size_t len;
104127
char *data = read_file("/data/dataset-large.json", &len);
@@ -123,6 +146,9 @@ static void load_dataset_large(void) {
123146
json_large_response = json_dumps(resp, JSON_COMPACT);
124147
json_large_len = strlen(json_large_response);
125148
json_decref(resp);
149+
150+
/* Pre-compress for /compression endpoint */
151+
json_large_gzipped = gzip_compress(json_large_response, json_large_len, &json_large_gzip_len);
126152
}
127153

128154
static const char *mime_for_ext(const char *ext) {
@@ -206,7 +232,14 @@ int cb_compression(const struct _u_request *request, struct _u_response *respons
206232
ulfius_set_string_body_response(response, 500, "No dataset");
207233
return U_CALLBACK_CONTINUE;
208234
}
209-
ulfius_set_binary_body_response(response, 200, json_large_response, json_large_len);
235+
/* Serve gzip if client accepts it and we have a pre-compressed version */
236+
const char *accept_enc = u_map_get(request->map_header, "Accept-Encoding");
237+
if (json_large_gzipped && accept_enc && strstr(accept_enc, "gzip")) {
238+
ulfius_set_binary_body_response(response, 200, (const char *)json_large_gzipped, json_large_gzip_len);
239+
u_map_put(response->map_header, "Content-Encoding", "gzip");
240+
} else {
241+
ulfius_set_binary_body_response(response, 200, json_large_response, json_large_len);
242+
}
210243
u_map_put(response->map_header, "Content-Type", "application/json");
211244
return U_CALLBACK_CONTINUE;
212245
}

0 commit comments

Comments
 (0)