Skip to content

Commit 1115ec1

Browse files
authored
Merge pull request #198 from EionRobb/gzip_compression
Add support for gzip compression in API calls
2 parents 4760d8f + 9d6b7c8 commit 1115ec1

5 files changed

Lines changed: 116 additions & 9 deletions

File tree

.github/workflows/cross.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ jobs:
6161
export WIN32_CC=i686-w64-mingw32-gcc
6262
export WIN32_DEV_TOP=win32-dev
6363
export PIDGIN_TREE_TOP=pidgin
64+
export OS=Windows_NT
6465
make libslack.dll
6566
6667
- name: archive
@@ -71,7 +72,7 @@ jobs:
7172
path: lib*.dll
7273

7374
- name: release
74-
if: ${{ !env.ACT }}
75+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
7576
uses: ncipollo/release-action@v1
7677
with:
7778
artifacts: lib*.dll
@@ -81,7 +82,7 @@ jobs:
8182
makeLatest: true
8283

8384
- name: attest
84-
if: ${{ !env.ACT }}
85+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
8586
uses: actions/attest-build-provenance@v1
8687
with:
8788
subject-path: lib*.dll

.github/workflows/linux-arm64.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
path: lib*.so
3737

3838
- name: release
39-
if: ${{ !env.ACT }}
39+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
4040
uses: ncipollo/release-action@v1
4141
with:
4242
artifacts: lib*.so
@@ -46,7 +46,7 @@ jobs:
4646
makeLatest: true
4747

4848
- name: attest
49-
if: ${{ !env.ACT }}
49+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
5050
uses: actions/attest-build-provenance@v1
5151
with:
5252
subject-path: lib*.so

.github/workflows/linux.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
path: lib*.so
3333

3434
- name: release
35-
if: ${{ !env.ACT }}
35+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
3636
uses: ncipollo/release-action@v1
3737
with:
3838
artifacts: lib*.so
@@ -42,7 +42,7 @@ jobs:
4242
makeLatest: true
4343

4444
- name: attest
45-
if: ${{ !env.ACT }}
45+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && !env.ACT
4646
uses: actions/attest-build-provenance@v1
4747
with:
4848
subject-path: lib*.so

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ifndef PROGFILES32
3232
PROGFILES32=$(PROGRAMFILES)
3333
endif
3434

35-
CC = $(WIN32_DEV_TOP)/mingw-4.7.2/bin/gcc
35+
CC = $(WIN32_CC)
3636

3737
DATA_ROOT_DIR_PURPLE:="$(PROGFILES32)/Pidgin"
3838
PLUGIN_DIR_PURPLE:="$(PROGFILES32)/Pidgin/plugins"

slack-api.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <debug.h>
2+
#include <zlib.h>
23

