summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>2013-07-23 20:48:25 +0200
committerTomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>2013-07-23 20:48:25 +0200
commitc1b60293efb827469aa250bb2a6cade988c0e6b8 (patch)
tree1b487839cb8565f2993bc4e22d4cf6dfc2cdcd7f
parent49087682770a35ae4cbff630359726ec5626e5e6 (diff)
downloadpidgin-c1b60293efb827469aa250bb2a6cade988c0e6b8.tar.gz
HTTP: get rid of the second msn's own HTTP implementation (for soap)
-rw-r--r--libpurple/http.c23
-rw-r--r--libpurple/protocols/msn/contact.c2
-rw-r--r--libpurple/protocols/msn/nexus.c16
-rw-r--r--libpurple/protocols/msn/oim.c5
-rw-r--r--libpurple/protocols/msn/session.c8
-rw-r--r--libpurple/protocols/msn/session.h4
-rw-r--r--libpurple/protocols/msn/soap.c750
-rw-r--r--libpurple/protocols/msn/soap.h14
8 files changed, 222 insertions, 600 deletions
diff --git a/libpurple/http.c b/libpurple/http.c
index 2a67da7dbb..2f296c289c 100644
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -703,6 +703,9 @@ static void _purple_http_error(PurpleHttpConnection *hc, const char *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);
}
@@ -1084,7 +1087,7 @@ static gboolean _purple_http_recv_loopbody(PurpleHttpConnection *hc, gint fd)
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, retrying...\n");
+ "expired (when reading), retrying...\n");
purple_http_conn_retry(hc);
return FALSE;
} else {
@@ -1289,6 +1292,15 @@ static void _purple_http_send(gpointer _hc, gint fd, PurpleInputCondition cond)
return;
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);
+ return;
+ }
+
_purple_http_error(hc, _("Error writing to %s: %s"),
hc->url->host, g_strerror(errno));
return;
@@ -1635,7 +1647,14 @@ purple_http_conn_retry(PurpleHttpConnection *http_conn)
void purple_http_conn_cancel_all(PurpleConnection *gc)
{
- GList *gc_list = g_hash_table_lookup(purple_http_hc_by_gc, 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(TRUE));
diff --git a/libpurple/protocols/msn/contact.c b/libpurple/protocols/msn/contact.c
index 437305a597..e5f18c230f 100644
--- a/libpurple/protocols/msn/contact.c
+++ b/libpurple/protocols/msn/contact.c
@@ -288,7 +288,7 @@ msn_contact_request(MsnCallbackState *state)
xmlnode_free(state->token->child);
xmlnode_insert_data(state->token,
msn_nexus_get_token_str(state->session->nexus, MSN_AUTH_CONTACTS), -1);
- msn_soap_message_send(state->session,
+ msn_soap_service_send_message(state->session->soap,
msn_soap_message_new(state->post_action, xmlnode_copy(state->body)),
MSN_CONTACT_SERVER, state->post_url, FALSE,
msn_contact_request_cb, state);
diff --git a/libpurple/protocols/msn/nexus.c b/libpurple/protocols/msn/nexus.c
index 95ddbbb3a7..5a8aafc43d 100644
--- a/libpurple/protocols/msn/nexus.c
+++ b/libpurple/protocols/msn/nexus.c
@@ -376,8 +376,6 @@ msn_nexus_connect(MsnNexus *nexus)
char *request;
int i;
- MsnSoapMessage *soap;
-
purple_debug_info("msn", "Starting Windows Live ID authentication\n");
msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
@@ -409,10 +407,11 @@ msn_nexus_connect(MsnNexus *nexus)
g_free(password_xml);
g_string_free(domains, TRUE);
- soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
+ msn_soap_service_send_message(session->soap,
+ msn_soap_message_new(NULL, xmlnode_from_str(request, -1)),
+ MSN_SSO_SERVER, SSO_POST_URL, TRUE,
+ nexus_got_response_cb, nexus);
g_free(request);
- msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE,
- nexus_got_response_cb, nexus);
}
static void
@@ -532,7 +531,6 @@ msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data)
guchar signature[20];
char *request;
- MsnSoapMessage *soap;
update = g_new0(MsnNexusUpdateCallback, 1);
update->cb = cb;
@@ -623,10 +621,10 @@ msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data)
g_free(signedinfo);
g_free(domain);
- soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1));
g_free(request);
- msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE,
- nexus_got_update_cb, ud);
+ msn_soap_service_send_message(session->soap,
+ msn_soap_message_new(NULL, xmlnode_from_str(request, -1)),
+ MSN_SSO_SERVER, SSO_POST_URL, TRUE, nexus_got_update_cb, ud);
}
GHashTable *
diff --git a/libpurple/protocols/msn/oim.c b/libpurple/protocols/msn/oim.c
index a08ee258f7..9b4101975e 100644
--- a/libpurple/protocols/msn/oim.c
+++ b/libpurple/protocols/msn/oim.c
@@ -244,10 +244,9 @@ msn_oim_request_helper(MsnOimRequestData *data)
xmlnode_insert_data(xml_p, msn_p, -1);
}
- msn_soap_message_send(session,
+ msn_soap_service_send_message(session->soap,
msn_soap_message_new(data->action, xmlnode_copy(data->body)),
- data->host, data->url, FALSE,
- msn_oim_request_cb, data);
+ data->host, data->url, FALSE, msn_oim_request_cb, data);
return FALSE;
}
diff --git a/libpurple/protocols/msn/session.c b/libpurple/protocols/msn/session.c
index 05dae91d7b..5fd88eba6b 100644
--- a/libpurple/protocols/msn/session.c
+++ b/libpurple/protocols/msn/session.c
@@ -55,6 +55,8 @@ msn_session_new(PurpleAccount *account)
session->guid = rand_guid();
+ session->soap = msn_soap_service_new(session);
+
return session;
}
@@ -73,11 +75,7 @@ msn_session_destroy(MsnSession *session)
if (session->connected)
msn_session_disconnect(session);
- if (session->soap_cleanup_handle)
- purple_timeout_remove(session->soap_cleanup_handle);
-
- if (session->soap_table != NULL)
- g_hash_table_destroy(session->soap_table);
+ msn_soap_service_destroy(session->soap);
while (session->slplinks != NULL)
msn_slplink_unref(session->slplinks->data);
diff --git a/libpurple/protocols/msn/session.h b/libpurple/protocols/msn/session.h
index 73b76fcc46..24a195a49a 100644
--- a/libpurple/protocols/msn/session.h
+++ b/libpurple/protocols/msn/session.h
@@ -66,6 +66,7 @@ typedef enum
#include "nexus.h"
#include "notification.h"
#include "oim.h"
+#include "soap.h"
#include "switchboard.h"
#include "user.h"
#include "userlist.h"
@@ -116,8 +117,7 @@ struct _MsnSession
gboolean email_enabled;
} passport_info;
- GHashTable *soap_table;
- guint soap_cleanup_handle;
+ MsnSoapService *soap;
char *guid;
GSList *http_reqs; /**< PurpleHttpConnection to be cancelled on exit */
diff --git a/libpurple/protocols/msn/soap.c b/libpurple/protocols/msn/soap.c
index 4e6814cdf5..fa2d0ed29e 100644
--- a/libpurple/protocols/msn/soap.c
+++ b/libpurple/protocols/msn/soap.c
@@ -25,668 +25,268 @@
#include "soap.h"
-#include "internal.h"
-
#include "debug.h"
#include "http.h"
-#define SOAP_TIMEOUT (5 * 60)
+typedef struct _MsnSoapRequest MsnSoapRequest;
struct _MsnSoapMessage {
gchar *action;
xmlnode *xml;
- GSList *headers;
};
-xmlnode *
-msn_soap_message_get_xml(MsnSoapMessage *message)
-{
- g_return_val_if_fail(message != NULL, NULL);
-
- return message->xml;
-}
-
-typedef struct _MsnSoapRequest {
- char *path;
+struct _MsnSoapRequest {
MsnSoapMessage *message;
- gboolean secure;
+ MsnSoapService *soaps;
MsnSoapCallback cb;
gpointer cb_data;
-} MsnSoapRequest;
+ gboolean secure;
+};
-typedef struct _MsnSoapConnection {
+struct _MsnSoapService {
MsnSession *session;
- char *host;
-
- time_t last_used;
- PurpleSslConnection *ssl;
- gboolean connected;
-
- guint event_handle;
- guint run_timer;
- GString *buf;
- gsize handled_len;
- gsize body_len;
- int response_code;
- gboolean headers_done;
- gboolean close_when_done;
-
- MsnSoapMessage *message;
-
- GQueue *queue;
- MsnSoapRequest *current_request;
-} MsnSoapConnection;
-
-static gboolean msn_soap_connection_run(gpointer data);
-
-static MsnSoapConnection *
-msn_soap_connection_new(MsnSession *session, const char *host)
-{
- MsnSoapConnection *conn = g_new0(MsnSoapConnection, 1);
- conn->session = session;
- conn->host = g_strdup(host);
- conn->queue = g_queue_new();
- return conn;
-}
-
-static void
-msn_soap_message_destroy(MsnSoapMessage *message)
-{
- g_slist_foreach(message->headers, (GFunc)g_free, NULL);
- g_slist_free(message->headers);
- g_free(message->action);
- if (message->xml)
- xmlnode_free(message->xml);
- g_free(message);
-}
+ PurpleHttpKeepalivePool *keepalive_pool;
+};
static void
-msn_soap_request_destroy(MsnSoapRequest *req, gboolean keep_message)
-{
- g_free(req->path);
- if (!keep_message)
- msn_soap_message_destroy(req->message);
- g_free(req);
-}
+msn_soap_service_send_message_simple(MsnSoapService *soaps,
+ MsnSoapMessage *message, const gchar *url, gboolean secure,
+ MsnSoapCallback cb, gpointer cb_data);
-static void
-msn_soap_connection_sanitize(MsnSoapConnection *conn, gboolean disconnect)
+MsnSoapMessage *
+msn_soap_message_new(const gchar *action, xmlnode *xml)
{
- if (conn->event_handle) {
- purple_input_remove(conn->event_handle);
- conn->event_handle = 0;
- }
+ MsnSoapMessage *msg;
- if (conn->run_timer) {
- purple_timeout_remove(conn->run_timer);
- conn->run_timer = 0;
- }
+ g_return_val_if_fail(xml != NULL, NULL);
- if (conn->message) {
- msn_soap_message_destroy(conn->message);
- conn->message = NULL;
- }
-
- if (conn->buf) {
- g_string_free(conn->buf, TRUE);
- conn->buf = NULL;
- }
+ msg = g_new0(MsnSoapMessage, 1);
+ msg->action = g_strdup(action);
+ msg->xml = xml;
- if (conn->ssl && (disconnect || conn->close_when_done)) {
- purple_ssl_close(conn->ssl);
- conn->ssl = NULL;
- }
-
- if (conn->current_request) {
- msn_soap_request_destroy(conn->current_request, FALSE);
- conn->current_request = NULL;
- }
+ return msg;
}
static void
-msn_soap_connection_destroy_foreach_cb(gpointer item, gpointer data)
-{
- MsnSoapRequest *req = item;
-
- req->cb(req->message, NULL, req->cb_data);
-
- msn_soap_request_destroy(req, FALSE);
-}
-
-static void
-msn_soap_connection_destroy(MsnSoapConnection *conn)
-{
- if (conn->current_request) {
- MsnSoapRequest *req = conn->current_request;
- conn->current_request = NULL;
- msn_soap_connection_destroy_foreach_cb(req, conn);
- }
-
- msn_soap_connection_sanitize(conn, TRUE);
- g_queue_foreach(conn->queue, msn_soap_connection_destroy_foreach_cb, conn);
- g_queue_free(conn->queue);
-
- g_free(conn->host);
- g_free(conn);
-}
-
-static gboolean
-msn_soap_cleanup_each(gpointer key, gpointer value, gpointer data)
+msn_soap_message_free(MsnSoapMessage *msg)
{
- MsnSoapConnection *conn = value;
- time_t *t = data;
-
- if ((*t - conn->last_used) > SOAP_TIMEOUT * 2) {
- purple_debug_info("soap", "cleaning up soap conn %p\n", conn);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-msn_soap_cleanup_for_session(gpointer data)
-{
- MsnSession *sess = data;
- time_t t = time(NULL);
-
- purple_debug_info("soap", "session cleanup timeout\n");
-
- if (sess->soap_table) {
- g_hash_table_foreach_remove(sess->soap_table, msn_soap_cleanup_each,
- &t);
-
- if (g_hash_table_size(sess->soap_table) != 0)
- return TRUE;
- }
+ if (msg == NULL)
+ return;
- sess->soap_cleanup_handle = 0;
- return FALSE;
+ g_free(msg->action);
+ if (msg->xml != NULL)
+ xmlnode_free(msg->xml);
+ g_free(msg);
}
-static MsnSoapConnection *
-msn_soap_get_connection(MsnSession *session, const char *host)
+xmlnode *
+msn_soap_message_get_xml(MsnSoapMessage *message)
{
- MsnSoapConnection *conn = NULL;
-
- if (session->soap_table) {
- conn = g_hash_table_lookup(session->soap_table, host);
- } else {
- session->soap_table = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, (GDestroyNotify)msn_soap_connection_destroy);
- }
-
- if (session->soap_cleanup_handle == 0)
- session->soap_cleanup_handle = purple_timeout_add_seconds(SOAP_TIMEOUT,
- msn_soap_cleanup_for_session, session);
-
- if (conn == NULL) {
- conn = msn_soap_connection_new(session, host);
- g_hash_table_insert(session->soap_table, conn->host, conn);
- }
-
- conn->last_used = time(NULL);
+ g_return_val_if_fail(message != NULL, NULL);
- return conn;
+ return message->xml;
}
static void
-msn_soap_connection_handle_next(MsnSoapConnection *conn)
+msn_soap_request_free(MsnSoapRequest *sreq)
{
- msn_soap_connection_sanitize(conn, FALSE);
+ g_return_if_fail(sreq != NULL);
- conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
+ msn_soap_message_free(sreq->message);
+ g_free(sreq);
}
-static void
-msn_soap_message_send_internal(MsnSession *session, MsnSoapMessage *message,
- const char *host, const char *path, gboolean secure,
- MsnSoapCallback cb, gpointer cb_data, gboolean first)
+MsnSoapService *
+msn_soap_service_new(MsnSession *session)
{
- MsnSoapConnection *conn = msn_soap_get_connection(session, host);
- MsnSoapRequest *req = g_new0(MsnSoapRequest, 1);
-
- req->path = g_strdup(path);
- req->message = message;
- req->secure = secure;
- req->cb = cb;
- req->cb_data = cb_data;
-
- if (first) {
- g_queue_push_head(conn->queue, req);
- } else {
- g_queue_push_tail(conn->queue, req);
- }
+ MsnSoapService *soaps;
- if (conn->run_timer == 0)
- conn->run_timer = purple_timeout_add(0, msn_soap_connection_run,
- conn);
-}
+ g_return_val_if_fail(session != NULL, NULL);
-void
-msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
- const char *host, const char *path, gboolean secure,
- MsnSoapCallback cb, gpointer cb_data)
-{
- g_return_if_fail(message != NULL);
- g_return_if_fail(cb != NULL);
+ soaps = g_new0(MsnSoapService, 1);
+ soaps->session = session;
+ soaps->keepalive_pool = purple_http_keepalive_pool_new();
+ purple_http_keepalive_pool_set_limit_per_host(soaps->keepalive_pool, 1);
- msn_soap_message_send_internal(session, message, host, path, secure,
- cb, cb_data, FALSE);
+ return soaps;
}
-static gboolean
-msn_soap_handle_redirect(MsnSoapConnection *conn, const char *url_raw)
+void
+msn_soap_service_destroy(MsnSoapService *soaps)
{
- MsnSoapRequest *req;
- PurpleHttpURL *url;
-
- url = purple_http_url_parse(url_raw);
- if (!url)
- return FALSE;
-
- req = conn->current_request;
- conn->current_request = NULL;
-
- msn_soap_message_send_internal(conn->session, req->message,
- purple_http_url_get_host(url), purple_http_url_get_path(url),
- req->secure, req->cb, req->cb_data, TRUE);
-
- msn_soap_request_destroy(req, TRUE);
-
- purple_http_url_free(url);
+ if (soaps == NULL)
+ return;
- return TRUE;
+ purple_http_keepalive_pool_unref(soaps->keepalive_pool);
+ g_free(soaps);
}
-static gboolean
-msn_soap_handle_body(MsnSoapConnection *conn, MsnSoapMessage *response)
+static void
+msn_soap_service_recv(PurpleHttpConnection *http_conn,
+ PurpleHttpResponse *response, gpointer _sreq)
{
- xmlnode *body = xmlnode_get_child(response->xml, "Body");
- xmlnode *fault = xmlnode_get_child(response->xml, "Fault");
+ MsnSoapRequest *sreq = _sreq;
+ xmlnode *xml_root, *xml_body, *xml_fault;
+ const gchar *xml_raw;
+ size_t xml_len;
- if (fault) {
- xmlnode *faultcode = xmlnode_get_child(fault, "faultcode");
+ if (purple_http_response_get_code(response) == 401) {
+ const gchar *errmsg;
- if (faultcode != NULL) {
- char *faultdata = xmlnode_get_data(faultcode);
+ purple_debug_error("msn-soap", "SOAP authentication failed\n");
- if (g_str_equal(faultdata, "psf:Redirect")) {
- xmlnode *url = xmlnode_get_child(fault, "redirectUrl");
+ errmsg = purple_http_response_get_header(response,
+ "WWW-Authenticate");
- if (url) {
- char *urldata = xmlnode_get_data(url);
- msn_soap_handle_redirect(conn, urldata);
- g_free(urldata);
- }
+ msn_session_set_error(sreq->soaps->session, MSN_ERROR_AUTH,
+ errmsg ? purple_url_decode(errmsg) : NULL);
- g_free(faultdata);
- msn_soap_message_destroy(response);
- return TRUE;
- } else if (g_str_equal(faultdata, "wsse:FailedAuthentication")) {
- xmlnode *reason = xmlnode_get_child(fault, "faultstring");
- char *reasondata = xmlnode_get_data(reason);
-
- msn_soap_connection_sanitize(conn, TRUE);
- msn_session_set_error(conn->session, MSN_ERROR_AUTH,
- reasondata);
-
- g_free(reasondata);
- g_free(faultdata);
- msn_soap_message_destroy(response);
- return FALSE;
- }
-
- g_free(faultdata);
- }
+ msn_soap_request_free(sreq);
+ return;
}
-
- if (fault || body) {
- if (conn->current_request) {
- MsnSoapRequest *request = conn->current_request;
- conn->current_request = NULL;
- request->cb(request->message, response,
- request->cb_data);
- msn_soap_request_destroy(request, FALSE);
- }
- msn_soap_message_destroy(response);
+ if (!purple_http_response_is_successfull(response)) {
+ purple_debug_error("msn-soap", "SOAP request failed\n");
+ msn_session_set_error(sreq->soaps->session,
+ MSN_ERROR_SERV_UNAVAILABLE, NULL);
+ msn_soap_request_free(sreq);
+ return;
}
- return TRUE;
-}
-
-static void
-msn_soap_message_add_header(MsnSoapMessage *message,
- const char *name, const char *value)
-{
- char *header = g_strdup_printf("%s: %s\r\n", name, value);
+ xml_raw = purple_http_response_get_data(response, &xml_len);
+ xml_root = xmlnode_from_str(xml_raw, xml_len);
- message->headers = g_slist_prepend(message->headers, header);
-}
-
-static void
-msn_soap_process(MsnSoapConnection *conn)
-{
- gboolean handled = FALSE;
- char *cursor;
- char *linebreak;
-
- cursor = conn->buf->str + conn->handled_len;
-
- if (!conn->headers_done) {
- while ((linebreak = strstr(cursor, "\r\n")) != NULL) {
- conn->handled_len = linebreak - conn->buf->str + 2;
-
- if (conn->response_code == 0) {
- if (sscanf(cursor, "HTTP/1.1 %d", &conn->response_code) != 1) {
- /* something horribly wrong */
- purple_ssl_close(conn->ssl);
- conn->ssl = NULL;
- handled = TRUE;
- break;
- } else if (conn->response_code == 503 && conn->session->login_step < MSN_LOGIN_STEP_END) {
- msn_soap_connection_sanitize(conn, TRUE);
- msn_session_set_error(conn->session, MSN_ERROR_SERV_UNAVAILABLE, NULL);
- return;
- }
- } else if (cursor == linebreak) {
- /* blank line */
- conn->headers_done = TRUE;
- cursor = conn->buf->str + conn->handled_len;
- break;
- } else {
- char *line = g_strndup(cursor, linebreak - cursor);
- char *sep = strstr(line, ": ");
- char *key = line;
- char *value;
-
- if (sep == NULL) {
- purple_debug_info("soap", "ignoring malformed line: %s\n", line);
- g_free(line);
- goto loop_end;
- }
-
- value = sep + 2;
- *sep = '\0';
- msn_soap_message_add_header(conn->message, key, value);
-
- if ((conn->response_code == 301 || conn->response_code == 300)
- && strcmp(key, "Location") == 0) {
-
- msn_soap_handle_redirect(conn, value);
-
- handled = TRUE;
- g_free(line);
- break;
- } else if (conn->response_code == 401 &&
- strcmp(key, "WWW-Authenticate") == 0) {
- char *error = strstr(value, "cbtxt=");
-
- if (error) {
- error += strlen("cbtxt=");
- }
-
- msn_soap_connection_sanitize(conn, TRUE);
- msn_session_set_error(conn->session, MSN_ERROR_AUTH,
- error ? purple_url_decode(error) : NULL);
-
- g_free(line);
- return;
- } else if (strcmp(key, "Content-Length") == 0) {
- if (sscanf(value, "%" G_GSIZE_FORMAT, &(conn->body_len)) != 1)
- purple_debug_error("soap", "Unable to parse Content-Length\n");
- } else if (strcmp(key, "Connection") == 0) {
- if (strcmp(value, "close") == 0) {
- conn->close_when_done = TRUE;
- }
- }
- g_free(line);
- }
-
- loop_end:
- cursor = conn->buf->str + conn->handled_len;
+ if (purple_debug_is_verbose()) {
+ if (sreq->secure && !purple_debug_is_unsafe()) {
+ purple_debug_misc("msn-soap",
+ "Received secure SOAP request.\n");
+ } else {
+ purple_debug_misc("msn-soap",
+ "Received SOAP request: %s\n", xml_raw);
}
}
- if (!handled && conn->headers_done) {
- if (conn->buf->len - conn->handled_len >=
- conn->body_len) {
- xmlnode *node = xmlnode_from_str(cursor, conn->body_len);
-
- if (node == NULL) {
- purple_debug_info("soap", "Malformed SOAP response: %s\n",
- cursor);
- } else {
- MsnSoapMessage *message = conn->message;
- conn->message = NULL;
- message->xml = node;
-
- if (!msn_soap_handle_body(conn, message)) {
- return;
- }
- }
-
- msn_soap_connection_handle_next(conn);
- }
-
+ if (xml_root == NULL) {
+ purple_debug_error("msn-soap", "SOAP response malformed\n");
+ msn_session_set_error(sreq->soaps->session,
+ MSN_ERROR_HTTP_MALFORMED, NULL);
+ msn_soap_request_free(sreq);
return;
}
- if (handled) {
- msn_soap_connection_handle_next(conn);
- }
-}
-
-static void
-msn_soap_read_cb(gpointer data, gint fd, PurpleInputCondition cond)
-{
- MsnSoapConnection *conn = data;
- int count = 0, cnt, perrno;
- /* This buffer needs to be larger than any packets received from
- login.live.com or Adium will fail to receive the packet
- (something weird with the login.live.com server). With NSS it works
- fine, so I believe it's some bug with OS X */
- char buf[16 * 1024];
- gsize cursor;
-
- if (conn->message == NULL) {
- conn->message = msn_soap_message_new(NULL, NULL);
- }
+ xml_body = xmlnode_get_child(xml_root, "Body");
+ xml_fault = xmlnode_get_child(xml_root, "Fault");
- if (conn->buf == NULL) {
- conn->buf = g_string_new_len(buf, 0);
- }
+ if (xml_fault != NULL) {
+ xmlnode *xml_faultcode;
+ gchar *faultdata = NULL;
- cursor = conn->buf->len;
- while ((cnt = purple_ssl_read(conn->ssl, buf, sizeof(buf))) > 0) {
- purple_debug_info("soap", "read %d bytes\n", cnt);
- count += cnt;
- g_string_append_len(conn->buf, buf, cnt);
- }
+ xml_faultcode = xmlnode_get_child(xml_fault, "faultcode");
+ if (xml_faultcode != NULL)
+ faultdata = xmlnode_get_data(xml_faultcode);
- perrno = errno;
- if (cnt < 0 && perrno != EAGAIN)
- purple_debug_info("soap", "read: %s\n", g_strerror(perrno));
+ if (g_strcmp0(faultdata, "psf:Redirect") == 0) {
+ xmlnode *xml_url;
+ gchar *url = NULL;
- if (conn->current_request && conn->current_request->secure &&
- !purple_debug_is_unsafe())
- purple_debug_misc("soap", "Received secure request.\n");
- else if (count != 0)
- purple_debug_misc("soap", "current %s\n", conn->buf->str + cursor);
+ xml_url = xmlnode_get_child(xml_fault, "redirectUrl");
+ if (xml_url != NULL)
+ url = xmlnode_get_data(xml_url);
- /* && count is necessary for Adium, on OS X the last read always
- return an error, so we want to proceed anyway. See #5212 for
- discussion on this and the above buffer size issues */
- if(cnt < 0 && errno == EAGAIN && count == 0)
- return;
+ msn_soap_service_send_message_simple(sreq->soaps,
+ sreq->message, url, sreq->secure, sreq->cb,
+ sreq->cb_data);
- /* msn_soap_process could alter errno */
- msn_soap_process(conn);
+ /* Steal the message, passed to another call. */
+ sreq->message = NULL;
+ msn_soap_request_free(sreq);
- if ((cnt < 0 && perrno != EAGAIN) || cnt == 0) {
- /* It's possible msn_soap_process closed the ssl connection */
- if (conn->ssl) {
- purple_ssl_close(conn->ssl);
- conn->ssl = NULL;
- msn_soap_connection_handle_next(conn);
+ g_free(url);
+ g_free(faultdata);
+ return;
}
- }
-}
+ if (g_strcmp0(faultdata, "wsse:FailedAuthentication") == 0) {
+ xmlnode *xml_reason =
+ xmlnode_get_child(xml_fault, "faultstring");
+ gchar *reasondata = xmlnode_get_data(xml_reason);
-static gboolean
-msn_soap_write_cb_internal(gpointer data, gint fd, PurpleInputCondition cond,
- gboolean initial)
-{
- MsnSoapConnection *conn = data;
- int written;
-
- if (cond != PURPLE_INPUT_WRITE)
- return TRUE;
-
- written = purple_ssl_write(conn->ssl, conn->buf->str + conn->handled_len,
- conn->buf->len - conn->handled_len);
-
- if (written < 0 && errno == EAGAIN)
- return TRUE;
- else if (written <= 0) {
- purple_ssl_close(conn->ssl);
- conn->ssl = NULL;
- if (!initial)
- msn_soap_connection_handle_next(conn);
- return FALSE;
- }
+ msn_session_set_error(sreq->soaps->session, MSN_ERROR_AUTH,
+ reasondata);
- conn->handled_len += written;
+ g_free(reasondata);
+ g_free(faultdata);
+ msn_soap_request_free(sreq);
+ return;
+ }
+ g_free(faultdata);
+ }
- if (conn->handled_len < conn->buf->len)
- return TRUE;
+ if (xml_fault != NULL || xml_body != NULL) {
+ MsnSoapMessage *resp;
- /* we are done! */
- g_string_free(conn->buf, TRUE);
- conn->buf = NULL;
- conn->handled_len = 0;
- conn->body_len = 0;
- conn->response_code = 0;
- conn->headers_done = FALSE;
- conn->close_when_done = FALSE;
+ resp = msn_soap_message_new(NULL, xml_root);
+ sreq->cb(sreq->message, resp, sreq->cb_data);
+ msn_soap_message_free(resp);
+ }
- purple_input_remove(conn->event_handle);
- conn->event_handle = purple_input_add(conn->ssl->fd, PURPLE_INPUT_READ,
- msn_soap_read_cb, conn);
- return TRUE;
+ /* XXX: shouldn't msn_session_set_error here? */
+ msn_soap_request_free(sreq);
}
static void
-msn_soap_write_cb(gpointer data, gint fd, PurpleInputCondition cond)
-{
- msn_soap_write_cb_internal(data, fd, cond, FALSE);
-}
-
-static void
-msn_soap_error_cb(PurpleSslConnection *ssl, PurpleSslErrorType error,
- gpointer data)
+msn_soap_service_send_message_simple(MsnSoapService *soaps,
+ MsnSoapMessage *message, const gchar *url, gboolean secure,
+ MsnSoapCallback cb, gpointer cb_data)
{
- MsnSoapConnection *conn = data;
-
- /* sslconn already frees the connection in case of error */
- conn->ssl = NULL;
-
- g_hash_table_remove(conn->session->soap_table, conn->host);
+ PurpleHttpRequest *hreq;
+ MsnSoapRequest *sreq;
+ gchar *body;
+ int body_len;
+
+ sreq = g_new0(MsnSoapRequest, 1);
+ sreq->soaps = soaps;
+ sreq->cb = cb;
+ sreq->cb_data = cb_data;
+ sreq->secure = secure;
+ sreq->message = message;
+
+ hreq = purple_http_request_new(url);
+ purple_http_request_set_method(hreq, "POST");
+ purple_http_request_set_keepalive_pool(hreq, soaps->keepalive_pool);
+ purple_http_request_header_set(hreq, "SOAPAction",
+ message->action ? message->action : "");
+ purple_http_request_header_set(hreq, "Content-Type",
+ "text/xml; charset=utf-8");
+ purple_http_request_header_set(hreq, "User-Agent",
+ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
+ purple_http_request_header_set(hreq, "Cache-Control", "no-cache");
+
+ body = xmlnode_to_str(message->xml, &body_len);
+ purple_http_request_set_contents(hreq, body, body_len);
+ g_free(body);
+
+ purple_http_request(purple_account_get_connection(
+ soaps->session->account), hreq, msn_soap_service_recv, sreq);
+ purple_http_request_unref(hreq);
}
-static void
-msn_soap_connected_cb(gpointer data, PurpleSslConnection *ssl,
- PurpleInputCondition cond)
+void
+msn_soap_service_send_message(MsnSoapService *soaps, MsnSoapMessage *message,
+ const gchar *host, const gchar *path, gboolean secure,
+ MsnSoapCallback cb, gpointer cb_data)
{
- MsnSoapConnection *conn = data;
+ gchar *url;
- conn->connected = TRUE;
+ g_return_if_fail(host != NULL);
+ g_return_if_fail(path != NULL);
- if (conn->run_timer == 0)
- conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
-}
+ if (path[0] == '/')
+ path = &path[1];
-MsnSoapMessage *
-msn_soap_message_new(const char *action, xmlnode *xml)
-{
- MsnSoapMessage *message = g_new0(MsnSoapMessage, 1);
-
- message->action = g_strdup(action);
- message->xml = xml;
-
- return message;
-}
+ url = g_strdup_printf("https://%s/%s", host, path);
-static gboolean
-msn_soap_connection_run(gpointer data)
-{
- MsnSoapConnection *conn = data;
- MsnSoapRequest *req = g_queue_peek_head(conn->queue);
-
- conn->run_timer = 0;
-
- if (req) {
- if (conn->ssl == NULL) {
- conn->ssl = purple_ssl_connect(conn->session->account, conn->host,
- 443, msn_soap_connected_cb, msn_soap_error_cb, conn);
- } else if (conn->connected) {
- int len = -1;
- char *body = xmlnode_to_str(req->message->xml, &len);
- GSList *iter;
-
- g_queue_pop_head(conn->queue);
-
- conn->buf = g_string_new("");
-
- g_string_append_printf(conn->buf,
- "POST /%s HTTP/1.1\r\n"
- "SOAPAction: %s\r\n"
- "Content-Type:text/xml; charset=utf-8\r\n"
- "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"
- "Accept: */*\r\n"
- "Host: %s\r\n"
- "Content-Length: %d\r\n"
- "Connection: Keep-Alive\r\n"
- "Cache-Control: no-cache\r\n",
- req->path, req->message->action ? req->message->action : "",
- conn->host, len);
-
- for (iter = req->message->headers; iter; iter = iter->next) {
- g_string_append(conn->buf, (char *)iter->data);
- g_string_append(conn->buf, "\r\n");
- }
-
- g_string_append(conn->buf, "\r\n");
- g_string_append(conn->buf, body);
-
- if (req->secure && !purple_debug_is_unsafe())
- purple_debug_misc("soap", "Sending secure request.\n");
- else
- purple_debug_misc("soap", "%s\n", conn->buf->str);
-
- conn->handled_len = 0;
- conn->current_request = req;
-
- if (conn->event_handle)
- purple_input_remove(conn->event_handle);
- conn->event_handle = purple_input_add(conn->ssl->fd,
- PURPLE_INPUT_WRITE, msn_soap_write_cb, conn);
- if (!msn_soap_write_cb_internal(conn, conn->ssl->fd, PURPLE_INPUT_WRITE, TRUE)) {
- /* Not connected => reconnect and retry */
- purple_debug_info("soap", "not connected, reconnecting\n");
-
- conn->connected = FALSE;
- conn->current_request = NULL;
- msn_soap_connection_sanitize(conn, FALSE);
-
- g_queue_push_head(conn->queue, req);
- conn->run_timer = purple_timeout_add(0, msn_soap_connection_run, conn);
- }
-
- g_free(body);
- }
- }
+ msn_soap_service_send_message_simple(soaps, message, url, secure,
+ cb, cb_data);
- return FALSE;
+ g_free(url);
}
diff --git a/libpurple/protocols/msn/soap.h b/libpurple/protocols/msn/soap.h
index 7a66c0dd19..9222986b59 100644
--- a/libpurple/protocols/msn/soap.h
+++ b/libpurple/protocols/msn/soap.h
@@ -26,21 +26,29 @@
#include "xmlnode.h"
-#include "session.h"
-
typedef struct _MsnSoapMessage MsnSoapMessage;
+typedef struct _MsnSoapService MsnSoapService;
+
typedef void (*MsnSoapCallback)(MsnSoapMessage *request,
MsnSoapMessage *response, gpointer cb_data);
+#include "session.h"
+
MsnSoapMessage *
msn_soap_message_new(const gchar *action, xmlnode *xml);
xmlnode *
msn_soap_message_get_xml(MsnSoapMessage *message);
+MsnSoapService *
+msn_soap_service_new(MsnSession *session);
+
+void
+msn_soap_service_destroy(MsnSoapService *soaps);
+
void
-msn_soap_message_send(MsnSession *session, MsnSoapMessage *message,
+msn_soap_service_send_message(MsnSoapService *soaps, MsnSoapMessage *message,
const gchar *host, const gchar *path, gboolean secure,
MsnSoapCallback cb, gpointer cb_data);