From 963e2746db91848661fdfe9bfadec1165ecb7b07 Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Mon, 1 Apr 2013 22:29:06 +0300 Subject: [PATCH] http: implement 3xx response handling Redirection requires URL parsing. Make the URL parsing visible to the request layer. As the data structure is now visible we can simplify the new request API by passing the parsed URI data structure. With this change the new implementation should be on par with the old implementation in http-conn.c. --- src/core/sipe-http-request.c | 121 +++++++++++++++++++++++++++++++------------ src/core/sipe-http-request.h | 31 ++++++++--- src/core/sipe-http.c | 34 ++++-------- src/core/sipe-http.h | 1 + 4 files changed, 125 insertions(+), 62 deletions(-) diff --git a/src/core/sipe-http-request.c b/src/core/sipe-http-request.c index 6a6ec081..ed2bda0d 100644 --- a/src/core/sipe-http-request.c +++ b/src/core/sipe-http-request.c @@ -144,9 +144,62 @@ void sipe_http_request_next(struct sipe_http_connection_public *conn_public) sipe_http_request_send(conn_public); } -static void sipe_http_request_response_unauthorized(struct sipe_core_private *sipe_private, - struct sipe_http_request *req, - struct sipmsg *msg) +static void sipe_http_request_enqueue(struct sipe_core_private *sipe_private, + struct sipe_http_request *req, + const struct sipe_http_parsed_uri *parsed_uri) +{ + struct sipe_http_connection_public *conn_public; + + req->path = g_strdup(parsed_uri->path); + req->connection = conn_public = sipe_http_transport_new(sipe_private, + parsed_uri->host, + parsed_uri->port); + if (!sipe_http_request_pending(conn_public)) + req->flags |= SIPE_HTTP_REQUEST_FLAG_FIRST; + + conn_public->pending_requests = g_slist_append(conn_public->pending_requests, + req); +} + +/* TRUE indicates failure */ +static gboolean sipe_http_request_response_redirection(struct sipe_core_private *sipe_private, + struct sipe_http_request *req, + struct sipmsg *msg) +{ + const gchar *location = sipmsg_find_header(msg, "Location"); + gboolean failed = TRUE; + + if (location) { + struct sipe_http_parsed_uri *parsed_uri = sipe_http_parse_uri(location); + + if (parsed_uri) { + /* remove request from old connection */ + struct sipe_http_connection_public *conn_public = req->connection; + conn_public->pending_requests = g_slist_remove(conn_public->pending_requests, + req); + + /* free old request data */ + g_free(req->path); + req->flags &= ~SIPE_HTTP_REQUEST_FLAG_FIRST; + + /* resubmit request on other connection */ + sipe_http_request_enqueue(sipe_private, req, parsed_uri); + failed = FALSE; + + sipe_http_parsed_uri_free(parsed_uri); + } else + SIPE_DEBUG_INFO("sipe_http_request_response_redirection: invalid redirection to '%s'", + location); + } else + SIPE_DEBUG_INFO_NOFORMAT("sipe_http_request_response_redirection: no URL found?!?"); + + return(failed); +} + +/* TRUE indicates failure */ +static gboolean sipe_http_request_response_unauthorized(struct sipe_core_private *sipe_private, + struct sipe_http_request *req, + struct sipmsg *msg) { const gchar *header = NULL; const gchar *name; @@ -222,13 +275,7 @@ static void sipe_http_request_response_unauthorized(struct sipe_core_private *si } else SIPE_DEBUG_INFO_NOFORMAT("sipe_http_request_response_unauthorized: only " DEBUG_STRING " supported"); - if (failed) { - /* Callback: authentication failed */ - (*req->cb)(sipe_private, 0, NULL, NULL, req->cb_data); - - /* remove failed request */ - sipe_http_request_cancel(req); - } + return(failed); } static void sipe_http_request_response_callback(struct sipe_core_private *sipe_private, @@ -285,14 +332,34 @@ void sipe_http_request_response(struct sipe_http_connection_public *conn_public, { struct sipe_core_private *sipe_private = conn_public->sipe_private; struct sipe_http_request *req = conn_public->pending_requests->data; + gboolean failed; + + if ((req->flags & SIPE_HTTP_REQUEST_FLAG_REDIRECT) && + (msg->response >= SIPE_HTTP_STATUS_REDIRECTION) && + (msg->response < SIPE_HTTP_STATUS_CLIENT_ERROR)) { + failed = sipe_http_request_response_redirection(sipe_private, + req, + msg); + + } else if (msg->response == SIPE_HTTP_STATUS_CLIENT_UNAUTHORIZED) { + failed = sipe_http_request_response_unauthorized(sipe_private, + req, + msg); - if (msg->response == SIPE_HTTP_STATUS_CLIENT_UNAUTHORIZED) { - sipe_http_request_response_unauthorized(sipe_private, req, msg); - /* req may no longer be valid */ } else { /* All other cases are passed on to the user */ sipe_http_request_response_callback(sipe_private, req, msg); + /* req is no longer valid */ + failed = FALSE; + } + + if (failed) { + /* Callback: request failed */ + (*req->cb)(sipe_private, 0, NULL, NULL, req->cb_data); + + /* remove failed request */ + sipe_http_request_cancel(req); } } @@ -316,19 +383,21 @@ void sipe_http_request_shutdown(struct sipe_http_connection_public *conn_public) } struct sipe_http_request *sipe_http_request_new(struct sipe_core_private *sipe_private, - const gchar *host, - guint32 port, - const gchar *path, + const struct sipe_http_parsed_uri *parsed_uri, const gchar *headers, const gchar *body, const gchar *content_type, sipe_http_response_callback *callback, gpointer callback_data) { - struct sipe_http_request *req = g_new0(struct sipe_http_request, 1); - struct sipe_http_connection_public *conn_public; + struct sipe_http_request *req; + if (!parsed_uri) + return(NULL); - req->path = g_strdup(path); + req = g_new0(struct sipe_http_request, 1); + req->flags = 0; + req->cb = callback; + req->cb_data = callback_data; if (headers) req->headers = g_strdup(headers); if (body) { @@ -336,8 +405,6 @@ struct sipe_http_request *sipe_http_request_new(struct sipe_core_private *sipe_p req->content_type = g_strdup(content_type); } - req->flags = 0; - /* default authentication */ if (!SIPE_CORE_PRIVATE_FLAG_IS(SSO)) sipe_http_request_authentication(req, @@ -345,17 +412,7 @@ struct sipe_http_request *sipe_http_request_new(struct sipe_core_private *sipe_p sipe_private->authuser, sipe_private->password); - req->cb = callback; - req->cb_data = callback_data; - - req->connection = conn_public = sipe_http_transport_new(sipe_private, - host, - port); - if (!sipe_http_request_pending(conn_public)) - req->flags |= SIPE_HTTP_REQUEST_FLAG_FIRST; - - conn_public->pending_requests = g_slist_append(conn_public->pending_requests, - req); + sipe_http_request_enqueue(sipe_private, req, parsed_uri); return(req); } diff --git a/src/core/sipe-http-request.h b/src/core/sipe-http-request.h index afc908d1..493c078d 100644 --- a/src/core/sipe-http-request.h +++ b/src/core/sipe-http-request.h @@ -38,6 +38,29 @@ struct sipe_core_private; struct sipe_http_connection_public; struct sipe_http_request; +struct sipe_http_parsed_uri { + gchar *host; + gchar *path; + guint port; +}; + +/** + * Parse URI + * + * @param uri text to parse + * + * @return pointer to parsed URI. Must be freed with @c sipe_http_parsed_uri_free() + */ +struct sipe_http_parsed_uri *sipe_http_parse_uri(const gchar *uri); + +/** + * Free parsed URI data structure + * + * @param pointer to parsed URI. + */ +void sipe_http_parsed_uri_free(struct sipe_http_parsed_uri *parsed_uri); + + /** * Is there pending request for HTTP connection? * @@ -72,9 +95,7 @@ void sipe_http_request_shutdown(struct sipe_http_connection_public *conn_public) * Create new HTTP request (internal raw version) * * @param sipe_private SIPE core private data - * @param host name of the host to connect to - * @param port port number to connect to - * @param path relative path + * @param parsed_uri pointer to parsed URI * @param headers additional headers to add (may be @c NULL) * @param body body (may be @c NULL) * @param content_type MIME type for body (may be @c NULL if body is @c NULL) @@ -84,9 +105,7 @@ void sipe_http_request_shutdown(struct sipe_http_connection_public *conn_public) * @return pointer to opaque HTTP request data structure */ struct sipe_http_request *sipe_http_request_new(struct sipe_core_private *sipe_private, - const gchar *host, - guint32 port, - const gchar *path, + const struct sipe_http_parsed_uri *parsed_uri, const gchar *headers, const gchar *body, const gchar *content_type, diff --git a/src/core/sipe-http.c b/src/core/sipe-http.c index b01fb3c1..0482095f 100644 --- a/src/core/sipe-http.c +++ b/src/core/sipe-http.c @@ -36,22 +36,16 @@ #define _SIPE_HTTP_PRIVATE_IF_REQUEST #include "sipe-http-request.h" -struct parsed_uri { - gchar *host; - gchar *path; - guint port; -}; - -static void parsed_uri_free(struct parsed_uri *parsed_uri) +void sipe_http_parsed_uri_free(struct sipe_http_parsed_uri *parsed_uri) { g_free(parsed_uri->host); g_free(parsed_uri->path); g_free(parsed_uri); } -static struct parsed_uri *sipe_http_parse_uri(const gchar *uri) +struct sipe_http_parsed_uri *sipe_http_parse_uri(const gchar *uri) { - struct parsed_uri *parsed_uri = NULL; + struct sipe_http_parsed_uri *parsed_uri = NULL; // SIPE_DEBUG_INFO("sipe_http_parse_uri: '%s'", uri); @@ -67,7 +61,7 @@ static struct parsed_uri *sipe_http_parse_uri(const gchar *uri) /* ":port" is optional */ if (host_port && host_port[0]) { - parsed_uri = g_new0(struct parsed_uri, 1); + parsed_uri = g_new0(struct sipe_http_parsed_uri, 1); parsed_uri->host = g_strdup(host_port[0]); parsed_uri->path = g_strdup(hostport_path[1]); @@ -101,20 +95,16 @@ struct sipe_http_request *sipe_http_request_get(struct sipe_core_private *sipe_p gpointer callback_data) { struct sipe_http_request *req; - struct parsed_uri *parsed_uri = sipe_http_parse_uri(uri); - if (!parsed_uri) - return(NULL); + struct sipe_http_parsed_uri *parsed_uri = sipe_http_parse_uri(uri); req = sipe_http_request_new(sipe_private, - parsed_uri->host, - parsed_uri->port, - parsed_uri->path, + parsed_uri, headers, NULL, NULL, callback, callback_data); - parsed_uri_free(parsed_uri); + sipe_http_parsed_uri_free(parsed_uri); return(req); } @@ -128,20 +118,16 @@ struct sipe_http_request *sipe_http_request_post(struct sipe_core_private *sipe_ gpointer callback_data) { struct sipe_http_request *req; - struct parsed_uri *parsed_uri = sipe_http_parse_uri(uri); - if (!parsed_uri) - return(NULL); + struct sipe_http_parsed_uri *parsed_uri = sipe_http_parse_uri(uri); req = sipe_http_request_new(sipe_private, - parsed_uri->host, - parsed_uri->port, - parsed_uri->path, + parsed_uri, headers, body, content_type, callback, callback_data); - parsed_uri_free(parsed_uri); + sipe_http_parsed_uri_free(parsed_uri); return(req); } diff --git a/src/core/sipe-http.h b/src/core/sipe-http.h index 055474aa..16d1b791 100644 --- a/src/core/sipe-http.h +++ b/src/core/sipe-http.h @@ -52,6 +52,7 @@ typedef void (sipe_http_response_callback)(struct sipe_core_private *sipe_privat /* HTTP response status codes */ #define SIPE_HTTP_STATUS_OK 200 +#define SIPE_HTTP_STATUS_REDIRECTION 300 /* - 399 */ #define SIPE_HTTP_STATUS_CLIENT_ERROR 400 /* - 499 */ #define SIPE_HTTP_STATUS_CLIENT_UNAUTHORIZED 401 -- 2.11.4.GIT