# HG changeset patch # User Paul Aurich # Date 1232239872 0 # Node ID 592c2cf00fea886b252adab12c80b67d0b08c845 # Parent 5ad14a53e266a9602837e43fa5d8b61e9a15f768 Jabber BOSH: Store less for each Request/Response * BOSH doesn't care about the HTTP headers, so we don't care about them much. * The request callback doesn't need the request for state. diff -r 5ad14a53e266 -r 592c2cf00fea libpurple/protocols/jabber/bosh.c --- a/libpurple/protocols/jabber/bosh.c Fri Dec 19 04:28:38 2008 +0000 +++ b/libpurple/protocols/jabber/bosh.c Sun Jan 18 00:51:12 2009 +0000 @@ -34,7 +34,7 @@ typedef void (*PurpleHTTPConnectionConnectFunction)(PurpleHTTPConnection *conn); typedef void (*PurpleHTTPConnectionDisconnectFunction)(PurpleHTTPConnection *conn); -typedef void (*PurpleHTTPRequestCallback)(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata); +typedef void (*PurpleHTTPRequestCallback)(PurpleHTTPResponse *res, void *userdata); typedef void (*PurpleBOSHConnectionConnectFunction)(PurpleBOSHConnection *conn); typedef void (*PurpleBOSHConnectionReceiveFunction)(PurpleBOSHConnection *conn, xmlnode *node); @@ -66,7 +66,7 @@ char *host; int port; int ie_handle; - GQueue *requests; + GQueue *requests; /* Queue of PurpleHTTPRequestCallbacks */ PurpleHTTPResponse *current_response; char *current_data; @@ -80,9 +80,7 @@ struct _PurpleHTTPRequest { PurpleHTTPRequestCallback cb; - char *method; - char *path; - GHashTable *header; + const char *path; char *data; int data_len; void *userdata; @@ -98,14 +96,12 @@ static void jabber_bosh_connection_stream_restart(PurpleBOSHConnection *conn); static gboolean jabber_bosh_connection_error_check(PurpleBOSHConnection *conn, xmlnode *node); static void jabber_bosh_connection_received(PurpleBOSHConnection *conn, xmlnode *node); -static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata); +static void jabber_bosh_connection_http_received_cb(PurpleHTTPResponse *res, void *userdata); static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node); static void jabber_bosh_http_connection_connect(PurpleHTTPConnection *conn); static void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req); -static void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value); - void jabber_bosh_init(void) { GHashTable *ui_info = purple_core_get_ui_info(); @@ -126,25 +122,9 @@ bosh_useragent = NULL; } -static PurpleHTTPRequest* -jabber_bosh_http_request_init(const char *method, const char *path, - PurpleHTTPRequestCallback cb, void *userdata) -{ - PurpleHTTPRequest *req = g_new(PurpleHTTPRequest, 1); - req->method = g_strdup(method); - req->path = g_strdup(path); - req->cb = cb; - req->userdata = userdata; - req->header = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - return req; -} - static void jabber_bosh_http_request_destroy(PurpleHTTPRequest *req) { - g_hash_table_destroy(req->header); - g_free(req->method); - g_free(req->path); g_free(req->data); g_free(req); } @@ -183,10 +163,8 @@ g_free(conn->current_data); g_free(conn->host); - if (conn->requests) { - g_queue_foreach(conn->requests, (GFunc)jabber_bosh_http_request_destroy, NULL); + if (conn->requests) g_queue_free(conn->requests); - } if (conn->current_response) jabber_bosh_http_response_destroy(conn->current_response); @@ -214,7 +192,8 @@ conn = g_new0(PurpleBOSHConnection, 1); conn->host = host; conn->port = port; - conn->path = path; + conn->path = g_strdup_printf("/%s", path); + g_free(path); conn->pipelining = TRUE; if ((user && user[0] != '\0') || (passwd && passwd[0] != '\0')) { @@ -414,7 +393,7 @@ xmlnode_free(init); } -static void jabber_bosh_connection_http_received_cb(PurpleHTTPRequest *req, PurpleHTTPResponse *res, void *userdata) { +static void jabber_bosh_connection_http_received_cb(PurpleHTTPResponse *res, void *userdata) { PurpleBOSHConnection *conn = userdata; if (conn->receive_cb) { xmlnode *node = xmlnode_from_str(res->data, res->data_len); @@ -468,14 +447,13 @@ static void jabber_bosh_connection_send_native(PurpleBOSHConnection *conn, xmlnode *node) { PurpleHTTPRequest *request; - char *txt = xmlnode_to_formatted_str(node, NULL); - printf("\njabber_bosh_connection_send\n%s\n", txt); - g_free(txt); - - request = jabber_bosh_http_request_init("POST", g_strdup_printf("/%s", conn->path), jabber_bosh_connection_http_received_cb, conn); - jabber_bosh_http_request_add_to_header(request, "Content-Encoding", "text/xml; charset=utf-8"); + request = g_new0(PurpleHTTPRequest, 1); + request->path = conn->path; + request->cb = jabber_bosh_connection_http_received_cb; + request->userdata = conn; + request->data = xmlnode_to_str(node, &(request->data_len)); - jabber_bosh_http_request_add_to_header(request, "Content-Length", g_strdup_printf("%d", (int)strlen(request->data))); + jabber_bosh_http_connection_send_request(conn->conn_a, request); } @@ -578,7 +556,7 @@ if (response) { if (conn->current_len >= response->data_len) { - PurpleHTTPRequest *request = g_queue_pop_head(conn->requests); + PurpleHTTPRequestCallback cb = g_queue_pop_head(conn->requests); #warning For a pure HTTP 1.1 stack, this would need to be handled elsewhere. if (bosh_conn->ready == TRUE && g_queue_is_empty(conn->requests) == TRUE) { @@ -586,17 +564,14 @@ printf("\n SEND AN EMPTY REQUEST \n"); } - if (request) { + if (cb) { char *old_data = conn->current_data; response->data = g_memdup(conn->current_data, response->data_len); conn->current_data = g_strdup(&conn->current_data[response->data_len]); conn->current_len -= response->data_len; g_free(old_data); - if (request->cb) request->cb(request, response, conn->userdata); - else purple_debug_info("jabber", "missing request callback!\n"); - - jabber_bosh_http_request_destroy(request); + cb(response, conn->userdata); jabber_bosh_http_response_destroy(response); conn->current_response = NULL; } else { @@ -653,34 +628,39 @@ } } -static void jabber_bosh_http_connection_send_request_add_field_to_string(gpointer key, gpointer value, gpointer user_data) +static void +jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, + PurpleHTTPRequest *req) { - char **ppacket = user_data; - char *tmp = *ppacket; - char *field = key; - char *val = value; - *ppacket = g_strdup_printf("%s%s: %s\r\n", tmp, field, val); - g_free(tmp); + PurpleBOSHConnection *bosh_conn = conn->userdata; + GString *packet = g_string_new(""); + int ret; + + /* TODO: Should we lie about this HTTP/1.1 support? */ + g_string_append_printf(packet, "POST %s HTTP/1.1\r\n" + "Host: %s\r\n" + "User-Agent: %s\r\n" + "Content-Encoding: text/xml; charset=utf-8\r\n" + "Content-Length: %d\r\n", + req->path, conn->host, bosh_useragent, req->data_len); + + printf("Sending %s\n", packet->str); + /* TODO: Better error handling, circbuffer or possible integration with + * low-level code in jabber.c */ + ret = write(conn->fd, packet->str, packet->len); + + g_string_free(packet, TRUE); + g_queue_push_tail(conn->requests, req->cb); + jabber_bosh_http_request_destroy(req); + + if (ret < 0 && errno == EAGAIN) + purple_debug_warning("jabber", "BOSH write would have blocked\n"); + + if (ret <= 0) { + purple_connection_error_reason(bosh_conn->js->gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Write error")); + return; + } } -void jabber_bosh_http_connection_send_request(PurpleHTTPConnection *conn, PurpleHTTPRequest *req) { - char *packet; - char *tmp; - jabber_bosh_http_request_add_to_header(req, "Host", conn->host); - jabber_bosh_http_request_add_to_header(req, "User-Agent", bosh_useragent); - - packet = tmp = g_strdup_printf("%s %s HTTP/1.1\r\n", req->method, req->path); - g_hash_table_foreach(req->header, jabber_bosh_http_connection_send_request_add_field_to_string, &packet); - tmp = packet; - packet = g_strdup_printf("%s\r\n%s", tmp, req->data); - g_free(tmp); - if (write(conn->fd, packet, strlen(packet)) == -1) purple_debug_info("jabber", "send error\n"); - g_queue_push_tail(conn->requests, req); -} - -static void jabber_bosh_http_request_add_to_header(PurpleHTTPRequest *req, const char *field, const char *value) { - char *f = g_strdup(field); - char *v = g_strdup(value); - g_hash_table_replace(req->header, f, v); -} -