34
#include "slack-api.h"
45
#include "slack-json.h"
@@ -42,21 +43,47 @@ static void api_error(SlackAPICall *call, const char *error) {
4243

4344
static gboolean api_retry(SlackAPICall *call);
4445
static void api_run(SlackAccount *sa);
46+
gchar *api_gunzip(const guchar *gzip_data, gsize *len_ptr);
4547

46-
static void api_cb(PurpleUtilFetchUrlData *fetch, gpointer data, const gchar *buf, gsize len, const gchar *error) {
48+
static void api_cb(PurpleUtilFetchUrlData *fetch, gpointer data, const gchar *buf_h, gsize len_h, const gchar *error) {
49+
gboolean free_buf = FALSE;
4750
SlackAccount *sa = data;
4851
SlackAPICall *call = g_queue_pop_head(&sa->api_calls);
4952
g_return_if_fail(call && (call->fetch == fetch || (call->fetch == NULL && error)));
5053
call->fetch = NULL;
5154

55+
gsize len = len_h;
56+
const gchar *buf = g_strstr_len(buf_h, len_h, "\r\n\r\n");
57+
if (buf) {
58+
buf += 4; // skip the headers
59+
len = len_h - (buf - buf_h);
60+
} else {
61+
buf = buf_h;
62+
len = len_h;
63+
}
64+
65+
if (g_strstr_len(buf_h, len_h - len, "Content-Encoding: gzip") != NULL ||
66+
g_strstr_len(buf_h, len_h - len, "content-encoding: gzip") != NULL) {
67+
gchar *gunzip = api_gunzip((const guchar *)buf, &len);
68+
if (!gunzip) {
69+
api_error(call, "Failed to gunzip response");
70+
api_run(sa);
71+
return;
72+
}
73+
free_buf = TRUE;
74+
buf = gunzip;
75+
}
76+
5277
purple_debug_misc("slack", "api response: %s\n", error ?: buf);
5378
if (error) {
79+
if (free_buf) g_free((gchar *)buf);
5480
api_error(call, error);
5581
api_run(sa);
5682
return;
5783
}
5884

5985
json_value *json = json_parse(buf, len);
86+
if (free_buf) g_free((gchar *)buf);
6087
if (!json) {
6188
api_error(call, "Invalid JSON response");
6289
api_run(sa);
@@ -94,7 +121,7 @@ static gboolean api_retry(SlackAPICall *call) {
94121
purple_debug_misc("slack", "api call: %s\n%s\n", call->url, call->request ?: "");
95122
PurpleUtilFetchUrlData *fetch =
96123
purple_util_fetch_url_request_len_with_account(call->sa->account,
97-
call->url, TRUE, NULL, TRUE, call->request, FALSE, 4096*1024,
124+
call->url, TRUE, NULL, TRUE, call->request, TRUE, 4096*1024,
98125
api_cb, call->sa);
99126
if (fetch)
100127
call->fetch = fetch;
@@ -149,6 +176,7 @@ Content-Length: %" G_GSIZE_FORMAT "\r\n",
149176
if (sa->d_cookie) {
150177
g_string_append_printf(request, "Cookie: d=%s\r\n", sa->d_cookie);
151178
}
179+
g_string_append(request, "Accept-Encoding: gzip\r\n");
152180
g_string_append(request, "\r\n");
153181
g_string_append(request, postdata->str);
154182

@@ -194,3 +222,81 @@ void slack_api_disconnect(SlackAccount *sa) {
194222
while ((call = g_queue_pop_head(&sa->api_calls)))
195223
api_error(call, "disconnected");
196224
}
225+
226+
227+
#include <zlib.h>
228+
229+
gchar *
230+
api_gunzip(const guchar *gzip_data, gsize *len_ptr)
231+
{
232+
gsize gzip_data_len = *len_ptr;
233+
z_stream zstr;
234+
int gzip_err = 0;
235+
gchar *data_buffer;
236+
gulong gzip_len = G_MAXUINT16;
237+
GString *output_string = NULL;
238+
239+
data_buffer = g_new0(gchar, gzip_len);
240+
241+
zstr.next_in = NULL;
242+
zstr.avail_in = 0;
243+
zstr.zalloc = Z_NULL;
244+
zstr.zfree = Z_NULL;
245+
zstr.opaque = 0;
246+
gzip_err = inflateInit2(&zstr, MAX_WBITS+32);
247+
if (gzip_err != Z_OK)
248+
{
249+
g_free(data_buffer);
250+
purple_debug_error("slack", "no built-in gzip support in zlib\n");
251+
return NULL;
252+
}
253+
254+
zstr.next_in = (Bytef *)gzip_data;
255+
zstr.avail_in = gzip_data_len;
256+
257+
zstr.next_out = (Bytef *)data_buffer;
258+
zstr.avail_out = gzip_len;
259+
260+
gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
261+
262+
if (gzip_err == Z_DATA_ERROR)
263+
{
264+
inflateEnd(&zstr);
265+
gzip_err = inflateInit2(&zstr, -MAX_WBITS);
266+
if (gzip_err != Z_OK)
267+
{
268+
g_free(data_buffer);
269+
purple_debug_error("slack", "Cannot decode gzip header\n");
270+
return NULL;
271+
}
272+
zstr.next_in = (Bytef *)gzip_data;
273+
zstr.avail_in = gzip_data_len;
274+
zstr.next_out = (Bytef *)data_buffer;
275+
zstr.avail_out = gzip_len;
276+
gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
277+
}
278+
output_string = g_string_new("");
279+
while (gzip_err == Z_OK)
280+
{
281+
//append data to buffer
282+
output_string = g_string_append_len(output_string, data_buffer, gzip_len - zstr.avail_out);
283+
//reset buffer pointer
284+
zstr.next_out = (Bytef *)data_buffer;
285+
zstr.avail_out = gzip_len;
286+
gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
287+
}
288+
if (gzip_err == Z_STREAM_END)
289+
{
290+
output_string = g_string_append_len(output_string, data_buffer, gzip_len - zstr.avail_out);
291+
} else {
292+
purple_debug_error("slack", "gzip inflate error\n");
293+
}
294+
inflateEnd(&zstr);
295+
296+
g_free(data_buffer);
297+
298+
if (len_ptr)
299+
*len_ptr = output_string->len;
300+
301+
return g_string_free(output_string, FALSE);
302+
}

0 commit comments

Comments
 (0)