55#include "sentry_ratelimiter.h"
66#include "sentry_string.h"
77
8+
89#define ENVELOPE_MIME "application/x-sentry-envelope"
9- // The headers we use are: `x-sentry-auth`, `content-type`, `content-length`
10- #define MAX_HTTP_HEADERS 3
10+ // The headers we use are: `x-sentry-auth`, `content-type`, `content-encoding`, `content- length`
11+ #define MAX_HTTP_HEADERS 4
1112
1213typedef struct sentry_transport_s {
1314 void (* send_envelope_func )(sentry_envelope_t * envelope , void * state );
@@ -165,9 +166,24 @@ sentry__prepare_http_request(sentry_envelope_t *envelope,
165166 return NULL ;
166167 }
167168
169+ char * compressed_body = NULL ;
170+ size_t compressed_body_len = 0 ;
171+ bool compressed = sentry_gzipped_with_compression (
172+ body , body_len , & compressed_body , & compressed_body_len );
173+ if (compressed ) {
174+ if (body_owned ) {
175+ sentry_free (body );
176+ body = NULL ;
177+ body_owned = false;
178+ }
179+ }
180+
168181 sentry_prepared_http_request_t * req
169182 = SENTRY_MAKE (sentry_prepared_http_request_t );
170183 if (!req ) {
184+ if (compressed ) {
185+ sentry_free (compressed_body );
186+ }
171187 if (body_owned ) {
172188 sentry_free (body );
173189 }
@@ -177,6 +193,9 @@ sentry__prepare_http_request(sentry_envelope_t *envelope,
177193 sizeof (sentry_prepared_http_header_t ) * MAX_HTTP_HEADERS );
178194 if (!req -> headers ) {
179195 sentry_free (req );
196+ if (compressed ) {
197+ sentry_free (compressed_body );
198+ }
180199 if (body_owned ) {
181200 sentry_free (body );
182201 }
@@ -196,13 +215,29 @@ sentry__prepare_http_request(sentry_envelope_t *envelope,
196215 h -> key = "content-type" ;
197216 h -> value = sentry__string_clone (ENVELOPE_MIME );
198217
218+ if (compressed ) {
219+ h = & req -> headers [req -> headers_len ++ ];
220+ h -> key = "content-encoding" ;
221+ h -> value = sentry__string_clone ("gzip" );
222+ }
223+
199224 h = & req -> headers [req -> headers_len ++ ];
200225 h -> key = "content-length" ;
201- h -> value = sentry__int64_to_string ((int64_t )body_len );
226+ if (compressed ) {
227+ h -> value = sentry__int64_to_string ((int64_t )compressed_body_len );
228+ } else {
229+ h -> value = sentry__int64_to_string ((int64_t )body_len );
230+ }
202231
203- req -> body = body ;
204- req -> body_len = body_len ;
205- req -> body_owned = body_owned ;
232+ if (compressed ) {
233+ req -> body = compressed_body ;
234+ req -> body_len = compressed_body_len ;
235+ req -> body_owned = true;
236+ } else {
237+ req -> body = body ;
238+ req -> body_len = body_len ;
239+ req -> body_owned = body_owned ;
240+ }
206241
207242 return req ;
208243}
@@ -223,3 +258,51 @@ sentry__prepared_http_request_free(sentry_prepared_http_request_t *req)
223258 }
224259 sentry_free (req );
225260}
261+
262+ bool
263+ sentry_gzipped_with_compression (const char * body , const size_t body_len ,
264+ char * * compressed_body , size_t * compressed_body_len )
265+ {
266+ if (!body || body_len == 0 ) {
267+ return false;
268+ }
269+
270+ z_stream stream ;
271+ memset (& stream , 0 , sizeof (stream ));
272+ stream .next_in = body ;
273+ stream .avail_in = body_len ;
274+
275+ int err = deflateInit2 (& stream , Z_DEFAULT_COMPRESSION , Z_DEFLATED ,
276+ MAX_WBITS + 16 , 9 , Z_DEFAULT_STRATEGY );
277+ if (err != Z_OK ) {
278+ SENTRY_TRACEF ("deflateInit2 failed: %d" , err );
279+ return false;
280+ }
281+
282+ size_t len = compressBound (body_len );
283+ char * buffer = sentry_malloc (len );
284+ if (!buffer ) {
285+ deflateEnd (& stream );
286+ return false;
287+ }
288+
289+ while (err == Z_OK ) {
290+ stream .next_out = buffer + stream .total_out ;
291+ stream .avail_out = len - stream .total_out ;
292+ err = deflate (& stream , Z_FINISH );
293+ }
294+
295+ if (err != Z_STREAM_END ) {
296+ SENTRY_TRACEF ("deflate failed: %d" , err );
297+ sentry_free (buffer );
298+ buffer = NULL ;
299+ deflateEnd (& stream );
300+ return false;
301+ }
302+
303+ * compressed_body_len = stream .total_out ;
304+ * compressed_body = buffer ;
305+
306+ deflateEnd (& stream );
307+ return true;
308+ }
0 commit comments