aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. David Alan Gilbert <dave@treblig.org>2018-03-25 17:07:50 +0100
committerDr. David Alan Gilbert <dave@treblig.org>2018-03-25 17:12:41 +0100
commit06ea88ed322401cf12e5d4acc854d4883274363b (patch)
tree6b76574e8d3ada650347640d160ca853285d9ba2
parentca2f214e252b2aa176a59b8b7e3f1b52e8df445e (diff)
downloadpurple-matrix-06ea88ed322401cf12e5d4acc854d4883274363b.tar.gz
api: Handle chunked messages
The http_parser handles chunked transfer encoding, but it calls the body handler for each chunk and it's our job to stitch it all back together. Use of on_message_complete suggested by ScottAbbey on github Fixes #72 Signed-off-by: Dr. David Alan Gilbert <dave@treblig.org>
-rw-r--r--matrix-api.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/matrix-api.c b/matrix-api.c
index fd18ce9..71dc39d 100644
--- a/matrix-api.c
+++ b/matrix-api.c
@@ -105,7 +105,7 @@ typedef struct {
gchar *content_type;
gboolean got_headers;
JsonParser *json_parser;
- const char *body;
+ char *body;
size_t body_len;
} MatrixApiResponseParserData;
@@ -134,6 +134,9 @@ static void _response_parser_data_free(MatrixApiResponseParserData *data)
/* free the JSON parser, and all of the node structures */
if(data -> json_parser)
g_object_unref(data -> json_parser);
+ g_free(data->body);
+ data->body = NULL;
+
g_free(data);
}
@@ -203,37 +206,47 @@ static int _handle_headers_complete(http_parser *http_parser)
/**
* callback from the http parser which handles the message body
+ * Can be called multiple times as we accumulate chunks.
*/
static int _handle_body(http_parser *http_parser, const char *at,
size_t length)
{
MatrixApiResponseParserData *response_data = http_parser->data;
- GError *err = NULL;
-
if(purple_debug_is_verbose())
purple_debug_info("matrixprpl", "Handling API response body %.*s\n",
(int)length, at);
+ response_data->body = g_realloc(response_data->body,
+ response_data->body_len + length);
+ memcpy(response_data->body + response_data->body_len, at, length);
+ response_data->body_len += length;
+
+ return 0;
+}
+
+/**
+ * callback from the http parser after all chunks have arrived.
+ */
+static int _handle_message_complete(http_parser *http_parser)
+{
+ MatrixApiResponseParserData *response_data = http_parser->data;
+ GError *err = NULL;
+
if(strcmp(response_data->content_type, "application/json") == 0) {
- if(!json_parser_load_from_data(response_data -> json_parser, at, length,
+ if(!json_parser_load_from_data(response_data -> json_parser,
+ response_data->body,
+ response_data->body_len,
&err)) {
purple_debug_info("matrixprpl", "unable to parse JSON: %s\n",
err->message);
g_error_free(err);
return 1;
}
- } else {
- /* Well if it's not JSON perhaps the callback is expecting to
- * handle it itself, e.g. for an image.
- */
- response_data->body = at;
- response_data->body_len = length;
}
return 0;
}
-
/**
* The callback we give to purple_util_fetch_url_request - does some
* initial processing of the response
@@ -270,6 +283,7 @@ static void matrix_api_complete(PurpleUtilFetchUrlData *url_data,
http_parser_settings.on_header_value = _handle_header_value;
http_parser_settings.on_headers_complete = _handle_headers_complete;
http_parser_settings.on_body = _handle_body;
+ http_parser_settings.on_message_complete = _handle_message_complete;
http_parser_init(&http_parser, HTTP_RESPONSE);
http_parser.data = response_data;