pidgin/pidgin

3e35de3c9afa
Merged in qulogic/pidgin (pull request #607)

Delete HTTP code

Approved-by: Gary Kramlich
--- a/ChangeLog.API Fri Oct 18 01:33:51 2019 +0000
+++ b/ChangeLog.API Fri Oct 18 04:19:09 2019 +0000
@@ -417,8 +417,6 @@
* PurpleEventLoopUiOps. Manually drive the GLib event loop
yourself. See GLib Main Event Loop docs.
* purple_get_tzoff_str(). Use g_date_time_format, instead.
- * purple_http_digest_calculate_response
- * purple_http_digest_calculate_session_key
* purple_ip_address_is_valid, purple_ipv4_address_is_valid, and
purple_ipv6_address_is_valid. Use g_hostname_is_ip_address()
or #GInetAddress instead.
--- a/doc/reference/libpurple/libpurple-docs.xml Fri Oct 18 01:33:51 2019 +0000
+++ b/doc/reference/libpurple/libpurple-docs.xml Fri Oct 18 04:19:09 2019 +0000
@@ -48,7 +48,6 @@
<xi:include href="xml/eventloop.xml" />
<xi:include href="xml/group.xml" />
<xi:include href="xml/xfer.xml" />
- <xi:include href="xml/http.xml" />
<xi:include href="xml/idle.xml" />
<xi:include href="xml/keyring.xml" />
<xi:include href="xml/memorypool.xml" />
--- a/finch/plugins/gnttinyurl.c Fri Oct 18 01:33:51 2019 +0000
+++ b/finch/plugins/gnttinyurl.c Fri Oct 18 04:19:09 2019 +0000
@@ -26,7 +26,6 @@
#define PREF_URL PREFS_BASE "/url"
#include <conversation.h>
-#include <http.h>
#include <signals.h>
#include <glib.h>
--- a/libpurple/connection.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/connection.c Fri Oct 18 04:19:09 2019 +0000
@@ -27,7 +27,6 @@
#include "connection.h"
#include "debug.h"
#include "enums.h"
-#include "http.h"
#include "log.h"
#include "notify.h"
#include "prefs.h"
@@ -869,7 +868,6 @@
buddies = g_slist_delete_link(buddies, buddies);
}
- purple_http_conn_cancel_all(gc);
purple_proxy_connect_cancel_with_handle(gc);
connections = g_list_remove(connections, gc);
--- a/libpurple/core.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/core.c Fri Oct 18 04:19:09 2019 +0000
@@ -26,7 +26,6 @@
#include "debug.h"
#include "xfer.h"
#include "glibcompat.h"
-#include "http.h"
#include "idle.h"
#include "image-store.h"
#include "keyring.h"
@@ -177,7 +176,6 @@
purple_stun_init();
purple_xfers_init();
purple_idle_init();
- purple_http_init();
_purple_smiley_custom_init();
_purple_smiley_parser_init();
@@ -219,7 +217,6 @@
_purple_smiley_theme_uninit();
_purple_smiley_custom_uninit();
_purple_smiley_parser_uninit();
- purple_http_uninit();
purple_idle_uninit();
purple_pounces_uninit();
purple_conversations_uninit();
--- a/libpurple/http.c Fri Oct 18 01:33:51 2019 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3430 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#include "http.h"
-
-#include "internal.h"
-#include "glibcompat.h"
-
-
-#include "debug.h"
-#include "proxy.h"
-#include "purple-gio.h"
-
-#define PURPLE_HTTP_URL_CREDENTIALS_CHARS "a-z0-9.,~_/*!&%?=+\\^-"
-#define PURPLE_HTTP_MAX_RECV_BUFFER_LEN 102400
-#define PURPLE_HTTP_MAX_READ_BUFFER_LEN 102400
-#define PURPLE_HTTP_GZ_BUFF_LEN 1024
-
-#define PURPLE_HTTP_REQUEST_DEFAULT_MAX_REDIRECTS 20
-#define PURPLE_HTTP_REQUEST_DEFAULT_TIMEOUT 30
-#define PURPLE_HTTP_REQUEST_DEFAULT_MAX_LENGTH 1048576
-#define PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH (G_MAXINT32 - 1)
-
-#define PURPLE_HTTP_PROGRESS_WATCHER_DEFAULT_INTERVAL 250000
-
-#define PURPLE_HTTP_GET_ACCOUNT(gc) (gc ? purple_connection_get_account(gc) : NULL)
-
-typedef struct _PurpleHttpSocket PurpleHttpSocket;
-
-typedef struct _PurpleHttpHeaders PurpleHttpHeaders;
-
-typedef struct _PurpleHttpKeepaliveHost PurpleHttpKeepaliveHost;
-
-typedef struct _PurpleHttpKeepaliveRequest PurpleHttpKeepaliveRequest;
-
-typedef struct _PurpleHttpGzStream PurpleHttpGzStream;
-
-typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs,
- const gchar *error, gpointer _hc);
-
-struct _PurpleHttpSocket
-{
- GSocketConnection *conn;
- GCancellable *cancellable;
- guint input_source;
- guint output_source;
-
- gboolean is_busy;
- guint use_count;
- PurpleHttpKeepaliveHost *host;
-};
-
-struct _PurpleHttpRequest
-{
- int ref_count;
-
- gchar *url;
- gchar *method;
- PurpleHttpHeaders *headers;
- PurpleHttpCookieJar *cookie_jar;
- PurpleHttpKeepalivePool *keepalive_pool;
-
- gchar *contents;
- int contents_length;
- PurpleHttpContentReader contents_reader;
- gpointer contents_reader_data;
- PurpleHttpContentWriter response_writer;
- gpointer response_writer_data;
-
- int timeout;
- int max_redirects;
- gboolean http11;
- guint max_length;
-};
-
-struct _PurpleHttpConnection
-{
- PurpleConnection *gc;
- PurpleHttpCallback callback;
- gpointer user_data;
- gboolean is_reading;
- gboolean is_keepalive;
- gboolean is_cancelling;
-
- PurpleHttpURL *url;
- PurpleHttpRequest *request;
- PurpleHttpResponse *response;
-
- PurpleHttpKeepaliveRequest *socket_request;
- PurpleHttpConnectionSet *connection_set;
- PurpleHttpSocket *socket;
- GString *request_header;
- guint request_header_written, request_contents_written;
- gboolean main_header_got, headers_got;
- GString *response_buffer;
- PurpleHttpGzStream *gz_stream;
-
- GString *contents_reader_buffer;
- gboolean contents_reader_requested;
-
- int redirects_count;
-
- int length_expected;
- guint length_got, length_got_decompressed;
-
- gboolean is_chunked, in_chunk, chunks_done;
- int chunk_length, chunk_got;
-
- GList *link_global, *link_gc;
-
- guint timeout_handle;
-
- PurpleHttpProgressWatcher watcher;
- gpointer watcher_user_data;
- guint watcher_interval_threshold;
- gint64 watcher_last_call;
- guint watcher_delayed_handle;
-};
-
-struct _PurpleHttpResponse
-{
- int code;
- gchar *error;
-
- GString *contents;
- PurpleHttpHeaders *headers;
-};
-
-struct _PurpleHttpURL
-{
- gchar *protocol;
- gchar *username;
- gchar *password;
- gchar *host;
- int port;
- gchar *path;
- gchar *fragment;
-};
-
-struct _PurpleHttpHeaders
-{
- GList *list;
- GHashTable *by_name;
-};
-
-typedef struct
-{
- time_t expires;
- gchar *value;
-} PurpleHttpCookie;
-
-struct _PurpleHttpCookieJar
-{
- int ref_count;
-
- GHashTable *tab;
-};
-
-struct _PurpleHttpKeepaliveRequest
-{
- PurpleConnection *gc;
- PurpleHttpSocketConnectCb cb;
- gpointer user_data;
-
- PurpleHttpKeepaliveHost *host;
- PurpleHttpSocket *hs;
-};
-
-struct _PurpleHttpKeepaliveHost
-{
- PurpleHttpKeepalivePool *pool;
-
- gchar *host;
- int port;
- gboolean is_ssl;
-
- GSList *sockets; /* list of PurpleHttpSocket */
-
- GSList *queue; /* list of PurpleHttpKeepaliveRequest */
- guint process_queue_timeout;
-};
-
-struct _PurpleHttpKeepalivePool
-{
- gboolean is_destroying;
-
- int ref_count;
-
- guint limit_per_host;
-
- /* key: purple_http_socket_hash, value: PurpleHttpKeepaliveHost */
- GHashTable *by_hash;
-};
-
-struct _PurpleHttpConnectionSet
-{
- gboolean is_destroying;
-
- GHashTable *connections;
-};
-
-struct _PurpleHttpGzStream
-{
- gboolean failed;
- GZlibDecompressor *decompressor;
- gsize max_output;
- gsize decompressed;
- GString *pending;
-};
-
-struct _ntlm_type1_message {
- guint8 protocol[8]; /* 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' */
- guint32 type; /* 0x00000001 */
- guint32 flags; /* 0x0000b203 */
-
- guint16 dom_len1; /* domain string length */
- guint16 dom_len2; /* domain string length */
- guint32 dom_off; /* domain string offset */
-
- guint16 host_len1; /* host string length */
- guint16 host_len2; /* host string length */
- guint32 host_off; /* host string offset (always 0x00000020) */
-};
-
-static time_t purple_http_rfc1123_to_time(const gchar *str);
-
-static gboolean purple_http_request_is_method(PurpleHttpRequest *request,
- const gchar *method);
-
-static PurpleHttpConnection * purple_http_connection_new(
- PurpleHttpRequest *request, PurpleConnection *gc);
-static void purple_http_connection_terminate(PurpleHttpConnection *hc);
-static void purple_http_conn_notify_progress_watcher(PurpleHttpConnection *hc);
-static void
-purple_http_conn_retry(PurpleHttpConnection *http_conn);
-
-static PurpleHttpResponse * purple_http_response_new(void);
-static void purple_http_response_free(PurpleHttpResponse *response);
-
-static void purple_http_cookie_jar_parse(PurpleHttpCookieJar *cookie_jar,
- GList *values);
-static gchar * purple_http_cookie_jar_gen(PurpleHttpCookieJar *cookie_jar);
-gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar);
-
-static PurpleHttpKeepaliveRequest *
-purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
- PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
- PurpleHttpSocketConnectCb cb, gpointer user_data);
-static void
-purple_http_keepalive_pool_request_cancel(PurpleHttpKeepaliveRequest *req);
-static void
-purple_http_keepalive_pool_release(PurpleHttpSocket *hs, gboolean invalidate);
-
-static void
-purple_http_connection_set_remove(PurpleHttpConnectionSet *set,
- PurpleHttpConnection *http_conn);
-
-static GRegex *purple_http_re_url, *purple_http_re_url_host,
- *purple_http_re_rfc1123;
-
-/*
- * Values: pointers to running PurpleHttpConnection.
- */
-static GList *purple_http_hc_list;
-
-/*
- * Keys: pointers to PurpleConnection.
- * Values: GList of pointers to running PurpleHttpConnection.
- */
-static GHashTable *purple_http_hc_by_gc;
-
-/*
- * Keys: pointers to PurpleConnection.
- * Values: gboolean TRUE.
- */
-static GHashTable *purple_http_cancelling_gc;
-
-/*
- * Keys: pointers to PurpleHttpConnection.
- * Values: pointers to links in purple_http_hc_list.
- */
-static GHashTable *purple_http_hc_by_ptr;
-
-/*** Helper functions *********************************************************/
-
-static time_t purple_http_rfc1123_to_time(const gchar *str)
-{
- static const gchar *months[13] = {
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec", NULL
- };
- GMatchInfo *match_info;
- gchar *d_date, *d_month, *d_year, *d_time;
- int month;
- gchar *iso_date;
- time_t t;
-
- g_return_val_if_fail(str != NULL, 0);
-
- g_regex_match(purple_http_re_rfc1123, str, 0, &match_info);
- if (!g_match_info_matches(match_info)) {
- g_match_info_free(match_info);
- return 0;
- }
-
- d_date = g_match_info_fetch(match_info, 1);
- d_month = g_match_info_fetch(match_info, 2);
- d_year = g_match_info_fetch(match_info, 3);
- d_time = g_match_info_fetch(match_info, 4);
-
- g_match_info_free(match_info);
-
- month = 0;
- while (months[month] != NULL) {
- if (0 == g_ascii_strcasecmp(d_month, months[month]))
- break;
- month++;
- }
- month++;
-
- iso_date = g_strdup_printf("%s-%02d-%sT%s+00:00",
- d_year, month, d_date, d_time);
-
- g_free(d_date);
- g_free(d_year);
- g_free(d_time);
-
- if (month > 12) {
- purple_debug_warning("http", "Invalid month: %s\n", d_month);
- g_free(d_month);
- g_free(iso_date);
- return 0;
- }
-
- g_free(d_month);
-
- t = purple_str_to_time(iso_date, TRUE, NULL, NULL, NULL);
-
- g_free(iso_date);
-
- return t;
-}
-
-/*** GZip streams *************************************************************/
-
-static PurpleHttpGzStream *
-purple_http_gz_new(gsize max_output, gboolean is_deflate)
-{
- PurpleHttpGzStream *gzs = g_new0(PurpleHttpGzStream, 1);
- GZlibCompressorFormat format;
-
- if (is_deflate)
- format = G_ZLIB_COMPRESSOR_FORMAT_RAW;
- else /* is gzip */
- format = G_ZLIB_COMPRESSOR_FORMAT_GZIP;
-
- gzs->decompressor = g_zlib_decompressor_new(format);
- gzs->max_output = max_output;
-
- return gzs;
-}
-
-static GString *
-purple_http_gz_put(PurpleHttpGzStream *gzs, const gchar *buf, gsize len)
-{
- const gchar *compressed_buff;
- gsize compressed_len;
- GString *ret;
-
- g_return_val_if_fail(gzs != NULL, NULL);
- g_return_val_if_fail(buf != NULL, NULL);
-
- if (gzs->failed)
- return NULL;
-
- if (gzs->pending) {
- g_string_append_len(gzs->pending, buf, len);
- compressed_buff = gzs->pending->str;
- compressed_len = gzs->pending->len;
- } else {
- compressed_buff = buf;
- compressed_len = len;
- }
-
- ret = g_string_new(NULL);
- while (compressed_len > 0) {
- GConverterResult gzres;
- gchar decompressed_buff[PURPLE_HTTP_GZ_BUFF_LEN];
- gsize decompressed_len = 0;
- gsize bytes_read = 0;
- GError *error = NULL;
-
- gzres = g_converter_convert(G_CONVERTER(gzs->decompressor),
- compressed_buff, compressed_len,
- decompressed_buff, sizeof(decompressed_buff),
- G_CONVERTER_NO_FLAGS,
- &bytes_read,
- &decompressed_len,
- &error);
-
- compressed_buff += bytes_read;
- compressed_len -= bytes_read;
-
- if (gzres == G_CONVERTER_CONVERTED || gzres == G_CONVERTER_FINISHED) {
- if (decompressed_len == 0)
- break;
- if (gzs->decompressed + decompressed_len >=
- gzs->max_output)
- {
- purple_debug_warning("http", "Maximum amount of"
- " decompressed data is reached\n");
- decompressed_len = gzs->max_output -
- gzs->decompressed;
- gzres = G_CONVERTER_FINISHED;
- }
- gzs->decompressed += decompressed_len;
- g_string_append_len(ret, decompressed_buff,
- decompressed_len);
- if (gzres == G_CONVERTER_FINISHED)
- break;
- } else {
- purple_debug_error("http",
- "Decompression failed (%d): %s\n", gzres,
- error->message);
- g_clear_error(&error);
- gzs->failed = TRUE;
- g_string_free(ret, TRUE);
- return NULL;
- }
- }
-
- if (gzs->pending) {
- g_string_free(gzs->pending, TRUE);
- gzs->pending = NULL;
- }
-
- if (compressed_len > 0) {
- gzs->pending = g_string_new_len(compressed_buff,
- compressed_len);
- }
-
- return ret;
-}
-
-static void
-purple_http_gz_free(PurpleHttpGzStream *gzs)
-{
- if (gzs == NULL)
- return;
- g_object_unref(gzs->decompressor);
- if (gzs->pending)
- g_string_free(gzs->pending, TRUE);
- g_free(gzs);
-}
-
-/*** NTLM *********************************************************************/
-
-/**
- * purple_ntlm_gen_type1:
- * @hostname: Your hostname
- * @domain: The domain to authenticate to
- *
- * Generates the base64 encoded type 1 message needed for NTLM authentication
- *
- * Returns: base64 encoded string to send to the server. This should
- * be g_free'd by the caller.
- */
-static gchar *
-purple_http_ntlm_gen_type1(const gchar *hostname, const gchar *domain)
-{
- int hostnamelen,host_off;
- int domainlen,dom_off;
- unsigned char *msg;
- struct _ntlm_type1_message *tmsg;
- gchar *tmp;
-
- hostnamelen = strlen(hostname);
- domainlen = strlen(domain);
- host_off = sizeof(struct _ntlm_type1_message);
- dom_off = sizeof(struct _ntlm_type1_message) + hostnamelen;
- msg = g_malloc0(sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen);
- tmsg = (struct _ntlm_type1_message*)(gpointer)msg;
- tmsg->protocol[0] = 'N';
- tmsg->protocol[1] = 'T';
- tmsg->protocol[2] = 'L';
- tmsg->protocol[3] = 'M';
- tmsg->protocol[4] = 'S';
- tmsg->protocol[5] = 'S';
- tmsg->protocol[6] = 'P';
- tmsg->protocol[7] = '\0';
- tmsg->type = GUINT32_TO_LE(0x00000001);
- tmsg->flags = GUINT32_TO_LE(0x0000b203);
- tmsg->dom_len1 = tmsg->dom_len2 = GUINT16_TO_LE(domainlen);
- tmsg->dom_off = GUINT32_TO_LE(dom_off);
- tmsg->host_len1 = tmsg->host_len2 = GUINT16_TO_LE(hostnamelen);
- tmsg->host_off = GUINT32_TO_LE(host_off);
- memcpy(msg + host_off, hostname, hostnamelen);
- memcpy(msg + dom_off, domain, domainlen);
-
- tmp = g_base64_encode(msg, sizeof(struct _ntlm_type1_message) + hostnamelen + domainlen);
- g_free(msg);
-
- return tmp;
-}
-
-/*** HTTP Sockets *************************************************************/
-
-static gchar *
-purple_http_socket_hash(const gchar *host, int port, gboolean is_ssl)
-{
- return g_strdup_printf("%c:%s:%d", (is_ssl ? 'S' : 'R'), host, port);
-}
-
-static void
-purple_http_socket_connect_new_cb(GObject *source, GAsyncResult *res,
- gpointer user_data)
-{
- PurpleHttpSocket *hs = user_data;
- GSocketConnection *conn;
- PurpleHttpSocketConnectCb cb;
- gpointer cb_data;
- GError *error = NULL;
-
- conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
- res, &error);
-
- cb = g_object_steal_data(source, "cb");
- cb_data = g_object_steal_data(source, "cb_data");
-
- if (conn == NULL) {
- if (!g_error_matches(error,
- G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- cb(hs, error->message, cb_data);
- }
-
- g_clear_error(&error);
- return;
- }
-
- hs->conn = conn;
-
- cb(hs, NULL, cb_data);
-}
-
-static PurpleHttpSocket *
-purple_http_socket_connect_new(PurpleConnection *gc, const gchar *host,
- int port, gboolean is_ssl,
- PurpleHttpSocketConnectCb cb, gpointer user_data)
-{
- PurpleHttpSocket *hs;
- GSocketClient *client;
- GError *error = NULL;
-
- client = purple_gio_socket_client_new(PURPLE_HTTP_GET_ACCOUNT(gc), &error);
-
- if (client == NULL) {
- purple_debug_error("http", "Error connecting to '%s:%d': %s",
- host, port, error->message);
- g_clear_error(&error);
- return NULL;
- }
-
- hs = g_new0(PurpleHttpSocket, 1);
- hs->cancellable = g_cancellable_new();
-
- g_socket_client_set_tls(client, is_ssl);
- g_object_set_data(G_OBJECT(client), "cb", cb);
- g_object_set_data(G_OBJECT(client), "cb_data", user_data);
-
- g_socket_client_connect_to_host_async(client,
- host, port, hs->cancellable,
- purple_http_socket_connect_new_cb, hs);
-
- g_object_unref(client);
-
- if (purple_debug_is_verbose())
- purple_debug_misc("http", "new socket created: %p\n", hs);
-
- return hs;
-}
-
-static void
-purple_http_socket_close_free(PurpleHttpSocket *hs)
-{
- if (hs == NULL)
- return;
-
- if (purple_debug_is_verbose())
- purple_debug_misc("http", "destroying socket: %p\n", hs);
-
- if (hs->input_source > 0) {
- g_source_remove(hs->input_source);
- hs->input_source = 0;
- }
-
- if (hs->output_source > 0) {
- g_source_remove(hs->output_source);
- hs->output_source = 0;
- }
-
- if (hs->cancellable != NULL) {
- g_cancellable_cancel(hs->cancellable);
- g_clear_object(&hs->cancellable);
- }
-
- if (hs->conn != NULL) {
- purple_gio_graceful_close(G_IO_STREAM(hs->conn), NULL, NULL);
- g_clear_object(&hs->conn);
- }
-
- g_free(hs);
-}
-
-/*** Headers collection *******************************************************/
-
-static PurpleHttpHeaders * purple_http_headers_new(void);
-static void purple_http_headers_free(PurpleHttpHeaders *hdrs);
-static void purple_http_headers_add(PurpleHttpHeaders *hdrs, const gchar *key,
- const gchar *value);
-static const GList * purple_http_headers_get_all(PurpleHttpHeaders *hdrs);
-static GList * purple_http_headers_get_all_by_name(
- PurpleHttpHeaders *hdrs, const gchar *key);
-static const gchar * purple_http_headers_get(PurpleHttpHeaders *hdrs,
- const gchar *key);
-static gboolean purple_http_headers_get_int(PurpleHttpHeaders *hdrs,
- const gchar *key, int *dst);
-static gboolean purple_http_headers_match(PurpleHttpHeaders *hdrs,
- const gchar *key, const gchar *value);
-static gchar * purple_http_headers_dump(PurpleHttpHeaders *hdrs);
-
-static PurpleHttpHeaders * purple_http_headers_new(void)
-{
- PurpleHttpHeaders *hdrs = g_new0(PurpleHttpHeaders, 1);
-
- hdrs->by_name = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- (GDestroyNotify)g_list_free);
-
- return hdrs;
-}
-
-static void purple_http_headers_free_kvp(PurpleKeyValuePair *kvp)
-{
- g_free(kvp->key);
- g_free(kvp->value);
- g_free(kvp);
-}
-
-static void purple_http_headers_free(PurpleHttpHeaders *hdrs)
-{
- if (hdrs == NULL)
- return;
-
- g_hash_table_destroy(hdrs->by_name);
- g_list_free_full(hdrs->list,
- (GDestroyNotify)purple_http_headers_free_kvp);
- g_free(hdrs);
-}
-
-static void purple_http_headers_add(PurpleHttpHeaders *hdrs, const gchar *key,
- const gchar *value)
-{
- PurpleKeyValuePair *kvp;
- GList *named_values, *new_values;
- gchar *key_low;
-
- g_return_if_fail(hdrs != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(value != NULL);
-
- kvp = g_new0(PurpleKeyValuePair, 1);
- kvp->key = g_strdup(key);
- kvp->value = g_strdup(value);
- hdrs->list = g_list_append(hdrs->list, kvp);
-
- key_low = g_ascii_strdown(key, -1);
- named_values = g_hash_table_lookup(hdrs->by_name, key_low);
- new_values = g_list_append(named_values, kvp->value);
- if (named_values)
- g_free(key_low);
- else
- g_hash_table_insert(hdrs->by_name, key_low, new_values);
-}
-
-static void purple_http_headers_remove(PurpleHttpHeaders *hdrs,
- const gchar *key)
-{
- GList *it, *curr;
-
- g_return_if_fail(hdrs != NULL);
- g_return_if_fail(key != NULL);
-
- if (!g_hash_table_remove(hdrs->by_name, key))
- return;
-
- /* Could be optimized to O(1). */
- it = g_list_first(hdrs->list);
- while (it) {
- PurpleKeyValuePair *kvp = it->data;
- curr = it;
- it = g_list_next(it);
- if (g_ascii_strcasecmp(kvp->key, key) != 0)
- continue;
-
- hdrs->list = g_list_delete_link(hdrs->list, curr);
- purple_http_headers_free_kvp(kvp);
- }
-}
-
-static const GList * purple_http_headers_get_all(PurpleHttpHeaders *hdrs)
-{
- g_return_val_if_fail(hdrs != NULL, NULL);
-
- return hdrs->list;
-}
-
-/* return const */
-static GList * purple_http_headers_get_all_by_name(
- PurpleHttpHeaders *hdrs, const gchar *key)
-{
- GList *values;
- gchar *key_low;
-
- g_return_val_if_fail(hdrs != NULL, NULL);
- g_return_val_if_fail(key != NULL, NULL);
-
- key_low = g_ascii_strdown(key, -1);
- values = g_hash_table_lookup(hdrs->by_name, key_low);
- g_free(key_low);
-
- return values;
-}
-
-static const gchar * purple_http_headers_get(PurpleHttpHeaders *hdrs,
- const gchar *key)
-{
- const GList *values = purple_http_headers_get_all_by_name(hdrs, key);
-
- if (!values)
- return NULL;
-
- return values->data;
-}
-
-static gboolean purple_http_headers_get_int(PurpleHttpHeaders *hdrs,
- const gchar *key, int *dst)
-{
- int val;
- const gchar *str;
-
- str = purple_http_headers_get(hdrs, key);
- if (!str)
- return FALSE;
-
- if (1 != sscanf(str, "%d", &val))
- return FALSE;
-
- *dst = val;
- return TRUE;
-}
-
-static gboolean purple_http_headers_match(PurpleHttpHeaders *hdrs,
- const gchar *key, const gchar *value)
-{
- const gchar *str;
-
- str = purple_http_headers_get(hdrs, key);
- if (str == NULL || value == NULL)
- return str == value;
-
- return (g_ascii_strcasecmp(str, value) == 0);
-}
-
-static gchar * purple_http_headers_dump(PurpleHttpHeaders *hdrs)
-{
- const GList *hdr;
-
- GString *s = g_string_new("");
-
- hdr = purple_http_headers_get_all(hdrs);
- while (hdr) {
- PurpleKeyValuePair *kvp = hdr->data;
- hdr = g_list_next(hdr);
-
- g_string_append_printf(s, "%s: %s%s", kvp->key,
- (gchar*)kvp->value, hdr ? "\n" : "");
- }
-
- return g_string_free(s, FALSE);
-}
-
-/*** HTTP protocol backend ****************************************************/
-
-static void _purple_http_disconnect(PurpleHttpConnection *hc,
- gboolean is_graceful);
-
-static void _purple_http_gen_headers(PurpleHttpConnection *hc);
-static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc);
-static gboolean _purple_http_recv(GObject *source, gpointer _hc);
-static gboolean _purple_http_send(GObject *source, gpointer _hc);
-
-/* closes current connection (if exists), estabilishes one and proceeds with
- * request */
-static gboolean _purple_http_reconnect(PurpleHttpConnection *hc);
-
-static void _purple_http_error(PurpleHttpConnection *hc, const char *format,
- ...) G_GNUC_PRINTF(2, 3);
-
-static void _purple_http_error(PurpleHttpConnection *hc, const char *format,
- ...)
-{
- va_list args;
-
- va_start(args, format);
- hc->response->error = g_strdup_vprintf(format, args);
- va_end(args);
-
- if (purple_debug_is_verbose())
- purple_debug_warning("http", "error: %s\n", hc->response->error);
-
- purple_http_conn_cancel(hc);
-}
-
-static void memset_zero(gpointer pnt, gsize len)
-{
- volatile unsigned char *volatile pnt_ =
- (volatile unsigned char *volatile) pnt;
- size_t i = (size_t) 0U;
-
- while (i < len) {
- pnt_[i++] = 0U;
- }
-}
-
-static void _purple_http_gen_headers(PurpleHttpConnection *hc)
-{
- GString *h;
- PurpleHttpURL *url;
- const GList *hdr;
- PurpleHttpRequest *req;
- PurpleHttpHeaders *hdrs;
- gchar *request_url, *tmp_url = NULL;
-
- PurpleProxyInfo *proxy;
- gboolean proxy_http = FALSE;
- const gchar *proxy_username, *proxy_password;
-
- g_return_if_fail(hc != NULL);
-
- if (hc->request_header != NULL)
- return;
-
- req = hc->request;
- url = hc->url;
- hdrs = req->headers;
- proxy = purple_proxy_get_setup(PURPLE_HTTP_GET_ACCOUNT(hc->gc));
-
- proxy_http = (purple_proxy_info_get_proxy_type(proxy) == PURPLE_PROXY_HTTP ||
- purple_proxy_info_get_proxy_type(proxy) == PURPLE_PROXY_USE_ENVVAR);
- /* this is HTTP proxy, but used with tunelling with CONNECT */
- if (proxy_http && url->port != 80)
- proxy_http = FALSE;
-
- hc->request_header = h = g_string_new("");
- hc->request_header_written = 0;
- hc->request_contents_written = 0;
-
- if (proxy_http)
- request_url = tmp_url = purple_http_url_print(url);
- else
- request_url = url->path;
-
- g_string_append_printf(h, "%s %s HTTP/%s\r\n",
- req->method ? req->method : "GET",
- request_url,
- req->http11 ? "1.1" : "1.0");
-
- g_free(tmp_url);
-
- if (!purple_http_headers_get(hdrs, "host"))
- g_string_append_printf(h, "Host: %s\r\n", url->host);
- if (!purple_http_headers_get(hdrs, "connection")) {
- g_string_append(h, "Connection: ");
- g_string_append(h, hc->is_keepalive ?
- "Keep-Alive\r\n" : "close\r\n");
- }
- if (!purple_http_headers_get(hdrs, "accept"))
- g_string_append(h, "Accept: */*\r\n");
- if (!purple_http_headers_get(hdrs, "accept-encoding"))
- g_string_append(h, "Accept-Encoding: gzip, deflate\r\n");
-
- if (!purple_http_headers_get(hdrs, "content-length") && (
- req->contents_length > 0 ||
- purple_http_request_is_method(req, "post")))
- {
- g_string_append_printf(h, "Content-Length: %u\r\n",
- (guint) req->contents_length);
- }
-
- if (proxy_http)
- g_string_append(h, "Proxy-Connection: close\r\n"); /* TEST: proxy+KeepAlive */
-
- proxy_username = purple_proxy_info_get_username(proxy);
- if (proxy_http && proxy_username != NULL && proxy_username[0] != '\0') {
- gchar *proxy_auth, *ntlm_type1, *tmp;
- int len;
-
- proxy_password = purple_proxy_info_get_password(proxy);
- if (proxy_password == NULL)
- proxy_password = "";
-
- tmp = g_strdup_printf("%s:%s", proxy_username, proxy_password);
- len = strlen(tmp);
- proxy_auth = g_base64_encode((const guchar *)tmp, len);
- memset_zero(tmp, len);
- g_free(tmp);
-
- ntlm_type1 = purple_http_ntlm_gen_type1(purple_get_host_name(),
- "");
-
- g_string_append_printf(h, "Proxy-Authorization: Basic %s\r\n",
- proxy_auth);
- g_string_append_printf(h, "Proxy-Authorization: NTLM %s\r\n",
- ntlm_type1);
- g_string_append(h, "Proxy-Connection: close\r\n"); /* TEST: proxy+KeepAlive */
-
- memset_zero(proxy_auth, strlen(proxy_auth));
- g_free(proxy_auth);
- g_free(ntlm_type1);
- }
-
- hdr = purple_http_headers_get_all(hdrs);
- while (hdr) {
- PurpleKeyValuePair *kvp = hdr->data;
- hdr = g_list_next(hdr);
-
- g_string_append_printf(h, "%s: %s\r\n",
- kvp->key, (gchar*)kvp->value);
- }
-
- if (!purple_http_cookie_jar_is_empty(req->cookie_jar)) {
- gchar * cookies = purple_http_cookie_jar_gen(req->cookie_jar);
- g_string_append_printf(h, "Cookie: %s\r\n", cookies);
- g_free(cookies);
- }
-
- g_string_append_printf(h, "\r\n");
-
- if (purple_debug_is_unsafe() && purple_debug_is_verbose()) {
- purple_debug_misc("http", "Generated request headers:\n%s",
- h->str);
- }
-}
-
-static gboolean _purple_http_recv_headers(PurpleHttpConnection *hc,
- const gchar *buf, int len)
-{
- gchar *eol, *delim;
-
- if (hc->headers_got) {
- purple_debug_error("http", "Headers already got\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
-
- g_string_append_len(hc->response_buffer, buf, len);
- if (hc->response_buffer->len > PURPLE_HTTP_MAX_RECV_BUFFER_LEN) {
- purple_debug_error("http",
- "Buffer too big when parsing headers\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
-
- while ((eol = strstr(hc->response_buffer->str, "\r\n"))
- != NULL)
- {
- gchar *hdrline = hc->response_buffer->str;
- int hdrline_len = eol - hdrline;
-
- hdrline[hdrline_len] = '\0';
-
- if (hdrline[0] == '\0') {
- if (!hc->main_header_got) {
- if (purple_debug_is_verbose() &&
- hc->is_keepalive)
- {
- purple_debug_misc("http", "Got keep-"
- "alive terminator from previous"
- " request\n");
- } else {
- purple_debug_warning("http", "Got empty"
- " line at the beginning - this "
- "may be a HTTP server quirk\n");
- }
- } else /* hc->main_header_got */ {
- hc->headers_got = TRUE;
- if (purple_debug_is_verbose()) {
- purple_debug_misc("http", "Got headers "
- "end\n");
- }
- }
- } else if (!hc->main_header_got) {
- hc->main_header_got = TRUE;
- delim = strchr(hdrline, ' ');
- if (delim == NULL || 1 != sscanf(delim + 1, "%d",
- &hc->response->code))
- {
- purple_debug_warning("http",
- "Invalid response code\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- if (purple_debug_is_verbose())
- purple_debug_misc("http",
- "Got main header with code %d\n",
- hc->response->code);
- } else {
- if (purple_debug_is_verbose() &&
- purple_debug_is_unsafe())
- purple_debug_misc("http", "Got header: %s\n",
- hdrline);
- delim = strchr(hdrline, ':');
- if (delim == NULL || delim == hdrline) {
- purple_debug_warning("http",
- "Bad header delimiter\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- *delim++ = '\0';
- while (*delim == ' ')
- delim++;
-
- purple_http_headers_add(hc->response->headers, hdrline, delim);
- }
-
- g_string_erase(hc->response_buffer, 0, hdrline_len + 2);
- if (hc->headers_got)
- break;
- }
- return TRUE;
-}
-
-static gboolean _purple_http_recv_body_data(PurpleHttpConnection *hc,
- const gchar *buf, int len)
-{
- GString *decompressed = NULL;
-
- if (hc->length_expected >= 0 &&
- len + hc->length_got > (guint)hc->length_expected)
- {
- len = hc->length_expected - hc->length_got;
- }
-
- hc->length_got += len;
-
- if (hc->gz_stream != NULL) {
- decompressed = purple_http_gz_put(hc->gz_stream, buf, len);
- if (decompressed == NULL) {
- _purple_http_error(hc,
- _("Error while decompressing data"));
- return FALSE;
- }
- buf = decompressed->str;
- len = decompressed->len;
- }
-
- g_assert(hc->request->max_length <=
- PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH);
- if (hc->length_got_decompressed + len > hc->request->max_length) {
- purple_debug_warning("http",
- "Maximum length exceeded, truncating\n");
- len = hc->request->max_length - hc->length_got_decompressed;
- hc->length_expected = hc->length_got;
- }
- hc->length_got_decompressed += len;
-
- if (len == 0) {
- if (decompressed != NULL)
- g_string_free(decompressed, TRUE);
- return TRUE;
- }
-
- if (hc->request->response_writer != NULL) {
- gboolean succ;
- succ = hc->request->response_writer(hc, hc->response, buf,
- hc->length_got_decompressed, len,
- hc->request->response_writer_data);
- if (!succ) {
- if (decompressed != NULL)
- g_string_free(decompressed, TRUE);
- purple_debug_error("http",
- "Cannot write using callback\n");
- _purple_http_error(hc,
- _("Error handling retrieved data"));
- return FALSE;
- }
- } else {
- if (hc->response->contents == NULL)
- hc->response->contents = g_string_new("");
- g_string_append_len(hc->response->contents, buf, len);
- }
-
- if (decompressed != NULL)
- g_string_free(decompressed, TRUE);
-
- purple_http_conn_notify_progress_watcher(hc);
- return TRUE;
-}
-
-static gboolean _purple_http_recv_body_chunked(PurpleHttpConnection *hc,
- const gchar *buf, int len)
-{
- gchar *eol, *line;
- int line_len;
-
- if (hc->chunks_done)
- return FALSE;
- if (!hc->response_buffer)
- hc->response_buffer = g_string_new("");
-
- g_string_append_len(hc->response_buffer, buf, len);
- if (hc->response_buffer->len > PURPLE_HTTP_MAX_RECV_BUFFER_LEN) {
- purple_debug_error("http",
- "Buffer too big when searching for chunk\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
-
- while (hc->response_buffer->len > 0) {
- if (hc->in_chunk) {
- int got_now = hc->response_buffer->len;
- if (hc->chunk_got + got_now > hc->chunk_length)
- got_now = hc->chunk_length - hc->chunk_got;
- hc->chunk_got += got_now;
-
- if (!_purple_http_recv_body_data(hc,
- hc->response_buffer->str, got_now))
- return FALSE;
-
- g_string_erase(hc->response_buffer, 0, got_now);
- hc->in_chunk = (hc->chunk_got < hc->chunk_length);
-
- continue;
- }
-
- line = hc->response_buffer->str;
- eol = strstr(line, "\r\n");
- if (eol == line) {
- g_string_erase(hc->response_buffer, 0, 2);
- line = hc->response_buffer->str;
- eol = strstr(line, "\r\n");
- }
- if (eol == NULL) {
- /* waiting for more data (unlikely, but possible) */
- if (hc->response_buffer->len > 20) {
- purple_debug_warning("http", "Chunk length not "
- "found (buffer too large)\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- return TRUE;
- }
- line_len = eol - line;
-
- if (1 != sscanf(line, "%x", &hc->chunk_length)) {
- if (purple_debug_is_unsafe())
- purple_debug_warning("http",
- "Chunk length not found in [%s]\n",
- line);
- else
- purple_debug_warning("http",
- "Chunk length not found\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- hc->chunk_got = 0;
- hc->in_chunk = TRUE;
-
- if (purple_debug_is_verbose())
- purple_debug_misc("http", "Found chunk of length %d\n", hc->chunk_length);
-
- g_string_erase(hc->response_buffer, 0, line_len + 2);
-
- if (hc->chunk_length == 0) {
- hc->chunks_done = TRUE;
- hc->in_chunk = FALSE;
- return TRUE;
- }
- }
-
- return TRUE;
-}
-
-static gboolean _purple_http_recv_body(PurpleHttpConnection *hc,
- const gchar *buf, int len)
-{
- if (hc->is_chunked)
- return _purple_http_recv_body_chunked(hc, buf, len);
-
- return _purple_http_recv_body_data(hc, buf, len);
-}
-
-static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc)
-{
- int len;
- gchar buf[4096];
- gboolean got_anything;
- GError *error = NULL;
-
- len = g_pollable_input_stream_read_nonblocking(
- G_POLLABLE_INPUT_STREAM(
- g_io_stream_get_input_stream(
- G_IO_STREAM(hc->socket->conn))),
- buf, sizeof(buf), hc->socket->cancellable,
- &error);
- got_anything = (len > 0);
-
- if (len < 0 && (g_error_matches(error,
- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
- g_error_matches(error,
- G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
- g_clear_error(&error);
- return FALSE;
- }
-
- if (len < 0) {
- _purple_http_error(hc, _("Error reading from %s: %s"),
- hc->url->host, error->message);
- g_clear_error(&error);
- return FALSE;
- }
-
- /* EOF */
- if (len == 0) {
- if (hc->request->max_length == 0) {
- /* It's definitely YHttpServer quirk. */
- purple_debug_warning("http", "Got EOF, but no data was "
- "expected (this may be a server quirk)\n");
- hc->length_expected = hc->length_got;
- }
- if (hc->length_expected >= 0 &&
- hc->length_got < (guint)hc->length_expected)
- {
- purple_debug_warning("http", "No more data while reading"
- " contents\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- if (hc->headers_got)
- hc->length_expected = hc->length_got;
- else if (hc->length_got == 0 && hc->socket->use_count > 1) {
- purple_debug_info("http", "Keep-alive connection "
- "expired (when reading), retrying...\n");
- purple_http_conn_retry(hc);
- return FALSE;
- } else {
- const gchar *server = purple_http_headers_get(
- hc->response->headers, "Server");
- if (server &&
- g_ascii_strcasecmp(server, "YHttpServer") == 0)
- {
- purple_debug_warning("http", "No more data "
- "while parsing headers (YHttpServer "
- "quirk)\n");
- hc->headers_got = TRUE;
- hc->length_expected = hc->length_got = 0;
- hc->length_got_decompressed = 0;
- } else {
- purple_debug_warning("http", "No more data "
- "while parsing headers\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
- }
- }
-
- if (!hc->headers_got && len > 0) {
- if (!_purple_http_recv_headers(hc, buf, len))
- return FALSE;
- len = 0;
- if (hc->headers_got) {
- gboolean is_gzip, is_deflate;
- if (!purple_http_headers_get_int(hc->response->headers,
- "Content-Length", &hc->length_expected))
- hc->length_expected = -1;
- hc->is_chunked = (purple_http_headers_match(
- hc->response->headers,
- "Transfer-Encoding", "chunked"));
- is_gzip = purple_http_headers_match(
- hc->response->headers, "Content-Encoding",
- "gzip");
- is_deflate = purple_http_headers_match(
- hc->response->headers, "Content-Encoding",
- "deflate");
- if (is_gzip || is_deflate) {
- hc->gz_stream = purple_http_gz_new(
- hc->request->max_length + 1,
- is_deflate);
- }
- }
- if (hc->headers_got && hc->response_buffer &&
- hc->response_buffer->len > 0)
- {
- int buffer_len = hc->response_buffer->len;
- gchar *buffer = g_string_free(hc->response_buffer, FALSE);
- hc->response_buffer = NULL;
- if (!_purple_http_recv_body(hc, buffer, buffer_len))
- {
- g_free(buffer);
- return FALSE;
- }
- g_free(buffer);
- }
- if (!hc->headers_got)
- return got_anything;
- }
-
- if (len > 0) {
- if (!_purple_http_recv_body(hc, buf, len))
- return FALSE;
- }
-
- if (hc->is_chunked && hc->chunks_done && hc->length_expected < 0)
- hc->length_expected = hc->length_got;
-
- if (hc->length_expected >= 0 &&
- hc->length_got >= (guint)hc->length_expected)
- {
- const gchar *redirect;
-
- if (hc->is_chunked && !hc->chunks_done) {
- if (len == 0) {
- _purple_http_error(hc, _("Chunked connection terminated"));
- return FALSE;
- }
- if (purple_debug_is_verbose()) {
- purple_debug_misc("http",
- "I need the terminating empty chunk\n");
- }
- return TRUE;
- }
-
- if (!hc->headers_got) {
- hc->response->code = 0;
- purple_debug_warning("http", "No headers got\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- return FALSE;
- }
-
- if (purple_debug_is_unsafe() && purple_debug_is_verbose()) {
- gchar *hdrs = purple_http_headers_dump(
- hc->response->headers);
- purple_debug_misc("http", "Got response headers: %s\n",
- hdrs);
- g_free(hdrs);
- }
-
- purple_http_cookie_jar_parse(hc->request->cookie_jar,
- purple_http_headers_get_all_by_name(
- hc->response->headers, "Set-Cookie"));
-
- if (purple_debug_is_unsafe() && purple_debug_is_verbose() &&
- !purple_http_cookie_jar_is_empty(
- hc->request->cookie_jar))
- {
- gchar *cookies = purple_http_cookie_jar_dump(
- hc->request->cookie_jar);
- purple_debug_misc("http", "Cookies: %s\n", cookies);
- g_free(cookies);
- }
-
- if (hc->response->code == 407) {
- _purple_http_error(hc, _("Invalid proxy credentials"));
- return FALSE;
- }
-
- redirect = purple_http_headers_get(hc->response->headers,
- "location");
- if (redirect && (hc->request->max_redirects == -1 ||
- hc->request->max_redirects > hc->redirects_count))
- {
- PurpleHttpURL *url = purple_http_url_parse(redirect);
-
- hc->redirects_count++;
-
- if (!url) {
- if (purple_debug_is_unsafe())
- purple_debug_warning("http",
- "Invalid redirect to %s\n",
- redirect);
- else
- purple_debug_warning("http",
- "Invalid redirect\n");
- _purple_http_error(hc, _("Error parsing HTTP"));
- }
-
- purple_http_url_relative(hc->url, url);
- purple_http_url_free(url);
-
- _purple_http_reconnect(hc);
- return FALSE;
- }
-
- _purple_http_disconnect(hc, TRUE);
- purple_http_connection_terminate(hc);
- return FALSE;
- }
-
- return got_anything;
-}
-
-static gboolean _purple_http_recv(GObject *source, gpointer _hc)
-{
- PurpleHttpConnection *hc = _hc;
-
- while (_purple_http_recv_loopbody(hc));
-
- return G_SOURCE_CONTINUE;
-}
-
-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 gboolean _purple_http_send(GObject *source, gpointer _hc)
-{
- PurpleHttpConnection *hc = _hc;
- int written, write_len;
- const gchar *write_from;
- gboolean writing_headers;
- GError *error = NULL;
- GSource *gsource;
-
- /* Waiting for data. This could be written more efficiently, by removing
- * (and later, adding) hs->inpa. */
- if (hc->contents_reader_requested)
- return G_SOURCE_CONTINUE;
-
- _purple_http_gen_headers(hc);
-
- writing_headers =
- (hc->request_header_written < hc->request_header->len);
- if (writing_headers) {
- write_from = hc->request_header->str +
- 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 G_SOURCE_CONTINUE; /* 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 G_SOURCE_CONTINUE;
- }
- write_from = hc->contents_reader_buffer->str;
- write_len = hc->contents_reader_buffer->len;
- } else {
- write_from = hc->request->contents +
- hc->request_contents_written;
- write_len = hc->request->contents_length -
- hc->request_contents_written;
- }
-
- if (write_len == 0) {
- purple_debug_warning("http", "Nothing to write\n");
- written = 0;
- } else {
- written = g_pollable_output_stream_write_nonblocking(
- G_POLLABLE_OUTPUT_STREAM(
- g_io_stream_get_output_stream(
- G_IO_STREAM(hc->socket->conn))),
- write_from, write_len, hc->socket->cancellable,
- &error);
- }
-
- if (written < 0 && (g_error_matches(error,
- G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
- g_error_matches(error,
- G_IO_ERROR, G_IO_ERROR_CANCELLED))) {
- g_clear_error(&error);
- return G_SOURCE_CONTINUE;
- }
-
- if (written < 0) {
- if (hc->request_header_written == 0 &&
- hc->socket->use_count > 1)
- {
- purple_debug_info("http", "Keep-alive connection "
- "expired (when writing), retrying...\n");
- purple_http_conn_retry(hc);
- } else {
- _purple_http_error(hc, _("Error writing to %s: %s"),
- hc->url->host, error->message);
- }
-
- g_clear_error(&error);
- return G_SOURCE_CONTINUE;
- }
-
- if (writing_headers) {
- hc->request_header_written += written;
- purple_http_conn_notify_progress_watcher(hc);
- if (hc->request_header_written < hc->request_header->len)
- return G_SOURCE_CONTINUE;
- if (hc->request->contents_length > 0)
- return G_SOURCE_CONTINUE;
- } else {
- hc->request_contents_written += written;
- purple_http_conn_notify_progress_watcher(hc);
- if (hc->contents_reader_buffer)
- g_string_erase(hc->contents_reader_buffer, 0, written);
- if (hc->request->contents_length > 0 &&
- hc->request_contents_written <
- (guint)hc->request->contents_length)
- {
- return G_SOURCE_CONTINUE;
- }
- }
-
- /* request is completely written, let's read the response */
- hc->is_reading = TRUE;
- gsource = g_pollable_input_stream_create_source(
- G_POLLABLE_INPUT_STREAM(
- g_io_stream_get_input_stream(
- G_IO_STREAM(hc->socket->conn))),
- NULL);
- g_source_set_callback(gsource,
- (GSourceFunc)_purple_http_recv, hc, NULL);
- hc->socket->input_source = g_source_attach(gsource, NULL);
- g_source_unref(gsource);
-
- hc->socket->output_source = 0;
- return G_SOURCE_REMOVE;
-}
-
-static void _purple_http_disconnect(PurpleHttpConnection *hc,
- gboolean is_graceful)
-{
- g_return_if_fail(hc != NULL);
-
- if (hc->request_header)
- g_string_free(hc->request_header, TRUE);
- hc->request_header = NULL;
-
- if (hc->response_buffer)
- g_string_free(hc->response_buffer, TRUE);
- hc->response_buffer = NULL;
-
- if (hc->gz_stream)
- purple_http_gz_free(hc->gz_stream);
- hc->gz_stream = NULL;
-
- if (hc->socket_request)
- purple_http_keepalive_pool_request_cancel(hc->socket_request);
- else {
- purple_http_keepalive_pool_release(hc->socket, !is_graceful);
- hc->socket = NULL;
- }
-}
-
-static void
-_purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc)
-{
- PurpleHttpConnection *hc = _hc;
- GSource *source;
-
- hc->socket_request = NULL;
- hc->socket = hs;
-
- if (error != NULL) {
- _purple_http_error(hc, _("Unable to connect to %s: %s"),
- hc->url->host, error);
- return;
- }
-
- source = g_pollable_output_stream_create_source(
- G_POLLABLE_OUTPUT_STREAM(
- g_io_stream_get_output_stream(G_IO_STREAM(hs->conn))),
- NULL);
- g_source_set_callback(source,
- (GSourceFunc)_purple_http_send, hc, NULL);
- hc->socket->output_source = g_source_attach(source, NULL);
- g_source_unref(source);
-}
-
-static gboolean _purple_http_reconnect(PurpleHttpConnection *hc)
-{
- PurpleHttpURL *url;
- gboolean is_ssl = FALSE;
-
- g_return_val_if_fail(hc != NULL, FALSE);
- g_return_val_if_fail(hc->url != NULL, FALSE);
-
- _purple_http_disconnect(hc, TRUE);
-
- if (purple_debug_is_verbose()) {
- if (purple_debug_is_unsafe()) {
- gchar *urlp = purple_http_url_print(hc->url);
- purple_debug_misc("http", "Connecting to %s...\n", urlp);
- g_free(urlp);
- } else
- purple_debug_misc("http", "Connecting to %s...\n",
- hc->url->host);
- }
-
- url = hc->url;
- if (g_strcmp0(url->protocol, "") == 0 ||
- g_ascii_strcasecmp(url->protocol, "http") == 0)
- {
- /* do nothing */
- } else if (g_ascii_strcasecmp(url->protocol, "https") == 0) {
- is_ssl = TRUE;
- } else {
- _purple_http_error(hc, _("Unsupported protocol: %s"),
- url->protocol);
- return FALSE;
- }
-
- if (hc->request->keepalive_pool != NULL) {
- hc->socket_request = purple_http_keepalive_pool_request(
- hc->request->keepalive_pool, hc->gc, url->host,
- url->port, is_ssl, _purple_http_connected, hc);
- } else {
- hc->socket = purple_http_socket_connect_new(hc->gc, url->host,
- url->port, is_ssl, _purple_http_connected, hc);
- }
-
- if (hc->socket_request == NULL && hc->socket == NULL) {
- _purple_http_error(hc, _("Unable to connect to %s"), url->host);
- return FALSE;
- }
-
- purple_http_headers_free(hc->response->headers);
- hc->response->headers = purple_http_headers_new();
- hc->response_buffer = g_string_new("");
- hc->main_header_got = FALSE;
- hc->headers_got = FALSE;
- if (hc->response->contents != NULL)
- g_string_free(hc->response->contents, TRUE);
- hc->response->contents = NULL;
- hc->length_got = 0;
- hc->length_got_decompressed = 0;
- hc->length_expected = -1;
- hc->is_chunked = FALSE;
- hc->in_chunk = FALSE;
- hc->chunks_done = FALSE;
-
- purple_http_conn_notify_progress_watcher(hc);
-
- return TRUE;
-}
-
-/*** Performing HTTP requests *************************************************/
-
-static gboolean purple_http_request_timeout(gpointer _hc)
-{
- PurpleHttpConnection *hc = _hc;
-
- purple_debug_warning("http", "Timeout reached for request %p\n", hc);
-
- purple_http_conn_cancel(hc);
-
- return FALSE;
-}
-
-PurpleHttpConnection * purple_http_get(PurpleConnection *gc,
- PurpleHttpCallback callback, gpointer user_data, const gchar *url)
-{
- PurpleHttpRequest *request;
- PurpleHttpConnection *hc;
-
- g_return_val_if_fail(url != NULL, NULL);
-
- request = purple_http_request_new(url);
- hc = purple_http_request(gc, request, callback, user_data);
- purple_http_request_unref(request);
-
- return hc;
-}
-
-PurpleHttpConnection * purple_http_get_printf(PurpleConnection *gc,
- PurpleHttpCallback callback, gpointer user_data,
- const gchar *format, ...)
-{
- va_list args;
- gchar *value;
- PurpleHttpConnection *ret;
-
- g_return_val_if_fail(format != NULL, NULL);
-
- va_start(args, format);
- value = g_strdup_vprintf(format, args);
- va_end(args);
-
- ret = purple_http_get(gc, callback, user_data, value);
- g_free(value);
-
- return ret;
-}
-
-PurpleHttpConnection * purple_http_request(PurpleConnection *gc,
- PurpleHttpRequest *request, PurpleHttpCallback callback,
- gpointer user_data)
-{
- PurpleHttpConnection *hc;
-
- g_return_val_if_fail(request != NULL, NULL);
-
- if (request->url == NULL) {
- purple_debug_error("http", "Cannot perform new request - "
- "URL is not set\n");
- return NULL;
- }
-
- if (g_hash_table_lookup(purple_http_cancelling_gc, gc)) {
- purple_debug_warning("http", "Cannot perform another HTTP "
- "request while cancelling all related with this "
- "PurpleConnection\n");
- return NULL;
- }
-
- hc = purple_http_connection_new(request, gc);
- hc->callback = callback;
- hc->user_data = user_data;
-
- hc->url = purple_http_url_parse(request->url);
-
- if (purple_debug_is_unsafe())
- purple_debug_misc("http", "Performing new request %p for %s.\n",
- hc, request->url);
- else
- purple_debug_misc("http", "Performing new request %p to %s.\n",
- hc, hc->url ? hc->url->host : NULL);
-
- if (!hc->url || hc->url->host == NULL || hc->url->host[0] == '\0') {
- purple_debug_error("http", "Invalid URL requested.\n");
- purple_http_connection_terminate(hc);
- return NULL;
- }
-
- _purple_http_reconnect(hc);
-
- hc->timeout_handle = g_timeout_add_seconds(request->timeout,
- purple_http_request_timeout, hc);
-
- return hc;
-}
-
-/*** HTTP connection API ******************************************************/
-
-static void purple_http_connection_free(PurpleHttpConnection *hc);
-static gboolean purple_http_conn_notify_progress_watcher_timeout(gpointer _hc);
-
-static PurpleHttpConnection * purple_http_connection_new(
- PurpleHttpRequest *request, PurpleConnection *gc)
-{
- PurpleHttpConnection *hc = g_new0(PurpleHttpConnection, 1);
-
- g_assert(request != NULL);
-
- hc->request = request;
- purple_http_request_ref(request);
- hc->response = purple_http_response_new();
- hc->is_keepalive = (request->keepalive_pool != NULL);
-
- hc->link_global = purple_http_hc_list =
- g_list_prepend(purple_http_hc_list, hc);
- g_hash_table_insert(purple_http_hc_by_ptr, hc, hc->link_global);
- if (gc) {
- GList *gc_list = g_hash_table_lookup(purple_http_hc_by_gc, gc);
- g_hash_table_steal(purple_http_hc_by_gc, gc);
- hc->link_gc = gc_list = g_list_prepend(gc_list, hc);
- g_hash_table_insert(purple_http_hc_by_gc, gc, gc_list);
- hc->gc = gc;
- }
-
- return hc;
-}
-
-static void purple_http_connection_free(PurpleHttpConnection *hc)
-{
- if (hc->timeout_handle)
- g_source_remove(hc->timeout_handle);
- if (hc->watcher_delayed_handle)
- g_source_remove(hc->watcher_delayed_handle);
-
- if (hc->connection_set != NULL)
- purple_http_connection_set_remove(hc->connection_set, hc);
-
- purple_http_url_free(hc->url);
- 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);
- purple_http_gz_free(hc->gz_stream);
-
- if (hc->request_header)
- g_string_free(hc->request_header, TRUE);
-
- purple_http_hc_list = g_list_delete_link(purple_http_hc_list,
- hc->link_global);
- g_hash_table_remove(purple_http_hc_by_ptr, hc);
- if (hc->gc) {
- GList *gc_list, *gc_list_new;
- gc_list = g_hash_table_lookup(purple_http_hc_by_gc, hc->gc);
- g_assert(gc_list != NULL);
-
- gc_list_new = g_list_delete_link(gc_list, hc->link_gc);
- if (gc_list != gc_list_new) {
- g_hash_table_steal(purple_http_hc_by_gc, hc->gc);
- if (gc_list_new)
- g_hash_table_insert(purple_http_hc_by_gc,
- hc->gc, gc_list_new);
- }
- }
-
- g_free(hc);
-}
-
-/* call callback and do the cleanup */
-static void purple_http_connection_terminate(PurpleHttpConnection *hc)
-{
- g_return_if_fail(hc != NULL);
-
- purple_debug_misc("http", "Request %p performed %s.\n", hc,
- purple_http_response_is_successful(hc->response) ?
- "successfully" : "without success");
-
- if (hc->callback)
- hc->callback(hc, hc->response, hc->user_data);
-
- purple_http_connection_free(hc);
-}
-
-void purple_http_conn_cancel(PurpleHttpConnection *http_conn)
-{
- if (http_conn == NULL)
- return;
-
- if (http_conn->is_cancelling)
- return;
- http_conn->is_cancelling = TRUE;
-
- if (purple_debug_is_verbose()) {
- purple_debug_misc("http", "Cancelling connection %p...\n",
- http_conn);
- }
-
- if (http_conn->response != NULL) {
- http_conn->response->code = 0;
- }
- _purple_http_disconnect(http_conn, FALSE);
- purple_http_connection_terminate(http_conn);
-}
-
-static void
-purple_http_conn_retry(PurpleHttpConnection *http_conn)
-{
- if (http_conn == NULL)
- return;
-
- purple_debug_info("http", "Retrying connection %p...\n", http_conn);
-
- if (http_conn->response != NULL) {
- http_conn->response->code = 0;
- }
- _purple_http_disconnect(http_conn, FALSE);
- _purple_http_reconnect(http_conn);
-}
-
-void purple_http_conn_cancel_all(PurpleConnection *gc)
-{
- GList *gc_list;
-
- if (purple_debug_is_verbose()) {
- purple_debug_misc("http", "Cancelling all running HTTP "
- "connections\n");
- }
-
- gc_list = g_hash_table_lookup(purple_http_hc_by_gc, gc);
-
- g_hash_table_insert(purple_http_cancelling_gc, gc, GINT_TO_POINTER(1));
-
- while (gc_list) {
- PurpleHttpConnection *hc = gc_list->data;
- gc_list = g_list_next(gc_list);
- purple_http_conn_cancel(hc);
- }
-
- g_hash_table_remove(purple_http_cancelling_gc, gc);
-
- if (NULL != g_hash_table_lookup(purple_http_hc_by_gc, gc))
- purple_debug_fatal("http", "Couldn't cancel all connections "
- "related to gc=%p (it shouldn't happen)\n", gc);
-}
-
-gboolean purple_http_conn_is_running(PurpleHttpConnection *http_conn)
-{
- if (http_conn == NULL)
- return FALSE;
- return (NULL != g_hash_table_lookup(purple_http_hc_by_ptr, http_conn));
-}
-
-PurpleHttpRequest * purple_http_conn_get_request(PurpleHttpConnection *http_conn)
-{
- g_return_val_if_fail(http_conn != NULL, NULL);
-
- return http_conn->request;
-}
-
-PurpleHttpCookieJar * purple_http_conn_get_cookie_jar(
- PurpleHttpConnection *http_conn)
-{
- return purple_http_request_get_cookie_jar(purple_http_conn_get_request(
- http_conn));
-}
-
-PurpleConnection * purple_http_conn_get_purple_connection(
- PurpleHttpConnection *http_conn)
-{
- g_return_val_if_fail(http_conn != NULL, NULL);
-
- return http_conn->gc;
-}
-
-void purple_http_conn_set_progress_watcher(PurpleHttpConnection *http_conn,
- PurpleHttpProgressWatcher watcher, gpointer user_data,
- gint interval_threshold)
-{
- g_return_if_fail(http_conn != NULL);
-
- if (interval_threshold < 0) {
- interval_threshold =
- PURPLE_HTTP_PROGRESS_WATCHER_DEFAULT_INTERVAL;
- }
-
- http_conn->watcher = watcher;
- http_conn->watcher_user_data = user_data;
- http_conn->watcher_interval_threshold = interval_threshold;
-}
-
-static void purple_http_conn_notify_progress_watcher(
- PurpleHttpConnection *hc)
-{
- gint64 now;
- gboolean reading_state;
- int processed, total;
-
- g_return_if_fail(hc != NULL);
-
- if (hc->watcher == NULL)
- return;
-
- reading_state = hc->is_reading;
- if (reading_state) {
- total = hc->length_expected;
- processed = hc->length_got;
- } else {
- total = hc->request->contents_length;
- processed = hc->request_contents_written;
- if (total == 0)
- total = -1;
- }
- if (total != -1 && total < processed) {
- purple_debug_warning("http", "Processed too much\n");
- total = processed;
- }
-
- now = g_get_monotonic_time();
- if (hc->watcher_last_call + hc->watcher_interval_threshold
- > now && processed != total)
- {
- if (hc->watcher_delayed_handle)
- return;
- hc->watcher_delayed_handle = g_timeout_add_seconds(
- 1 + hc->watcher_interval_threshold / 1000000,
- purple_http_conn_notify_progress_watcher_timeout, hc);
- return;
- }
-
- if (hc->watcher_delayed_handle)
- g_source_remove(hc->watcher_delayed_handle);
- hc->watcher_delayed_handle = 0;
-
- hc->watcher_last_call = now;
- hc->watcher(hc, reading_state, processed, total, hc->watcher_user_data);
-}
-
-static gboolean purple_http_conn_notify_progress_watcher_timeout(gpointer _hc)
-{
- PurpleHttpConnection *hc = _hc;
-
- purple_http_conn_notify_progress_watcher(hc);
-
- return FALSE;
-}
-
-/*** Cookie jar API ***********************************************************/
-
-static PurpleHttpCookie * purple_http_cookie_new(const gchar *value);
-void purple_http_cookie_free(PurpleHttpCookie *cookie);
-
-static void purple_http_cookie_jar_set_ext(PurpleHttpCookieJar *cookie_jar,
- const gchar *name, const gchar *value, time_t expires);
-
-static PurpleHttpCookie * purple_http_cookie_new(const gchar *value)
-{
- PurpleHttpCookie *cookie = g_new0(PurpleHttpCookie, 1);
-
- cookie->value = g_strdup(value);
- cookie->expires = -1;
-
- return cookie;
-}
-
-void purple_http_cookie_free(PurpleHttpCookie *cookie)
-{
- g_free(cookie->value);
- g_free(cookie);
-}
-
-void purple_http_cookie_jar_free(PurpleHttpCookieJar *cookie_jar);
-
-PurpleHttpCookieJar * purple_http_cookie_jar_new(void)
-{
- PurpleHttpCookieJar *cjar = g_new0(PurpleHttpCookieJar, 1);
-
- cjar->ref_count = 1;
- cjar->tab = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- (GDestroyNotify)purple_http_cookie_free);
-
- return cjar;
-}
-
-void purple_http_cookie_jar_free(PurpleHttpCookieJar *cookie_jar)
-{
- g_hash_table_destroy(cookie_jar->tab);
- g_free(cookie_jar);
-}
-
-void purple_http_cookie_jar_ref(PurpleHttpCookieJar *cookie_jar)
-{
- g_return_if_fail(cookie_jar != NULL);
-
- cookie_jar->ref_count++;
-}
-
-PurpleHttpCookieJar * purple_http_cookie_jar_unref(
- PurpleHttpCookieJar *cookie_jar)
-{
- if (cookie_jar == NULL)
- return NULL;
-
- g_return_val_if_fail(cookie_jar->ref_count > 0, NULL);
-
- cookie_jar->ref_count--;
- if (cookie_jar->ref_count > 0)
- return cookie_jar;
-
- purple_http_cookie_jar_free(cookie_jar);
- return NULL;
-}
-
-static void purple_http_cookie_jar_parse(PurpleHttpCookieJar *cookie_jar,
- GList *values)
-{
- values = g_list_first(values);
- while (values) {
- const gchar *cookie = values->data;
- const gchar *eqsign, *semicolon;
- gchar *name, *value;
- time_t expires = -1;
- values = g_list_next(values);
-
- eqsign = strchr(cookie, '=');
- semicolon = strchr(cookie, ';');
-
- if (eqsign == NULL || eqsign == cookie ||
- (semicolon != NULL && semicolon < eqsign))
- {
- if (purple_debug_is_unsafe())
- purple_debug_warning("http",
- "Invalid cookie: [%s]\n", cookie);
- else
- purple_debug_warning("http", "Invalid cookie.");
- continue;
- }
-
- name = g_strndup(cookie, eqsign - cookie);
- eqsign++;
- if (semicolon != NULL)
- value = g_strndup(eqsign, semicolon - eqsign);
- else
- value = g_strdup(eqsign);
-
- if (semicolon != NULL) {
- GMatchInfo *match_info;
- GRegex *re_expires = g_regex_new( /* XXX: make it static */
- "expires=([a-z0-9, :]+)",
- G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
- G_REGEX_MATCH_NOTEMPTY, NULL);
-
- g_regex_match(re_expires, semicolon, 0, &match_info);
- if (g_match_info_matches(match_info)) {
- gchar *expire_date =
- g_match_info_fetch(match_info, 1);
- expires = purple_http_rfc1123_to_time(
- expire_date);
- g_free(expire_date);
- }
- g_match_info_free(match_info);
-
- g_regex_unref(re_expires);
- }
-
- purple_http_cookie_jar_set_ext(cookie_jar, name, value, expires);
-
- g_free(name);
- g_free(value);
- }
-}
-
-static gchar * purple_http_cookie_jar_gen(PurpleHttpCookieJar *cookie_jar)
-{
- GHashTableIter it;
- gchar *key;
- PurpleHttpCookie *cookie;
- GString *str;
- time_t now = time(NULL);
-
- g_return_val_if_fail(cookie_jar != NULL, NULL);
-
- str = g_string_new("");
-
- g_hash_table_iter_init(&it, cookie_jar->tab);
- while (g_hash_table_iter_next(&it, (gpointer*)&key,
- (gpointer*)&cookie))
- {
- if (cookie->expires != -1 && cookie->expires != 0 && cookie->expires <= now)
- continue;
- g_string_append_printf(str, "%s=%s; ", key, cookie->value);
- }
-
- if (str->len > 0)
- g_string_truncate(str, str->len - 2);
- return g_string_free(str, FALSE);
-}
-
-void purple_http_cookie_jar_set(PurpleHttpCookieJar *cookie_jar,
- const gchar *name, const gchar *value)
-{
- gchar *escaped_name = g_strdup(purple_url_encode(name));
- gchar *escaped_value = NULL;
-
- if (value) {
- escaped_value = g_strdup(purple_url_encode(value));
- }
-
- purple_http_cookie_jar_set_ext(cookie_jar, escaped_name, escaped_value, -1);
-
- g_free(escaped_name);
- g_free(escaped_value);
-}
-
-static void purple_http_cookie_jar_set_ext(PurpleHttpCookieJar *cookie_jar,
- const gchar *name, const gchar *value, time_t expires)
-{
- g_return_if_fail(cookie_jar != NULL);
- g_return_if_fail(name != NULL);
-
- if (expires != -1 && expires != 0 && time(NULL) >= expires)
- value = NULL;
-
- if (value != NULL) {
- PurpleHttpCookie *cookie = purple_http_cookie_new(value);
- cookie->expires = expires;
- g_hash_table_insert(cookie_jar->tab, g_strdup(name), cookie);
- } else
- g_hash_table_remove(cookie_jar->tab, name);
-}
-
-gchar * purple_http_cookie_jar_get(PurpleHttpCookieJar *cookie_jar,
- const gchar *name)
-{
- PurpleHttpCookie *cookie;
-
- g_return_val_if_fail(cookie_jar != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- cookie = g_hash_table_lookup(cookie_jar->tab, name);
- if (!cookie)
- return NULL;
-
- return g_strdup(purple_url_decode(cookie->value));
-}
-
-gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar)
-{
- GHashTableIter it;
- gchar *key;
- PurpleHttpCookie *cookie;
- GString *str = g_string_new("");
-
- g_hash_table_iter_init(&it, cjar->tab);
- while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&cookie))
- g_string_append_printf(str, "%s: %s (expires: %" G_GINT64_FORMAT
- ")\n", key, cookie->value, (gint64)cookie->expires);
-
- if (str->len > 0)
- g_string_truncate(str, str->len - 1);
- return g_string_free(str, FALSE);
-}
-
-gboolean purple_http_cookie_jar_is_empty(PurpleHttpCookieJar *cookie_jar)
-{
- g_return_val_if_fail(cookie_jar != NULL, TRUE);
-
- return g_hash_table_size(cookie_jar->tab) == 0;
-}
-
-/*** HTTP Keep-Alive pool API *************************************************/
-
-static void
-purple_http_keepalive_host_process_queue(PurpleHttpKeepaliveHost *host);
-
-static void
-purple_http_keepalive_host_free(gpointer _host)
-{
- PurpleHttpKeepaliveHost *host = _host;
-
- g_free(host->host);
-
- g_slist_free_full(host->queue,
- (GDestroyNotify)purple_http_keepalive_pool_request_cancel);
- g_slist_free_full(host->sockets,
- (GDestroyNotify)purple_http_socket_close_free);
-
- if (host->process_queue_timeout > 0) {
- g_source_remove(host->process_queue_timeout);
- host->process_queue_timeout = 0;
- }
-
-
- g_free(host);
-}
-
-PurpleHttpKeepalivePool *
-purple_http_keepalive_pool_new(void)
-{
- PurpleHttpKeepalivePool *pool = g_new0(PurpleHttpKeepalivePool, 1);
-
- pool->ref_count = 1;
- pool->by_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- purple_http_keepalive_host_free);
-
- return pool;
-}
-
-static void
-purple_http_keepalive_pool_free(PurpleHttpKeepalivePool *pool)
-{
- g_return_if_fail(pool != NULL);
-
- if (pool->is_destroying)
- return;
- pool->is_destroying = TRUE;
- g_hash_table_destroy(pool->by_hash);
- g_free(pool);
-}
-
-void
-purple_http_keepalive_pool_ref(PurpleHttpKeepalivePool *pool)
-{
- g_return_if_fail(pool != NULL);
-
- pool->ref_count++;
-}
-
-PurpleHttpKeepalivePool *
-purple_http_keepalive_pool_unref(PurpleHttpKeepalivePool *pool)
-{
- if (pool == NULL)
- return NULL;
-
- g_return_val_if_fail(pool->ref_count > 0, NULL);
-
- pool->ref_count--;
- if (pool->ref_count > 0)
- return pool;
-
- purple_http_keepalive_pool_free(pool);
- return NULL;
-}
-
-static PurpleHttpKeepaliveRequest *
-purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
- PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
- PurpleHttpSocketConnectCb cb, gpointer user_data)
-{
- PurpleHttpKeepaliveRequest *req;
- PurpleHttpKeepaliveHost *kahost;
- gchar *hash;
-
- g_return_val_if_fail(pool != NULL, NULL);
- g_return_val_if_fail(host != NULL, NULL);
-
- if (pool->is_destroying) {
- purple_debug_error("http", "pool is destroying\n");
- return NULL;
- }
-
- hash = purple_http_socket_hash(host, port, is_ssl);
- kahost = g_hash_table_lookup(pool->by_hash, hash);
-
- if (kahost == NULL) {
- kahost = g_new0(PurpleHttpKeepaliveHost, 1);
- kahost->pool = pool;
- kahost->host = g_strdup(host);
- kahost->port = port;
- kahost->is_ssl = is_ssl;
-
- g_hash_table_insert(pool->by_hash, g_strdup(hash), kahost);
- }
-
- g_free(hash);
-
- req = g_new0(PurpleHttpKeepaliveRequest, 1);
- req->gc = gc;
- req->cb = cb;
- req->user_data = user_data;
- req->host = kahost;
-
- kahost->queue = g_slist_append(kahost->queue, req);
-
- purple_http_keepalive_host_process_queue(kahost);
-
- return req;
-}
-
-static void
-_purple_http_keepalive_socket_connected(PurpleHttpSocket *hs,
- const gchar *error, gpointer _req)
-{
- PurpleHttpKeepaliveRequest *req = _req;
-
- if (hs != NULL)
- hs->use_count++;
-
- req->cb(hs, error, req->user_data);
- g_free(req);
-}
-
-static gboolean
-_purple_http_keepalive_host_process_queue_cb(gpointer _host)
-{
- PurpleHttpKeepaliveRequest *req;
- PurpleHttpKeepaliveHost *host = _host;
- PurpleHttpSocket *hs = NULL;
- GSList *it;
- guint sockets_count;
-
- g_return_val_if_fail(host != NULL, FALSE);
-
- host->process_queue_timeout = 0;
-
- if (host->queue == NULL)
- return FALSE;
-
- sockets_count = 0;
- it = host->sockets;
- while (it != NULL) {
- PurpleHttpSocket *hs_current = it->data;
-
- sockets_count++;
-
- if (!hs_current->is_busy) {
- hs = hs_current;
- break;
- }
-
- it = g_slist_next(it);
- }
-
- /* There are no free sockets and we cannot create another one. */
- if (hs == NULL && sockets_count >= host->pool->limit_per_host &&
- host->pool->limit_per_host > 0)
- {
- return FALSE;
- }
-
- req = host->queue->data;
- host->queue = g_slist_remove(host->queue, req);
-
- if (hs != NULL) {
- if (purple_debug_is_verbose()) {
- purple_debug_misc("http", "locking a (previously used) "
- "socket: %p\n", hs);
- }
-
- hs->is_busy = TRUE;
- hs->use_count++;
-
- purple_http_keepalive_host_process_queue(host);
-
- req->cb(hs, NULL, req->user_data);
- g_free(req);
-
- return FALSE;
- }
-
- hs = purple_http_socket_connect_new(req->gc, req->host->host,
- req->host->port, req->host->is_ssl,
- _purple_http_keepalive_socket_connected, req);
- if (hs == NULL) {
- purple_debug_error("http", "failed creating new socket");
- return FALSE;
- }
-
- req->hs = hs;
- hs->is_busy = TRUE;
- hs->host = host;
-
- if (purple_debug_is_verbose())
- purple_debug_misc("http", "locking a (new) socket: %p\n", hs);
-
- host->sockets = g_slist_append(host->sockets, hs);
-
- return FALSE;
-}
-
-static void
-purple_http_keepalive_host_process_queue(PurpleHttpKeepaliveHost *host)
-{
- g_return_if_fail(host != NULL);
-
- if (host->process_queue_timeout > 0)
- return;
-
- host->process_queue_timeout = g_timeout_add(0,
- _purple_http_keepalive_host_process_queue_cb, host);
-}
-
-static void
-purple_http_keepalive_pool_request_cancel(PurpleHttpKeepaliveRequest *req)
-{
- if (req == NULL)
- return;
-
- if (req->host != NULL)
- req->host->queue = g_slist_remove(req->host->queue, req);
-
- if (req->hs != NULL) {
- if (G_LIKELY(req->host)) {
- req->host->sockets = g_slist_remove(req->host->sockets,
- req->hs);
- }
- purple_http_socket_close_free(req->hs);
- /* req should already be free'd here */
- } else {
- req->cb(NULL, _("Cancelled"), req->user_data);
- g_free(req);
- }
-}
-
-static void
-purple_http_keepalive_pool_release(PurpleHttpSocket *hs, gboolean invalidate)
-{
- PurpleHttpKeepaliveHost *host;
-
- if (hs == NULL)
- return;
-
- if (purple_debug_is_verbose())
- purple_debug_misc("http", "releasing a socket: %p\n", hs);
-
- if (hs->input_source > 0) {
- g_source_remove(hs->input_source);
- hs->input_source = 0;
- }
-
- if (hs->output_source > 0) {
- g_source_remove(hs->output_source);
- hs->output_source = 0;
- }
-
- hs->is_busy = FALSE;
- host = hs->host;
-
- if (host == NULL) {
- purple_http_socket_close_free(hs);
- return;
- }
-
- if (invalidate) {
- host->sockets = g_slist_remove(host->sockets, hs);
- purple_http_socket_close_free(hs);
- }
-
- purple_http_keepalive_host_process_queue(host);
-}
-
-void
-purple_http_keepalive_pool_set_limit_per_host(PurpleHttpKeepalivePool *pool,
- guint limit)
-{
- g_return_if_fail(pool != NULL);
-
- pool->limit_per_host = limit;
-}
-
-guint
-purple_http_keepalive_pool_get_limit_per_host(PurpleHttpKeepalivePool *pool)
-{
- g_return_val_if_fail(pool != NULL, 0);
-
- return pool->limit_per_host;
-}
-
-/*** HTTP connection set API **************************************************/
-
-PurpleHttpConnectionSet *
-purple_http_connection_set_new(void)
-{
- PurpleHttpConnectionSet *set;
-
- set = g_new0(PurpleHttpConnectionSet, 1);
- set->connections = g_hash_table_new(g_direct_hash, g_direct_equal);
-
- return set;
-}
-
-void
-purple_http_connection_set_destroy(PurpleHttpConnectionSet *set)
-{
- if (set == NULL)
- return;
-
- set->is_destroying = TRUE;
-
- while (TRUE) {
- GHashTableIter iter;
- PurpleHttpConnection *http_conn;
-
- g_hash_table_iter_init(&iter, set->connections);
- if (!g_hash_table_iter_next(&iter, (gpointer*)&http_conn, NULL))
- break;
-
- purple_http_conn_cancel(http_conn);
- }
-
- g_hash_table_destroy(set->connections);
- g_free(set);
-}
-
-void
-purple_http_connection_set_add(PurpleHttpConnectionSet *set,
- PurpleHttpConnection *http_conn)
-{
- if (set->is_destroying)
- return;
- if (http_conn->connection_set == set)
- return;
- if (http_conn->connection_set != NULL) {
- purple_http_connection_set_remove(http_conn->connection_set,
- http_conn);
- }
- g_hash_table_insert(set->connections, http_conn, GINT_TO_POINTER(1));
- http_conn->connection_set = set;
-}
-
-static void
-purple_http_connection_set_remove(PurpleHttpConnectionSet *set,
- PurpleHttpConnection *http_conn)
-{
- g_hash_table_remove(set->connections, http_conn);
- if (http_conn->connection_set == set)
- http_conn->connection_set = NULL;
-}
-
-/*** Request API **************************************************************/
-
-static void purple_http_request_free(PurpleHttpRequest *request);
-
-PurpleHttpRequest * purple_http_request_new(const gchar *url)
-{
- PurpleHttpRequest *request;
-
- request = g_new0(PurpleHttpRequest, 1);
-
- request->ref_count = 1;
- request->url = g_strdup(url);
- request->headers = purple_http_headers_new();
- request->cookie_jar = purple_http_cookie_jar_new();
- request->keepalive_pool = purple_http_keepalive_pool_new();
-
- request->timeout = PURPLE_HTTP_REQUEST_DEFAULT_TIMEOUT;
- request->max_redirects = PURPLE_HTTP_REQUEST_DEFAULT_MAX_REDIRECTS;
- request->http11 = TRUE;
- request->max_length = PURPLE_HTTP_REQUEST_DEFAULT_MAX_LENGTH;
-
- return request;
-}
-
-static void purple_http_request_free(PurpleHttpRequest *request)
-{
- purple_http_headers_free(request->headers);
- purple_http_cookie_jar_unref(request->cookie_jar);
- purple_http_keepalive_pool_unref(request->keepalive_pool);
- g_free(request->method);
- g_free(request->contents);
- g_free(request->url);
- g_free(request);
-}
-
-void purple_http_request_ref(PurpleHttpRequest *request)
-{
- g_return_if_fail(request != NULL);
-
- request->ref_count++;
-}
-
-PurpleHttpRequest * purple_http_request_unref(PurpleHttpRequest *request)
-{
- if (request == NULL)
- return NULL;
-
- g_return_val_if_fail(request->ref_count > 0, NULL);
-
- request->ref_count--;
- if (request->ref_count > 0)
- return request;
-
- purple_http_request_free(request);
- return NULL;
-}
-
-void purple_http_request_set_url(PurpleHttpRequest *request, const gchar *url)
-{
- g_return_if_fail(request != NULL);
- g_return_if_fail(url != NULL);
-
- g_free(request->url);
- request->url = g_strdup(url);
-}
-
-void purple_http_request_set_url_printf(PurpleHttpRequest *request,
- const gchar *format, ...)
-{
- va_list args;
- gchar *value;
-
- g_return_if_fail(request != NULL);
- g_return_if_fail(format != NULL);
-
- va_start(args, format);
- value = g_strdup_vprintf(format, args);
- va_end(args);
-
- purple_http_request_set_url(request, value);
- g_free(value);
-}
-
-const gchar * purple_http_request_get_url(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, NULL);
-
- return request->url;
-}
-
-void purple_http_request_set_method(PurpleHttpRequest *request, const gchar *method)
-{
- g_return_if_fail(request != NULL);
-
- g_free(request->method);
- request->method = g_strdup(method);
-}
-
-const gchar * purple_http_request_get_method(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, NULL);
-
- return request->method;
-}
-
-static gboolean purple_http_request_is_method(PurpleHttpRequest *request,
- const gchar *method)
-{
- const gchar *rmethod;
-
- g_return_val_if_fail(request != NULL, FALSE);
- g_return_val_if_fail(method != NULL, FALSE);
-
- rmethod = purple_http_request_get_method(request);
- if (rmethod == NULL)
- return (g_ascii_strcasecmp(method, "get") == 0);
- return (g_ascii_strcasecmp(method, rmethod) == 0);
-}
-
-void
-purple_http_request_set_keepalive_pool(PurpleHttpRequest *request,
- PurpleHttpKeepalivePool *pool)
-{
- g_return_if_fail(request != NULL);
-
- if (pool != NULL)
- purple_http_keepalive_pool_ref(pool);
-
- if (request->keepalive_pool != NULL) {
- purple_http_keepalive_pool_unref(request->keepalive_pool);
- request->keepalive_pool = NULL;
- }
-
- if (pool != NULL)
- request->keepalive_pool = pool;
-}
-
-PurpleHttpKeepalivePool *
-purple_http_request_get_keepalive_pool(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, FALSE);
-
- return request->keepalive_pool;
-}
-
-void purple_http_request_set_contents(PurpleHttpRequest *request,
- const gchar *contents, int length)
-{
- 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;
- request->contents_length = 0;
- return;
- }
-
- if (length == -1)
- length = strlen(contents);
- request->contents = g_memdup(contents, length);
- 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_response_writer(PurpleHttpRequest *request,
- PurpleHttpContentWriter writer, gpointer user_data)
-{
- g_return_if_fail(request != NULL);
-
- if (writer == NULL)
- user_data = NULL;
- request->response_writer = writer;
- request->response_writer_data = user_data;
-}
-
-void purple_http_request_set_timeout(PurpleHttpRequest *request, int timeout)
-{
- g_return_if_fail(request != NULL);
-
- if (timeout < -1)
- timeout = -1;
-
- request->timeout = timeout;
-}
-
-int purple_http_request_get_timeout(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, -1);
-
- return request->timeout;
-}
-
-void purple_http_request_set_max_redirects(PurpleHttpRequest *request,
- int max_redirects)
-{
- g_return_if_fail(request != NULL);
-
- if (max_redirects < -1)
- max_redirects = -1;
-
- request->max_redirects = max_redirects;
-}
-
-int purple_http_request_get_max_redirects(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, -1);
-
- return request->max_redirects;
-}
-
-void purple_http_request_set_cookie_jar(PurpleHttpRequest *request,
- PurpleHttpCookieJar *cookie_jar)
-{
- g_return_if_fail(request != NULL);
- g_return_if_fail(cookie_jar != NULL);
-
- purple_http_cookie_jar_ref(cookie_jar);
- purple_http_cookie_jar_unref(request->cookie_jar);
- request->cookie_jar = cookie_jar;
-}
-
-PurpleHttpCookieJar * purple_http_request_get_cookie_jar(
- PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, NULL);
-
- return request->cookie_jar;
-}
-
-void purple_http_request_set_http11(PurpleHttpRequest *request, gboolean http11)
-{
- g_return_if_fail(request != NULL);
-
- request->http11 = http11;
-}
-
-gboolean purple_http_request_is_http11(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, FALSE);
-
- return request->http11;
-}
-
-void purple_http_request_set_max_len(PurpleHttpRequest *request, int max_len)
-{
- g_return_if_fail(request != NULL);
-
- if (max_len < 0 || max_len > PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH)
- max_len = PURPLE_HTTP_REQUEST_HARD_MAX_LENGTH;
-
- request->max_length = max_len;
-}
-
-int purple_http_request_get_max_len(PurpleHttpRequest *request)
-{
- g_return_val_if_fail(request != NULL, -1);
-
- return request->max_length;
-}
-
-void purple_http_request_header_set(PurpleHttpRequest *request,
- const gchar *key, const gchar *value)
-{
- g_return_if_fail(request != NULL);
- g_return_if_fail(key != NULL);
-
- purple_http_headers_remove(request->headers, key);
- if (value)
- purple_http_headers_add(request->headers, key, value);
-}
-
-void purple_http_request_header_set_printf(PurpleHttpRequest *request,
- const gchar *key, const gchar *format, ...)
-{
- va_list args;
- gchar *value;
-
- g_return_if_fail(request != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(format != NULL);
-
- va_start(args, format);
- value = g_strdup_vprintf(format, args);
- va_end(args);
-
- purple_http_request_header_set(request, key, value);
- g_free(value);
-}
-
-void purple_http_request_header_add(PurpleHttpRequest *request,
- const gchar *key, const gchar *value)
-{
- g_return_if_fail(request != NULL);
- g_return_if_fail(key != NULL);
-
- purple_http_headers_add(request->headers, key, value);
-}
-
-/*** HTTP response API ********************************************************/
-
-static PurpleHttpResponse * purple_http_response_new(void)
-{
- PurpleHttpResponse *response = g_new0(PurpleHttpResponse, 1);
-
- return response;
-}
-
-static void purple_http_response_free(PurpleHttpResponse *response)
-{
- if (response->contents != NULL)
- g_string_free(response->contents, TRUE);
- g_free(response->error);
- purple_http_headers_free(response->headers);
- g_free(response);
-}
-
-gboolean purple_http_response_is_successful(PurpleHttpResponse *response)
-{
- int code;
-
- g_return_val_if_fail(response != NULL, FALSE);
-
- code = response->code;
-
- if (code <= 0)
- return FALSE;
-
- /* TODO: HTTP/1.1 100 Continue */
-
- if (code / 100 == 2)
- return TRUE;
-
- return FALSE;
-}
-
-int purple_http_response_get_code(PurpleHttpResponse *response)
-{
- g_return_val_if_fail(response != NULL, 0);
-
- return response->code;
-}
-
-const gchar * purple_http_response_get_error(PurpleHttpResponse *response)
-{
- g_return_val_if_fail(response != NULL, NULL);
-
- if (response->error != NULL)
- return response->error;
-
- if (!purple_http_response_is_successful(response)) {
- static gchar errmsg[200];
- if (response->code <= 0) {
- g_snprintf(errmsg, sizeof(errmsg),
- _("Unknown HTTP error"));
- } else {
- g_snprintf(errmsg, sizeof(errmsg),
- _("Invalid HTTP response code (%d)"),
- response->code);
- }
- return errmsg;
- }
-
- return NULL;
-}
-
-gsize purple_http_response_get_data_len(PurpleHttpResponse *response)
-{
- g_return_val_if_fail(response != NULL, 0);
-
- if (response->contents == NULL)
- return 0;
-
- return response->contents->len;
-}
-
-const gchar * purple_http_response_get_data(PurpleHttpResponse *response, size_t *len)
-{
- const gchar *ret = "";
-
- g_return_val_if_fail(response != NULL, "");
-
- if (response->contents != NULL) {
- ret = response->contents->str;
- if (len)
- *len = response->contents->len;
- } else {
- if (len)
- *len = 0;
- }
-
- return ret;
-}
-
-const GList * purple_http_response_get_all_headers(PurpleHttpResponse *response)
-{
- g_return_val_if_fail(response != NULL, NULL);
-
- return purple_http_headers_get_all(response->headers);
-}
-
-const GList * purple_http_response_get_headers_by_name(
- PurpleHttpResponse *response, const gchar *name)
-{
- g_return_val_if_fail(response != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- return purple_http_headers_get_all_by_name(response->headers, name);
-}
-
-const gchar * purple_http_response_get_header(PurpleHttpResponse *response,
- const gchar *name)
-{
- g_return_val_if_fail(response != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- return purple_http_headers_get(response->headers, name);
-}
-
-/*** URL functions ************************************************************/
-
-PurpleHttpURL *
-purple_http_url_parse(const char *raw_url)
-{
- PurpleHttpURL *url;
- GMatchInfo *match_info;
-
- gchar *host_full, *tmp;
-
- g_return_val_if_fail(raw_url != NULL, NULL);
-
- if (!g_regex_match(purple_http_re_url, raw_url, 0, &match_info)) {
- if (purple_debug_is_verbose() && purple_debug_is_unsafe()) {
- purple_debug_warning("http",
- "Invalid URL provided: %s\n",
- raw_url);
- }
- return NULL;
- }
-
- url = g_new0(PurpleHttpURL, 1);
-
- url->protocol = g_match_info_fetch(match_info, 1);
- host_full = g_match_info_fetch(match_info, 2);
- url->path = g_match_info_fetch(match_info, 3);
- url->fragment = g_match_info_fetch(match_info, 4);
- g_match_info_free(match_info);
-
- if (g_strcmp0(url->protocol, "") == 0) {
- g_free(url->protocol);
- url->protocol = NULL;
- } else if (url->protocol != NULL) {
- tmp = url->protocol;
- url->protocol = g_ascii_strdown(url->protocol, -1);
- g_free(tmp);
- }
- if (host_full[0] == '\0') {
- g_free(host_full);
- host_full = NULL;
- }
- if (url->path[0] == '\0') {
- g_free(url->path);
- url->path = NULL;
- }
- if ((url->protocol == NULL) != (host_full == NULL))
- purple_debug_warning("http", "Protocol or host not present "
- "(unlikely case)\n");
-
- if (host_full) {
- gchar *port_str;
-
- if (!g_regex_match(purple_http_re_url_host, host_full, 0,
- &match_info))
- {
- if (purple_debug_is_verbose() &&
- purple_debug_is_unsafe())
- {
- purple_debug_warning("http",
- "Invalid host provided for URL: %s\n",
- raw_url);
- }
-
- g_free(host_full);
- purple_http_url_free(url);
- return NULL;
- }
-
- url->username = g_match_info_fetch(match_info, 1);
- url->password = g_match_info_fetch(match_info, 2);
- url->host = g_match_info_fetch(match_info, 3);
- port_str = g_match_info_fetch(match_info, 4);
-
- if (port_str && port_str[0])
- url->port = atoi(port_str);
-
- if (url->username[0] == '\0') {
- g_free(url->username);
- url->username = NULL;
- }
- if (url->password[0] == '\0') {
- g_free(url->password);
- url->password = NULL;
- }
- if (g_strcmp0(url->host, "") == 0) {
- g_free(url->host);
- url->host = NULL;
- } else if (url->host != NULL) {
- tmp = url->host;
- url->host = g_ascii_strdown(url->host, -1);
- g_free(tmp);
- }
-
- g_free(port_str);
- g_match_info_free(match_info);
-
- g_free(host_full);
- host_full = NULL;
- }
-
- if (url->host != NULL) {
- if (url->protocol == NULL)
- url->protocol = g_strdup("http");
- if (url->port == 0 && 0 == strcmp(url->protocol, "http"))
- url->port = 80;
- if (url->port == 0 && 0 == strcmp(url->protocol, "https"))
- url->port = 443;
- if (url->path == NULL)
- url->path = g_strdup("/");
- if (url->path[0] != '/')
- purple_debug_warning("http",
- "URL path doesn't start with slash\n");
- }
-
- return url;
-}
-
-void
-purple_http_url_free(PurpleHttpURL *parsed_url)
-{
- if (parsed_url == NULL)
- return;
-
- g_free(parsed_url->protocol);
- g_free(parsed_url->username);
- g_free(parsed_url->password);
- g_free(parsed_url->host);
- g_free(parsed_url->path);
- g_free(parsed_url->fragment);
- g_free(parsed_url);
-}
-
-void
-purple_http_url_relative(PurpleHttpURL *base_url, PurpleHttpURL *relative_url)
-{
- g_return_if_fail(base_url != NULL);
- g_return_if_fail(relative_url != NULL);
-
- if (relative_url->host) {
- g_free(base_url->protocol);
- base_url->protocol = g_strdup(relative_url->protocol);
- g_free(base_url->username);
- base_url->username = g_strdup(relative_url->username);
- g_free(base_url->password);
- base_url->password = g_strdup(relative_url->password);
- g_free(base_url->host);
- base_url->host = g_strdup(relative_url->host);
- base_url->port = relative_url->port;
-
- g_free(base_url->path);
- base_url->path = NULL;
- }
-
- if (relative_url->path) {
- if (relative_url->path[0] == '/' ||
- base_url->path == NULL)
- {
- g_free(base_url->path);
- base_url->path = g_strdup(relative_url->path);
- } else {
- gchar *last_slash = strrchr(base_url->path, '/');
- gchar *tmp;
- if (last_slash == NULL)
- base_url->path[0] = '\0';
- else
- last_slash[1] = '\0';
- tmp = base_url->path;
- base_url->path = g_strconcat(base_url->path,
- relative_url->path, NULL);
- g_free(tmp);
- }
- }
-
- g_free(base_url->fragment);
- base_url->fragment = g_strdup(relative_url->fragment);
-}
-
-gchar *
-purple_http_url_print(PurpleHttpURL *parsed_url)
-{
- GString *url = g_string_new("");
- gboolean before_host_printed = FALSE, host_printed = FALSE;
- gboolean port_is_default = FALSE;
-
- if (parsed_url->protocol) {
- g_string_append_printf(url, "%s://", parsed_url->protocol);
- before_host_printed = TRUE;
- if (parsed_url->port == 80 && 0 == strcmp(parsed_url->protocol,
- "http"))
- port_is_default = TRUE;
- if (parsed_url->port == 443 && 0 == strcmp(parsed_url->protocol,
- "https"))
- port_is_default = TRUE;
- }
- if (parsed_url->username || parsed_url->password) {
- if (parsed_url->username)
- g_string_append(url, parsed_url->username);
- g_string_append_c(url, ':');
- if (parsed_url->password)
- g_string_append(url, parsed_url->password);
- g_string_append(url, "@");
- before_host_printed = TRUE;
- }
- if (parsed_url->host || parsed_url->port) {
- if (!parsed_url->host)
- g_string_append_printf(url, "{???}:%d",
- parsed_url->port);
- else {
- g_string_append(url, parsed_url->host);
- if (!port_is_default)
- g_string_append_printf(url, ":%d",
- parsed_url->port);
- }
- host_printed = TRUE;
- }
- if (parsed_url->path) {
- if (!host_printed && before_host_printed)
- g_string_append(url, "{???}");
- g_string_append(url, parsed_url->path);
- }
- if (parsed_url->fragment)
- g_string_append_printf(url, "#%s", parsed_url->fragment);
-
- return g_string_free(url, FALSE);
-}
-
-const gchar *
-purple_http_url_get_protocol(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->protocol;
-}
-
-const gchar *
-purple_http_url_get_username(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->username;
-}
-
-const gchar *
-purple_http_url_get_password(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->password;
-}
-
-const gchar *
-purple_http_url_get_host(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->host;
-}
-
-int
-purple_http_url_get_port(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, 0);
-
- return parsed_url->port;
-}
-
-const gchar *
-purple_http_url_get_path(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->path;
-}
-
-const gchar *
-purple_http_url_get_fragment(const PurpleHttpURL *parsed_url)
-{
- g_return_val_if_fail(parsed_url != NULL, NULL);
-
- return parsed_url->fragment;
-}
-
-/*** HTTP Subsystem ***********************************************************/
-
-void purple_http_init(void)
-{
- purple_http_re_url = g_regex_new("^"
-
- "(?:" /* host part beginning */
- "([a-z]+)\\:/*" /* protocol */
- "([^/]+)" /* username, password, host, port */
- ")?" /* host part ending */
-
- "([^#]*)" /* path */
-
- "(?:#" "(.*)" ")?" /* fragment */
-
- "$", G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
- G_REGEX_MATCH_NOTEMPTY, NULL);
-
- purple_http_re_url_host = g_regex_new("^"
-
- "(?:" /* user credentials part beginning */
- "([" PURPLE_HTTP_URL_CREDENTIALS_CHARS "]+)" /* username */
- "(?::([" PURPLE_HTTP_URL_CREDENTIALS_CHARS "]+))" /* password */
- "@)?" /* user credentials part ending */
-
- "([a-z0-9.-]+)" /* host */
- "(?::([0-9]+))?" /* port*/
-
- "$", G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
- G_REGEX_MATCH_NOTEMPTY, NULL);
-
- purple_http_re_rfc1123 = g_regex_new(
- "^[a-z]+, " /* weekday */
- "([0-9]+) " /* date */
- "([a-z]+) " /* month */
- "([0-9]+) " /* year */
- "([0-9]+:[0-9]+:[0-9]+) " /* time */
- "(?:GMT|UTC)$",
- G_REGEX_OPTIMIZE | G_REGEX_CASELESS,
- G_REGEX_MATCH_NOTEMPTY, NULL);
-
- purple_http_hc_list = NULL;
- purple_http_hc_by_ptr = g_hash_table_new(g_direct_hash, g_direct_equal);
- purple_http_hc_by_gc = g_hash_table_new_full(g_direct_hash,
- g_direct_equal, NULL, (GDestroyNotify)g_list_free);
- purple_http_cancelling_gc = g_hash_table_new(g_direct_hash, g_direct_equal);
-}
-
-static void purple_http_foreach_conn_cancel(gpointer _hc, gpointer user_data)
-{
- PurpleHttpConnection *hc = _hc;
- purple_http_conn_cancel(hc);
-}
-
-void purple_http_uninit(void)
-{
- g_regex_unref(purple_http_re_url);
- purple_http_re_url = NULL;
- g_regex_unref(purple_http_re_url_host);
- purple_http_re_url_host = NULL;
- g_regex_unref(purple_http_re_rfc1123);
- purple_http_re_rfc1123 = NULL;
-
- if (purple_http_hc_list != NULL) {
- g_list_foreach(purple_http_hc_list, purple_http_foreach_conn_cancel, NULL);
- }
-
- if (purple_http_hc_list != NULL ||
- 0 != g_hash_table_size(purple_http_hc_by_ptr) ||
- 0 != g_hash_table_size(purple_http_hc_by_gc))
- purple_debug_warning("http",
- "Couldn't cleanup all connections.\n");
-
- g_list_free(purple_http_hc_list);
- purple_http_hc_list = NULL;
- g_hash_table_destroy(purple_http_hc_by_gc);
- purple_http_hc_by_gc = NULL;
- g_hash_table_destroy(purple_http_hc_by_ptr);
- purple_http_hc_by_ptr = NULL;
- g_hash_table_destroy(purple_http_cancelling_gc);
- purple_http_cancelling_gc = NULL;
-}
--- a/libpurple/http.h Fri Oct 18 01:33:51 2019 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,984 +0,0 @@
-/* purple
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
- */
-
-#ifndef PURPLE_HTTP_H
-#define PURPLE_HTTP_H
-/**
- * SECTION:http
- * @section_id: libpurple-http
- * @short_description: <filename>http.h</filename>
- * @title: HTTP API
- */
-
-#include <glib.h>
-
-#include "connection.h"
-
-/**
- * PurpleHttpRequest:
- *
- * A structure containing all data required to generate a single HTTP request.
- */
-typedef struct _PurpleHttpRequest PurpleHttpRequest;
-
-/**
- * PurpleHttpConnection:
- *
- * A representation of actually running HTTP request. Can be used to cancel the
- * request.
- */
-typedef struct _PurpleHttpConnection PurpleHttpConnection;
-
-/**
- * PurpleHttpResponse:
- *
- * All information got with response for HTTP request.
- */
-typedef struct _PurpleHttpResponse PurpleHttpResponse;
-
-/**
- * PurpleHttpURL:
- *
- * Parsed representation for the URL.
- */
-typedef struct _PurpleHttpURL PurpleHttpURL;
-
-/**
- * PurpleHttpCookieJar:
- *
- * An collection of cookies, got from HTTP response or provided for HTTP
- * request.
- */
-typedef struct _PurpleHttpCookieJar PurpleHttpCookieJar;
-
-/**
- * PurpleHttpKeepalivePool:
- *
- * A pool of TCP connections for HTTP Keep-Alive session.
- */
-typedef struct _PurpleHttpKeepalivePool PurpleHttpKeepalivePool;
-
-/**
- * PurpleHttpConnectionSet:
- *
- * A set of running HTTP requests. Can be used to cancel all of them at once.
- */
-typedef struct _PurpleHttpConnectionSet PurpleHttpConnectionSet;
-
-/**
- * PurpleHttpCallback:
- *
- * An callback called after performing (successfully or not) HTTP request.
- */
-typedef void (*PurpleHttpCallback)(PurpleHttpConnection *http_conn,
- PurpleHttpResponse *response, gpointer user_data);
-
-/**
- * PurpleHttpContentReaderCb:
- *
- * An callback called after storing data requested by PurpleHttpContentReader.
- */
-typedef void (*PurpleHttpContentReaderCb)(PurpleHttpConnection *http_conn,
- gboolean success, gboolean eof, size_t stored);
-
-/**
- * PurpleHttpContentReader:
- * @http_conn: Connection, which requests data.
- * @buffer: Buffer to store data to (with offset ignored).
- * @offset: Position, from where to read data.
- * @length: Length of data to read.
- * @user_data: The user data passed with callback function.
- * @cb: The function to call after storing data to buffer.
- *
- * An callback for getting large request contents (ie. from file stored on
- * disk).
- */
-typedef void (*PurpleHttpContentReader)(PurpleHttpConnection *http_conn,
- gchar *buffer, size_t offset, size_t length, gpointer user_data,
- PurpleHttpContentReaderCb cb);
-
-/**
- * PurpleHttpContentWriter:
- * @http_conn: Connection, which requests data.
- * @response: Response at point got so far (may change later).
- * @buffer: Buffer to read data from (with offset ignored).
- * @offset: Position of data got (its value is offset + length of
- * previous call), can be safely ignored.
- * @length: Length of data read.
- * @user_data: The user data passed with callback function.
- *
- * An callback for writting large response contents.
- *
- * Returns: TRUE, if succeeded, FALSE otherwise.
- */
-typedef gboolean (*PurpleHttpContentWriter)(PurpleHttpConnection *http_conn,
- PurpleHttpResponse *response, const gchar *buffer, size_t offset,
- size_t length, gpointer user_data);
-
-/**
- * PurpleHttpProgressWatcher:
- * @http_conn: The HTTP Connection.
- * @reading_state: FALSE, is we are sending the request, TRUE, when reading
- * the response.
- * @processed: The amount of data already processed.
- * @total: Total amount of data (in current state).
- * @user_data: The user data passed with callback function.
- *
- * An callback for watching HTTP connection progress.
- */
-typedef void (*PurpleHttpProgressWatcher)(PurpleHttpConnection *http_conn,
- gboolean reading_state, int processed, int total, gpointer user_data);
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* Performing HTTP requests */
-/**************************************************************************/
-
-/**
- * purple_http_get: (skip)
- * @gc: The connection for which the request is needed, or NULL.
- * @callback: (scope call): The callback function.
- * @user_data: The user data to pass to the callback function.
- * @url: The URL.
- *
- * Fetches the data from a URL with GET request, and passes it to a callback
- * function.
- *
- * Returns: The HTTP connection struct.
- */
-PurpleHttpConnection * purple_http_get(PurpleConnection *gc,
- PurpleHttpCallback callback, gpointer user_data, const gchar *url);
-
-/**
- * purple_http_get_printf: (skip)
- * @gc: The connection for which the request is needed, or NULL.
- * @callback: (scope call): The callback function.
- * @user_data: The user data to pass to the callback function.
- * @format: The format string.
- * @...: The parameters to insert into the format string.
- *
- * Constructs an URL and fetches the data from it with GET request, then passes
- * it to a callback function.
- *
- * Returns: The HTTP connection struct.
- */
-PurpleHttpConnection * purple_http_get_printf(PurpleConnection *gc,
- PurpleHttpCallback callback, gpointer user_data,
- const gchar *format, ...) G_GNUC_PRINTF(4, 5);
-
-/**
- * purple_http_request: (skip)
- * @gc: The connection for which the request is needed, or NULL.
- * @request: The request.
- * @callback: (scope call): The callback function.
- * @user_data: The user data to pass to the callback function.
- *
- * Fetches a HTTP request and passes the response to a callback function.
- * Provided request struct can be shared by multiple http requests but can not
- * be modified when any of these is running.
- *
- * Returns: The HTTP connection struct.
- */
-PurpleHttpConnection * purple_http_request(PurpleConnection *gc,
- PurpleHttpRequest *request, PurpleHttpCallback callback,
- gpointer user_data);
-
-/**************************************************************************/
-/* HTTP connection API */
-/**************************************************************************/
-
-/**
- * purple_http_conn_cancel: (skip)
- * @http_conn: The data returned when you initiated the HTTP request.
- *
- * Cancel a pending HTTP request.
- */
-void purple_http_conn_cancel(PurpleHttpConnection *http_conn);
-
-/**
- * purple_http_conn_cancel_all: (skip)
- * @gc: The handle.
- *
- * Cancels all HTTP connections associated with the specified handle.
- */
-void purple_http_conn_cancel_all(PurpleConnection *gc);
-
-/**
- * purple_http_conn_is_running: (skip)
- * @http_conn: The HTTP connection (may be invalid pointer).
- *
- * Checks, if provided HTTP request is running.
- *
- * Returns: TRUE, if provided connection is currently running.
- */
-gboolean purple_http_conn_is_running(PurpleHttpConnection *http_conn);
-
-/**
- * purple_http_conn_get_request: (skip)
- * @http_conn: The HTTP connection.
- *
- * Gets PurpleHttpRequest used for specified HTTP connection.
- *
- * Returns: The PurpleHttpRequest object.
- */
-PurpleHttpRequest * purple_http_conn_get_request(
- PurpleHttpConnection *http_conn);
-
-/**
- * purple_http_conn_get_cookie_jar: (skip)
- * @http_conn: The HTTP connection.
- *
- * Gets cookie jar used within connection.
- *
- * Returns: The cookie jar.
- */
-PurpleHttpCookieJar * purple_http_conn_get_cookie_jar(
- PurpleHttpConnection *http_conn);
-
-/**
- * purple_http_conn_get_purple_connection: (skip)
- * @http_conn: The HTTP connection.
- *
- * Gets PurpleConnection tied with specified HTTP connection.
- *
- * Returns: The PurpleConnection object.
- */
-PurpleConnection * purple_http_conn_get_purple_connection(
- PurpleHttpConnection *http_conn);
-
-/**
- * purple_http_conn_set_progress_watcher: (skip)
- * @http_conn: The HTTP connection.
- * @watcher: (scope call): The watcher.
- * @user_data: The user data to pass to the callback function.
- * @interval_threshold: Minimum interval (in microseconds) of calls to
- * watcher, or -1 for default.
- *
- * Sets the watcher, called after writing or reading data to/from HTTP stream.
- * May be used for updating transfer progress gauge.
- */
-void purple_http_conn_set_progress_watcher(PurpleHttpConnection *http_conn,
- PurpleHttpProgressWatcher watcher, gpointer user_data,
- gint interval_threshold);
-
-
-/**************************************************************************/
-/* URL processing API */
-/**************************************************************************/
-
-/**
- * purple_http_url_parse: (skip)
- * @url: The URL to parse.
- *
- * Parses a URL.
- *
- * The returned data must be freed with purple_http_url_free.
- *
- * Returns: The parsed url or NULL, if the URL is invalid.
- */
-PurpleHttpURL *
-purple_http_url_parse(const char *url);
-
-/**
- * purple_http_url_free: (skip)
- * @parsed_url: The parsed URL struct, or NULL.
- *
- * Frees the parsed URL struct.
- */
-void
-purple_http_url_free(PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_relative: (skip)
- * @base_url: The base URL. The result is stored here.
- * @relative_url: The relative URL.
- *
- * Converts the base URL to the absolute form of the provided relative URL.
- *
- * Example: "https://example.com/path/to/file.html" + "subdir/other-file.html" =
- * "https://example.com/path/to/subdir/another-file.html"
- */
-void
-purple_http_url_relative(PurpleHttpURL *base_url, PurpleHttpURL *relative_url);
-
-/**
- * purple_http_url_print: (skip)
- * @parsed_url: The URL struct.
- *
- * Converts the URL struct to the printable form. The result may not be a valid
- * URL (in cases, when the struct doesn't have all fields filled properly).
- *
- * The result must be g_free'd.
- *
- * Returns: The printable form of the URL.
- */
-gchar *
-purple_http_url_print(PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_protocol: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the protocol part of URL.
- *
- * Returns: The protocol.
- */
-const gchar *
-purple_http_url_get_protocol(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_username: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the username part of URL.
- *
- * Returns: The username.
- */
-const gchar *
-purple_http_url_get_username(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_password: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the password part of URL.
- *
- * Returns: The password.
- */
-const gchar *
-purple_http_url_get_password(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_host: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the hostname part of URL.
- *
- * Returns: The hostname.
- */
-const gchar *
-purple_http_url_get_host(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_port: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the port part of URL.
- *
- * Returns: The port number.
- */
-int
-purple_http_url_get_port(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_path: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the path part of URL.
- *
- * Returns: The path.
- */
-const gchar *
-purple_http_url_get_path(const PurpleHttpURL *parsed_url);
-
-/**
- * purple_http_url_get_fragment: (skip)
- * @parsed_url: The URL struct.
- *
- * Gets the fragment part of URL.
- *
- * Returns: The fragment.
- */
-const gchar *
-purple_http_url_get_fragment(const PurpleHttpURL *parsed_url);
-
-
-/**************************************************************************/
-/* Cookie jar API */
-/**************************************************************************/
-
-/**
- * purple_http_cookie_jar_new: (skip)
- *
- * Creates new cookie jar,
- *
- * Returns: empty cookie jar.
- */
-PurpleHttpCookieJar * purple_http_cookie_jar_new(void);
-
-/**
- * purple_http_cookie_jar_ref: (skip)
- * @cookie_jar: The cookie jar.
- *
- * Increment the reference count.
- */
-void purple_http_cookie_jar_ref(PurpleHttpCookieJar *cookie_jar);
-
-/**
- * purple_http_cookie_jar_unref: (skip)
- * @cookie_jar: The cookie jar.
- *
- * Decrement the reference count.
- *
- * If the reference count reaches zero, the cookie jar will be freed.
- *
- * Returns: @cookie_jar or %NULL if the reference count reached zero.
- */
-PurpleHttpCookieJar * purple_http_cookie_jar_unref(
- PurpleHttpCookieJar *cookie_jar);
-
-/**
- * purple_http_cookie_jar_set: (skip)
- * @cookie_jar: The cookie jar.
- * @name: Cookie name.
- * @value: Cookie contents.
- *
- * Sets the cookie.
- */
-void purple_http_cookie_jar_set(PurpleHttpCookieJar *cookie_jar,
- const gchar *name, const gchar *value);
-
-/**
- * purple_http_cookie_jar_get: (skip)
- * @cookie_jar: The cookie jar.
- * @name: Cookie name.
- *
- * Gets the cookie.
- *
- * The result must be g_free'd.
- *
- * Returns: Cookie contents, or NULL, if cookie doesn't exists.
- */
-gchar * purple_http_cookie_jar_get(PurpleHttpCookieJar *cookie_jar,
- const gchar *name);
-
-/**
- * purple_http_cookie_jar_is_empty: (skip)
- * @cookie_jar: The cookie jar.
- *
- * Checks, if the cookie jar contains any cookies.
- *
- * Returns: TRUE, if cookie jar contains any cookie, FALSE otherwise.
- */
-gboolean purple_http_cookie_jar_is_empty(PurpleHttpCookieJar *cookie_jar);
-
-
-/**************************************************************************/
-/* HTTP Request API */
-/**************************************************************************/
-
-/**
- * purple_http_request_new: (skip)
- * @url: The URL to request for, or NULL to leave empty (to be set with
- * purple_http_request_set_url).
- *
- * Creates the new instance of HTTP request configuration.
- *
- * Returns: The new instance of HTTP request struct.
- */
-PurpleHttpRequest * purple_http_request_new(const gchar *url);
-
-/**
- * purple_http_request_ref: (skip)
- * @request: The request.
- *
- * Increment the reference count.
- */
-void purple_http_request_ref(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_unref: (skip)
- * @request: The request.
- *
- * Decrement the reference count.
- *
- * If the reference count reaches zero, the http request struct will be freed.
- *
- * Returns: @request or %NULL if the reference count reached zero.
- */
-PurpleHttpRequest * purple_http_request_unref(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_url: (skip)
- * @request: The request.
- * @url: The url.
- *
- * Sets URL for HTTP request.
- */
-void purple_http_request_set_url(PurpleHttpRequest *request, const gchar *url);
-
-/**
- * purple_http_request_set_url_printf: (skip)
- * @request: The request.
- * @format: The format string.
- * @...: The parameters to insert into the format string.
- *
- * Constructs and sets an URL for HTTP request.
- */
-void purple_http_request_set_url_printf(PurpleHttpRequest *request,
- const gchar *format, ...) G_GNUC_PRINTF(2, 3);
-
-/**
- * purple_http_request_get_url: (skip)
- * @request: The request.
- *
- * Gets URL set for the HTTP request.
- *
- * Returns: URL set for this request.
- */
-const gchar * purple_http_request_get_url(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_method: (skip)
- * @request: The request.
- * @method: The method, or NULL for default.
- *
- * Sets custom HTTP method used for the request.
- */
-void purple_http_request_set_method(PurpleHttpRequest *request,
- const gchar *method);
-
-/**
- * purple_http_request_get_method: (skip)
- * @request: The request.
- *
- * Gets HTTP method set for the request.
- *
- * Returns: The method.
- */
-const gchar * purple_http_request_get_method(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_keepalive_pool: (skip)
- * @request: The request.
- * @pool: The new KeepAlive pool, or NULL to reset.
- *
- * Sets HTTP KeepAlive connections pool for the request.
- *
- * It increases pool's reference count.
- */
-void
-purple_http_request_set_keepalive_pool(PurpleHttpRequest *request,
- PurpleHttpKeepalivePool *pool);
-
-/**
- * purple_http_request_get_keepalive_pool: (skip)
- * @request: The request.
- *
- * Gets HTTP KeepAlive connections pool associated with the request.
- *
- * It doesn't affect pool's reference count.
- *
- * Returns: The KeepAlive pool, used for the request.
- */
-PurpleHttpKeepalivePool *
-purple_http_request_get_keepalive_pool(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_contents: (skip)
- * @request: The request.
- * @contents: The contents.
- * @length: The length of contents (-1 if it's a NULL-terminated string)
- *
- * Sets contents of HTTP request (for example, POST data).
- */
-void purple_http_request_set_contents(PurpleHttpRequest *request,
- const gchar *contents, int length);
-
-/**
- * purple_http_request_set_contents_reader: (skip)
- * @request: The request.
- * @reader: (scope call): The reader callback.
- * @contents_length: The size of all contents.
- * @user_data: The user data to pass to the callback function.
- *
- * Sets contents reader for HTTP request, used mainly for possible large
- * uploads.
- */
-void purple_http_request_set_contents_reader(PurpleHttpRequest *request,
- PurpleHttpContentReader reader, int contents_length, gpointer user_data);
-
-/**
- * purple_http_request_set_response_writer: (skip)
- * @request: The request.
- * @writer: (scope call): The writer callback, or %NULL to remove existing.
- * @user_data: The user data to pass to the callback function.
- *
- * Set contents writer for HTTP response.
- */
-void purple_http_request_set_response_writer(PurpleHttpRequest *request,
- PurpleHttpContentWriter writer, gpointer user_data);
-
-/**
- * purple_http_request_set_timeout: (skip)
- * @request: The request.
- * @timeout: Time (in seconds) after that timeout will be cancelled,
- * -1 for infinite time.
- *
- * Set maximum amount of time, that request is allowed to run.
- */
-void purple_http_request_set_timeout(PurpleHttpRequest *request, int timeout);
-
-/**
- * purple_http_request_get_timeout: (skip)
- * @request: The request.
- *
- * Get maximum amount of time, that request is allowed to run.
- *
- * Returns: Timeout currently set (-1 for infinite).
- */
-int purple_http_request_get_timeout(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_max_redirects: (skip)
- * @request: The request.
- * @max_redirects: Maximum amount of redirects, or -1 for unlimited.
- *
- * Sets maximum amount of redirects.
- */
-void purple_http_request_set_max_redirects(PurpleHttpRequest *request,
- int max_redirects);
-
-/**
- * purple_http_request_get_max_redirects: (skip)
- * @request: The request.
- *
- * Gets maximum amount of redirects.
- *
- * Returns: Current maximum amount of redirects (-1 for unlimited).
- */
-int purple_http_request_get_max_redirects(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_cookie_jar: (skip)
- * @request: The request.
- * @cookie_jar: The cookie jar.
- *
- * Sets cookie jar used for the request.
- */
-void purple_http_request_set_cookie_jar(PurpleHttpRequest *request,
- PurpleHttpCookieJar *cookie_jar);
-
-/**
- * purple_http_request_get_cookie_jar: (skip)
- * @request: The request.
- *
- * Gets cookie jar used for the request.
- *
- * Returns: The cookie jar.
- */
-PurpleHttpCookieJar * purple_http_request_get_cookie_jar(
- PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_http11: (skip)
- * @request: The request.
- * @http11: TRUE for HTTP/1.1, FALSE for HTTP/1.0.
- *
- * Sets HTTP version to use.
- */
-void purple_http_request_set_http11(PurpleHttpRequest *request,
- gboolean http11);
-
-/**
- * purple_http_request_is_http11: (skip)
- * @request: The request.
- *
- * Gets used HTTP version.
- *
- * Returns: TRUE, if we use HTTP/1.1, FALSE for HTTP/1.0.
- */
-gboolean purple_http_request_is_http11(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_set_max_len: (skip)
- * @request: The request.
- * @max_len: Maximum length of response to read (-1 for the maximum
- * supported amount).
- *
- * Sets maximum length of response content to read.
- *
- * Headers length doesn't count here.
- *
- */
-void purple_http_request_set_max_len(PurpleHttpRequest *request, int max_len);
-
-/**
- * purple_http_request_get_max_len: (skip)
- * @request: The request.
- *
- * Gets maximum length of response content to read.
- *
- * Returns: Maximum length of response to read, or -1 if unlimited.
- */
-int purple_http_request_get_max_len(PurpleHttpRequest *request);
-
-/**
- * purple_http_request_header_set: (skip)
- * @request: The request.
- * @key: A header to be set.
- * @value: A value to set, or NULL to remove specified header.
- *
- * Sets (replaces, if exists) specified HTTP request header with provided value.
- *
- * See purple_http_request_header_add().
- */
-void purple_http_request_header_set(PurpleHttpRequest *request,
- const gchar *key, const gchar *value);
-
-/**
- * purple_http_request_header_set_printf: (skip)
- * @request: The request.
- * @key: A header to be set.
- * @format: The format string.
- *
- * Constructs and sets (replaces, if exists) specified HTTP request header.
- */
-void purple_http_request_header_set_printf(PurpleHttpRequest *request,
- const gchar *key, const gchar *format, ...) G_GNUC_PRINTF(3, 4);
-
-/**
- * purple_http_request_header_add: (skip)
- * @request: The request.
- * @key: A header to be set.
- * @value: A value to set.
- *
- * Adds (without replacing, if exists) an HTTP request header.
- *
- * See purple_http_request_header_set().
- */
-void purple_http_request_header_add(PurpleHttpRequest *request,
- const gchar *key, const gchar *value);
-
-
-/**************************************************************************/
-/* HTTP Keep-Alive pool API */
-/**************************************************************************/
-
-/**
- * purple_http_keepalive_pool_new: (skip)
- *
- * Creates a new HTTP Keep-Alive pool.
- */
-PurpleHttpKeepalivePool *
-purple_http_keepalive_pool_new(void);
-
-/**
- * purple_http_keepalive_pool_ref: (skip)
- * @pool: The HTTP Keep-Alive pool.
- *
- * Increment the reference count.
- */
-void
-purple_http_keepalive_pool_ref(PurpleHttpKeepalivePool *pool);
-
-/**
- * purple_http_keepalive_pool_unref: (skip)
- * @pool: The HTTP Keep-Alive pool.
- *
- * Decrement the reference count.
- *
- * If the reference count reaches zero, the pool will be freed and all
- * connections will be closed.
- *
- * Returns: @pool or %NULL if the reference count reached zero.
- */
-PurpleHttpKeepalivePool *
-purple_http_keepalive_pool_unref(PurpleHttpKeepalivePool *pool);
-
-/**
- * purple_http_keepalive_pool_set_limit_per_host: (skip)
- * @pool: The HTTP Keep-Alive pool.
- * @limit: The new limit, 0 for unlimited.
- *
- * Sets maximum allowed number of connections to specific host-triple (is_ssl +
- * hostname + port).
- */
-void
-purple_http_keepalive_pool_set_limit_per_host(PurpleHttpKeepalivePool *pool,
- guint limit);
-
-/**
- * purple_http_keepalive_pool_get_limit_per_host: (skip)
- * @pool: The HTTP Keep-Alive pool.
- *
- * Gets maximum allowed number of connections to specific host-triple (is_ssl +
- * hostname + port).
- *
- * Returns: The limit.
- */
-guint
-purple_http_keepalive_pool_get_limit_per_host(PurpleHttpKeepalivePool *pool);
-
-
-/**************************************************************************/
-/* HTTP connection set API */
-/**************************************************************************/
-
-/**
- * purple_http_connection_set_new: (skip)
- *
- * Creates a new connection set.
- *
- * Returns: A new connection set.
- */
-PurpleHttpConnectionSet *
-purple_http_connection_set_new(void);
-
-/**
- * purple_http_connection_set_destroy: (skip)
- * @set: The connection set to be destroyed
- *
- * Destroys connection set @set.
- */
-void
-purple_http_connection_set_destroy(PurpleHttpConnectionSet *set);
-
-/**
- * purple_http_connection_set_add: (skip)
- * @set: The connection set to add to
- * @http_conn: The connection to add
- *
- * Adds @http_conn to @set.
- */
-void
-purple_http_connection_set_add(PurpleHttpConnectionSet *set,
- PurpleHttpConnection *http_conn);
-
-
-/**************************************************************************/
-/* HTTP response API */
-/**************************************************************************/
-
-/**
- * purple_http_response_is_successful: (skip)
- * @response: The response.
- *
- * Checks, if HTTP request was performed successfully.
- *
- * Returns: TRUE, if request was performed successfully.
- */
-gboolean purple_http_response_is_successful(PurpleHttpResponse *response);
-
-/**
- * purple_http_response_get_code: (skip)
- * @response: The response.
- *
- * Gets HTTP response code.
- *
- * Returns: HTTP response code.
- */
-int purple_http_response_get_code(PurpleHttpResponse *response);
-
-/**
- * purple_http_response_get_error: (skip)
- * @response: The response.
- *
- * Gets error description.
- *
- * Returns: Localized error description or NULL, if there was no error.
- */
-const gchar * purple_http_response_get_error(PurpleHttpResponse *response);
-
-/**
- * purple_http_response_get_data_len: (skip)
- * @response: The response.
- *
- * Gets HTTP response data length.
- *
- * Returns: Data length;
- */
-gsize purple_http_response_get_data_len(PurpleHttpResponse *response);
-
-/**
- * purple_http_response_get_data: (skip)
- * @response: The response.
- * @len: Return address for the size of the data. Can be NULL.
- *
- * Gets HTTP response data.
- *
- * Response data is not written, if writer callback was set for request.
- *
- * Returns: The data.
- */
-const gchar * purple_http_response_get_data(PurpleHttpResponse *response, size_t *len);
-
-/**
- * purple_http_response_get_all_headers: (skip)
- * @response: The response.
- *
- * Gets all headers got with response.
- *
- * Returns: (element-type PurpleKeyValuePair) (transfer none): Keys are header
- * field names (gchar*) and values are its contents (gchar*).
- */
-const GList * purple_http_response_get_all_headers(PurpleHttpResponse *response);
-
-/**
- * purple_http_response_get_headers_by_name: (skip)
- * @response: The response.
- * @name: The name of header field.
- *
- * Gets all headers with specified name got with response.
- *
- * Returns: (element-type gchar*) (transfer none): Header field record contents.
- */
-const GList * purple_http_response_get_headers_by_name(
- PurpleHttpResponse *response, const gchar *name);
-
-/**
- * purple_http_response_get_header: (skip)
- * @response: The response.
- * @name: The name of header field.
- *
- * Gets one header contents with specified name got with response.
- *
- * To get all headers with the same name, use
- * purple_http_response_get_headers_by_name instead.
- *
- * Returns: Header field contents or NULL, if there is no such one.
- */
-const gchar * purple_http_response_get_header(PurpleHttpResponse *response,
- const gchar *name);
-
-
-/**************************************************************************/
-/* HTTP Subsystem */
-/**************************************************************************/
-
-/**
- * purple_http_init:
- *
- * Initializes the http subsystem.
- */
-void purple_http_init(void);
-
-/**
- * purple_http_uninit:
- *
- * Uninitializes the http subsystem.
- */
-void purple_http_uninit(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_HTTP_H */
--- a/libpurple/meson.build Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/meson.build Fri Oct 18 04:19:09 2019 +0000
@@ -21,7 +21,6 @@
'e2ee.c',
'eventloop.c',
'group.c',
- 'http.c',
'idle.c',
'image.c',
'image-store.c',
@@ -104,7 +103,6 @@
'e2ee.h',
'eventloop.h',
'group.h',
- 'http.h',
'idle.h',
'image.h',
'image-store.h',
--- a/libpurple/protocols/facebook/http.h Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/facebook/http.h Fri Oct 18 04:19:09 2019 +0000
@@ -34,8 +34,6 @@
#include <glib.h>
#include <libsoup/soup.h>
-#include <libpurple/http.h>
-
/**
* FB_HTTP_ERROR:
*
--- a/libpurple/protocols/gg/avatar.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/gg/avatar.c Fri Oct 18 04:19:09 2019 +0000
@@ -31,7 +31,6 @@
#include <debug.h>
#include <glibcompat.h>
-#include <http.h>
#include "gg.h"
#include "utils.h"
--- a/libpurple/protocols/gg/edisc.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/gg/edisc.c Fri Oct 18 04:19:09 2019 +0000
@@ -33,7 +33,6 @@
#include "gg.h"
#include "libgaduw.h"
#include "utils.h"
-#include <http.h>
#include <json-glib/json-glib.h>
--- a/libpurple/protocols/gg/oauth/oauth-purple.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/gg/oauth/oauth-purple.c Fri Oct 18 04:19:09 2019 +0000
@@ -35,7 +35,6 @@
#include "../xml.h"
#include <debug.h>
-#include <http.h>
#define GGP_OAUTH_RESPONSE_MAX 10240
--- a/libpurple/protocols/gg/pubdir-prpl.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/gg/pubdir-prpl.c Fri Oct 18 04:19:09 2019 +0000
@@ -31,7 +31,6 @@
#include "gg.h"
#include <debug.h>
-#include <http.h>
#include <request.h>
#include "oauth/oauth-purple.h"
--- a/libpurple/protocols/jabber/bosh.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/bosh.c Fri Oct 18 04:19:09 2019 +0000
@@ -23,7 +23,6 @@
#include "internal.h"
#include "core.h"
#include "debug.h"
-#include "http.h"
#include <libsoup/soup.h>
--- a/libpurple/protocols/jabber/google/relay.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/google/relay.c Fri Oct 18 04:19:09 2019 +0000
@@ -20,7 +20,6 @@
#include "internal.h"
#include "debug.h"
-#include "http.h"
#include "relay.h"
--- a/libpurple/protocols/jabber/jabber.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.c Fri Oct 18 04:19:09 2019 +0000
@@ -29,7 +29,6 @@
#include "connection.h"
#include "conversation.h"
#include "debug.h"
-#include "http.h"
#include "message.h"
#include "notify.h"
#include "pluginpref.h"
--- a/libpurple/protocols/jabber/jabber.h Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/jabber.h Fri Oct 18 04:19:09 2019 +0000
@@ -64,7 +64,6 @@
#include "attention.h"
#include "circularbuffer.h"
#include "connection.h"
-#include "http.h"
#include "media.h"
#include "mediamanager.h"
#include "protocol.h"
--- a/libpurple/protocols/jabber/oob.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/oob.c Fri Oct 18 04:19:09 2019 +0000
@@ -23,7 +23,6 @@
#include "internal.h"
#include "debug.h"
#include "xfer.h"
-#include "http.h"
#include "util.h"
#include "jabber.h"
--- a/libpurple/protocols/jabber/useravatar.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/jabber/useravatar.c Fri Oct 18 04:19:09 2019 +0000
@@ -25,7 +25,6 @@
#include <libsoup/soup.h>
-#include "http.h"
#include "useravatar.h"
#include "pep.h"
#include "debug.h"
--- a/libpurple/protocols/oscar/oscar.h Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/protocols/oscar/oscar.h Fri Oct 18 04:19:09 2019 +0000
@@ -33,7 +33,6 @@
#include "circularbuffer.h"
#include "debug.h"
#include "eventloop.h"
-#include "http.h"
#include "proxy.h"
#include "sslconn.h"
--- a/libpurple/proxy.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/proxy.c Fri Oct 18 04:19:09 2019 +0000
@@ -27,7 +27,6 @@
#include "internal.h"
#include "debug.h"
-#include "http.h"
#include "notify.h"
#include "prefs.h"
#include "proxy.h"
--- a/libpurple/upnp.c Fri Oct 18 01:33:51 2019 +0000
+++ b/libpurple/upnp.c Fri Oct 18 04:19:09 2019 +0000
@@ -27,7 +27,6 @@
#include "debug.h"
#include "eventloop.h"
-#include "http.h"
#include "network.h"
#include "proxy.h"
#include "signals.h"
--- a/pidgin/gtkprefs.c Fri Oct 18 01:33:51 2019 +0000
+++ b/pidgin/gtkprefs.c Fri Oct 18 04:19:09 2019 +0000
@@ -26,7 +26,6 @@
#include "pidgin.h"
#include "debug.h"
-#include "http.h"
#include "nat-pmp.h"
#include "notify.h"
#include "prefs.h"
--- a/pidgin/gtksmiley-manager.c Fri Oct 18 01:33:51 2019 +0000
+++ b/pidgin/gtksmiley-manager.c Fri Oct 18 04:19:09 2019 +0000
@@ -23,7 +23,6 @@
#include "internal.h"
#include "debug.h"
-#include "http.h"
#include "notify.h"
#include "smiley.h"
#include "smiley-custom.h"
--- a/pidgin/plugins/imgupload.c Fri Oct 18 01:33:51 2019 +0000
+++ b/pidgin/plugins/imgupload.c Fri Oct 18 04:19:09 2019 +0000
@@ -23,7 +23,6 @@
#include "debug.h"
#include "glibcompat.h"
-#include "http.h"
#include "version.h"
#include "gtk3compat.h"
--- a/pidgin/plugins/relnot.c Fri Oct 18 01:33:51 2019 +0000
+++ b/pidgin/plugins/relnot.c Fri Oct 18 04:19:09 2019 +0000
@@ -34,7 +34,6 @@
#include "gtkblist.h"
#include "gtkplugin.h"
#include "gtkutils.h"
-#include "http.h"
#include "notify.h"
#include "pidginicon.h"
#include "prefs.h"