diff --git a/src/matrix-api.c b/src/matrix-api.c index b649422..ec494e8 100644 --- a/src/matrix-api.c +++ b/src/matrix-api.c @@ -106,11 +106,16 @@ /** * MatrixAPICallback: * @api: A #MatrixAPI implementation - * @content: the JSON content of the response, as a #JsonNode - * @data: User data specified when calling original request function - * @err: a #GError + * @content_type: the content_type of the response + * @json_content: (allow-none): the JSON content of the response, as a + * #JsonNode + * @raw_content: (allow-none): the raw content of the response + * @user_data: User data specified when calling original request function + * @err: a #GError. It will hold any errors from the underlying API + * (including communication or type errors) * - * A callback function to use with API calls. + * A callback function to use with API calls. Either @json_content or + * @raw_content will be set. */ G_DEFINE_INTERFACE(MatrixAPI, matrix_api, G_TYPE_OBJECT); diff --git a/src/matrix-api.h b/src/matrix-api.h index 5e686e8..c37e296 100644 --- a/src/matrix-api.h +++ b/src/matrix-api.h @@ -35,8 +35,10 @@ typedef struct _MatrixAPIInterface MatrixAPIInterface; typedef struct _MatrixAPI MatrixAPI; typedef void (*MatrixAPICallback)(MatrixAPI *api, - JsonNode *content, - gpointer data, + const gchar *content_type, + JsonNode *json_content, + GByteArray *raw_content, + gpointer user_data, GError *err); struct _MatrixAPIInterface { diff --git a/src/matrix-http-api.c b/src/matrix-http-api.c index 1fa944e..958c136 100644 --- a/src/matrix-http-api.c +++ b/src/matrix-http-api.c @@ -75,6 +75,7 @@ typedef struct { JsonNode *request_content; MatrixAPICallback callback; gpointer callback_data; + gboolean accept_non_json; } MatrixHTTPAPIRequest; GParamSpec *obj_properties[N_PROPERTIES] = {NULL,}; @@ -455,6 +456,7 @@ _response_callback(SoupSession *session, MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); GError *err = NULL; JsonNode *content = NULL; + GByteArray *raw_content = NULL; if (msg->status_code < SOUP_STATUS_CONTINUE) { err = g_error_new(MATRIX_API_ERROR, @@ -467,6 +469,9 @@ _response_callback(SoupSession *session, const guint8 *data; gsize datalen; JsonParser *parser; + SoupURI *request_uri = soup_message_get_uri(msg); + const gchar *request_url = soup_uri_get_path(request_uri) + + strlen(API_ENDPOINT); buffer = soup_message_body_flatten(msg->response_body); soup_buffer_get_data(buffer, &data, &datalen); @@ -475,9 +480,7 @@ _response_callback(SoupSession *session, if (json_parser_load_from_data(parser, (const gchar *)data, datalen, &err)) { - SoupURI *request_uri = soup_message_get_uri(msg); - - g_debug("Data (%s): %s", soup_uri_get_path(request_uri) + strlen(API_ENDPOINT), data); + g_debug("Data (%s): %s", request_url, data); content = json_parser_get_root(parser); if (JSON_NODE_HOLDS_OBJECT(content)) { @@ -602,10 +605,18 @@ _response_callback(SoupSession *session, g_debug("Bad response: %s", data); } } else { // Invalid JSON - err = g_error_new(MATRIX_API_ERROR, - MATRIX_API_ERROR_BAD_RESPONSE, - "Malformed response (invalid JSON)"); - g_debug("Malformed response: %s", data); + if (request->accept_non_json) { + raw_content = g_byte_array_sized_new(datalen); + g_byte_array_append(raw_content, data, datalen); + g_debug("Binary data (%s): %" G_GSIZE_FORMAT " bytes", + request_url, + datalen); + } else { + err = g_error_new(MATRIX_API_ERROR, + MATRIX_API_ERROR_BAD_RESPONSE, + "Malformed response (invalid JSON)"); + g_debug("Malformed response (%s): %s", request_url, data); + } } } @@ -613,7 +624,11 @@ _response_callback(SoupSession *session, if (request->callback) { request->callback( MATRIX_API(api), + soup_message_headers_get_content_type( + msg->response_headers, + NULL), content, + raw_content, request->callback_data, err); } @@ -651,6 +666,7 @@ _send(MatrixHTTPAPI *api, const gchar *path, GHashTable *params, const JsonNode *content, + gboolean accept_non_json, GError **error) { MatrixHTTPAPIPrivate *priv = matrix_http_api_get_instance_private(api); @@ -728,6 +744,7 @@ _send(MatrixHTTPAPI *api, request->api = api; request->callback = callback; request->callback_data = user_data; + request->accept_non_json = accept_non_json; soup_session_queue_message(priv->soup_session, message, @@ -753,7 +770,7 @@ i_login(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "POST", "login", NULL, body, - error); + FALSE, error); } static void @@ -886,7 +903,7 @@ i_create_room(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "POST", "createRoom", NULL, body, - error); + FALSE, error); } static void @@ -912,7 +929,7 @@ i_initial_sync(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "GET", "initialSync", params, NULL, - err); + FALSE, err); } static void @@ -939,7 +956,7 @@ i_event_stream(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "GET", "events", params, NULL, - err); + FALSE, err); } static void @@ -958,7 +975,7 @@ i_leave_room(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "POST", path, NULL, NULL, - error); + FALSE, error); g_free(path); } @@ -971,7 +988,7 @@ i_list_public_rooms(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "GET", "publicRooms", NULL, NULL, - error); + FALSE, error); } static void @@ -999,7 +1016,7 @@ i_join_room(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "POST", path, NULL, NULL, - error); + FALSE, error); g_free(path); } @@ -1020,7 +1037,7 @@ i_get_presence_list(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "GET", path, NULL, NULL, - error); + FALSE, error); g_free(path); } @@ -1041,7 +1058,7 @@ i_get_user_presence(MatrixAPI *api, _send(MATRIX_HTTP_API(api), callback, user_data, "GET", path, NULL, NULL, - error); + FALSE, error); g_free(path); } diff --git a/src/test-client.c b/src/test-client.c index 3ff9be6..d29b9f7 100644 --- a/src/test-client.c +++ b/src/test-client.c @@ -38,8 +38,10 @@ static GOptionEntry entries[] = { static void initial_sync_finished(MatrixAPI *api, - JsonNode *content, - gpointer data, + const gchar *content_type, + JsonNode *json_content, + GByteArray *raw_content, + gpointer user_data, GError *err) { g_printf("initialSync finished\n"); @@ -49,7 +51,9 @@ initial_sync_finished(MatrixAPI *api, static void create_room_finished(MatrixAPI *api, - JsonNode *content, + const gchar *content_type, + JsonNode *json_content, + GByteArray *raw_content, gpointer data, GError *err) { @@ -65,7 +69,9 @@ create_room_finished(MatrixAPI *api, static void get_user_presence_finished(MatrixAPI *api, + const gchar *content_type, JsonNode *json_content, + GByteArray *raw_content, gpointer data, GError *err) { @@ -83,16 +89,16 @@ get_user_presence_finished(MatrixAPI *api, soup_uri_get_scheme(avatar_uri), soup_uri_get_host(avatar_uri), soup_uri_get_path(avatar_uri)); - matrix_api_media_download(api, - NULL, NULL, - soup_uri_get_host(avatar_uri), - soup_uri_get_path(avatar_uri) + 1, - NULL); soup_uri_free(avatar_uri); } static void -login_finished(MatrixAPI *api, JsonNode *content, gpointer data, GError *err) +login_finished(MatrixAPI *api, + const gchar *content_type, + JsonNode *json_content, + GByteArray *raw_content, + gpointer data, + GError *err) { JsonPath *path = json_path_new(); JsonNode *result; @@ -108,7 +114,7 @@ login_finished(MatrixAPI *api, JsonNode *content, gpointer data, GError *err) json_path_compile(path, "$.user_id", NULL); - if ((result = json_path_match(path, content)) != NULL) { + if ((result = json_path_match(path, json_content)) != NULL) { JsonArray *array = json_node_get_array(result); const gchar *user_id;