Tue, 23 Oct 2012 01:13:04 +0200
HTTP API: PurpleHttpContentReader support
| libpurple/http.c | file | annotate | diff | comparison | revisions | |
| libpurple/http.h | file | annotate | diff | comparison | revisions |
--- a/libpurple/http.c Mon Oct 22 21:11:30 2012 +0200 +++ b/libpurple/http.c Tue Oct 23 01:13:04 2012 +0200 @@ -33,6 +33,7 @@ #define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\\^-" #define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 10240 +#define PURPLE_HTTP_MAX_READ_BUFFER_LEN 10240 #define PURPLE_HTTP_REQUEST_DEFAULT_MAX_REDIRECTS 20 #define PURPLE_HTTP_REQUEST_DEFAULT_TIMEOUT 30 @@ -63,6 +64,8 @@ gchar *contents; int contents_length; + PurpleHttpContentReader contents_reader; + gpointer contents_reader_data; int timeout; int max_redirects; @@ -86,6 +89,9 @@ gboolean main_header_got, headers_got; GString *response_buffer; + GString *contents_reader_buffer; + gboolean contents_reader_requested; + int redirects_count; int data_length_got; @@ -916,6 +922,33 @@ _purple_http_recv(_hc, -1, cond); } +static void _purple_http_send_got_data(PurpleHttpConnection *hc, + gboolean success, gboolean eof, size_t stored) +{ + int estimated_length; + + g_return_if_fail(hc != NULL); + + if (!success) { + _purple_http_error(hc, _("Error requesting data to write")); + return; + } + + hc->contents_reader_requested = FALSE; + g_string_set_size(hc->contents_reader_buffer, stored); + if (!eof) + return; + + estimated_length = hc->request_contents_written + stored; + + if (hc->request->contents_length != -1 && + hc->request->contents_length != estimated_length) { + purple_debug_warning("http", + "Invalid amount of data has been written\n"); + } + hc->request->contents_length = estimated_length; +} + static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond) { PurpleHttpConnection *hc = _hc; @@ -924,6 +957,11 @@ const gchar *write_from; gboolean writing_headers; + /* Waiting for data. This could be written more efficiently, by removing + * (and later, adding) hs->inpa. */ + if (hc->contents_reader_requested) + return; + _purple_http_gen_headers(hc); writing_headers = @@ -933,8 +971,26 @@ hc->request_header_written; write_len = hc->request_header->len - hc->request_header_written; + } else if (hc->request->contents_reader) { + if (hc->contents_reader_requested) + return; /* waiting for data */ + if (!hc->contents_reader_buffer) + hc->contents_reader_buffer = g_string_new(""); + if (hc->contents_reader_buffer->len == 0) { + hc->contents_reader_requested = TRUE; + g_string_set_size(hc->contents_reader_buffer, + PURPLE_HTTP_MAX_READ_BUFFER_LEN); + hc->request->contents_reader(hc, + hc->contents_reader_buffer->str, + hc->request_contents_written, + PURPLE_HTTP_MAX_READ_BUFFER_LEN, + hc->request->contents_reader_data, + _purple_http_send_got_data); + return; + } + write_from = hc->contents_reader_buffer->str; + write_len = hc->contents_reader_buffer->len; } else { - /* TODO: write_from - other write methods */ write_from = hc->request->contents + hc->request_contents_written; write_len = hc->request->contents_length - @@ -967,6 +1023,8 @@ return; } else { hc->request_contents_written += written; + if (hc->contents_reader_buffer) + g_string_erase(hc->contents_reader_buffer, 0, written); if (hc->request_contents_written < hc->request->contents_length) return; } @@ -1234,6 +1292,9 @@ purple_http_request_unref(hc->request); purple_http_response_free(hc->response); + if (hc->contents_reader_buffer) + g_string_free(hc->contents_reader_buffer, TRUE); + if (hc->request_header) g_string_free(hc->request_header, TRUE); @@ -1628,6 +1689,9 @@ g_return_if_fail(request != NULL); g_return_if_fail(length >= -1); + request->contents_reader = NULL; + request->contents_reader_data = NULL; + g_free(request->contents); if (contents == NULL || length == 0) { request->contents = NULL; @@ -1641,6 +1705,20 @@ request->contents_length = length; } +void purple_http_request_set_contents_reader(PurpleHttpRequest *request, + PurpleHttpContentReader reader, int contents_length, gpointer user_data) +{ + g_return_if_fail(request != NULL); + g_return_if_fail(reader != NULL); + g_return_if_fail(contents_length >= -1); + + g_free(request->contents); + request->contents = NULL; + request->contents_length = contents_length; + request->contents_reader = reader; + request->contents_reader_data = user_data; +} + void purple_http_request_set_timeout(PurpleHttpRequest *request, int timeout) { g_return_if_fail(request != NULL);
--- a/libpurple/http.h Mon Oct 22 21:11:30 2012 +0200 +++ b/libpurple/http.h Tue Oct 23 01:13:04 2012 +0200 @@ -63,7 +63,7 @@ * An callback called after storing data requested by PurpleHttpContentReader. */ typedef void (*PurpleHttpContentReaderCb)(PurpleHttpConnection *http_conn, - gboolean success, size_t stored); + gboolean success, gboolean eof, size_t stored); /** * An callback for getting large request contents (ie. from file stored on @@ -325,13 +325,13 @@ * Sets contents reader for HTTP request, used mainly for possible large * uploads. * - * @param request The request. - * @param reader The reader callback. - * @param user_data The user data to pass to the callback function. + * @param request The request. + * @param reader The reader callback. + * @param contents_size The size of all contents. + * @param user_data The user data to pass to the callback function. */ -/* TODO */ void purple_http_request_set_contents_reader(PurpleHttpRequest *request, - PurpleHttpContentReader reader, gpointer user_data); + PurpleHttpContentReader reader, int contents_length, gpointer user_data); /** * Set contents writer for HTTP response.