From d4629510fb547f3ed2cce829ea1ec0c73bc5647c Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 5 Nov 2002 19:45:46 +0000 Subject: Split libsoup out of soup. ChangeLog.old contains the original soup * Split libsoup out of soup. ChangeLog.old contains the original soup ChangeLog. * Makefile.am, etc: Fix things up to work with the new directory layout. Disable docs until we fix them. * autogen.sh: Use gnome-autogen.sh * configure.in: Require autoconf 2.53. Remove stuff that was only needed for httpd or wsdl code. Remove glib1 support. Bump version to 2.0. * libsoup/Makefile.am: Rename library to libsoup-2.0, put includes in ${includedir}/soup-2.0 * libsoup/*: Merge soup-0-7 back onto the trunk. Remove SOAP-specific stuff, Windows support, and other things that weren't being maintained. * soup-config.in, soupConf.sh: Kill these. We only support pkg-config now. --- libsoup/.cvsignore | 1 + libsoup/Makefile.am | 50 ++-- libsoup/soup-auth.c | 155 +++++----- libsoup/soup-auth.h | 24 +- libsoup/soup-context.c | 72 ++--- libsoup/soup-context.h | 2 +- libsoup/soup-headers.c | 4 +- libsoup/soup-headers.h | 2 +- libsoup/soup-message.c | 727 ++++++++++++++++++++++++--------------------- libsoup/soup-message.h | 134 +++------ libsoup/soup-misc.c | 70 ++++- libsoup/soup-misc.h | 13 +- libsoup/soup-nss.c | 9 +- libsoup/soup-nss.h | 5 +- libsoup/soup-ntlm.c | 394 ++++++++++++------------ libsoup/soup-ntlm.h | 25 +- libsoup/soup-openssl.c | 329 +++++++++++++------- libsoup/soup-openssl.h | 2 +- libsoup/soup-private.h | 40 +-- libsoup/soup-queue.c | 29 +- libsoup/soup-queue.h | 2 +- libsoup/soup-server.c | 259 ++++++++++------ libsoup/soup-server.h | 9 +- libsoup/soup-socket-unix.c | 10 +- libsoup/soup-socket.c | 140 ++++----- libsoup/soup-socket.h | 2 +- libsoup/soup-socks.c | 2 +- libsoup/soup-socks.h | 2 +- libsoup/soup-ssl-proxy.c | 32 +- libsoup/soup-ssl.c | 73 +++-- libsoup/soup-ssl.h | 8 +- libsoup/soup-transfer.c | 132 ++++---- libsoup/soup-transfer.h | 2 +- libsoup/soup-uri.c | 6 +- libsoup/soup-uri.h | 3 +- libsoup/soup.h | 8 +- 36 files changed, 1497 insertions(+), 1280 deletions(-) (limited to 'libsoup') diff --git a/libsoup/.cvsignore b/libsoup/.cvsignore index 69fb0bd8..0be24a01 100644 --- a/libsoup/.cvsignore +++ b/libsoup/.cvsignore @@ -4,3 +4,4 @@ .libs Makefile Makefile.in +libsoup-ssl-proxy diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index e47c5752..8e6f1697 100644 --- a/libsoup/Makefile.am +++ b/libsoup/Makefile.am @@ -1,71 +1,57 @@ ## Process this file with automake to produce Makefile.in -@SET_MAKE@ - INCLUDES = \ -DG_LOG_DOMAIN=\"SOUP\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DBINDIR=\"$(bindir)\" \ - -I$(top_srcdir)/src \ + -I$(top_srcdir) \ $(SOUP_DEBUG_FLAGS) \ $(GLIB_CFLAGS) \ - $(XML_CFLAGS) \ - $(NSS_CFLAGS) + $(NSS_CFLAGS) \ + $(OPENSSL_CFLAGS) -libsoupincludedir = $(includedir)/soup/libsoup +libsoupincludedir = $(includedir)/soup-2.0/libsoup libsoupinclude_HEADERS = \ soup.h \ soup-context.h \ - soup-dav.h \ - soup-dav-server.h \ - soup-env.h \ soup-error.h \ - soup-fault.h \ soup-headers.h \ soup-message.h \ soup-method.h \ soup-misc.h \ - soup-parser.h \ - soup-serializer.h \ + soup-ntlm.h \ soup-server-auth.h \ soup-server.h \ soup-socket.h \ soup-uri.h -lib_LTLIBRARIES = libsoup.la +lib_LTLIBRARIES = libsoup-2.0.la -libsoup_la_LDFLAGS = -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE) +libsoup_2_0_la_LDFLAGS = \ + -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE) -libsoup_la_LIBADD = \ +libsoup_2_0_la_LIBADD = \ $(GLIB_LIBS) \ - $(XML_LIBS) \ $(NSS_LIBS) -libsoup_la_SOURCES = \ +libsoup_2_0_la_SOURCES = \ md5-utils.h \ md5-utils.c \ soup-auth.h \ soup-auth.c \ soup-context.c \ - soup-dav.c \ - soup-dav-server.c \ - soup-env.c \ soup-error.c \ - soup-fault.c \ soup-headers.c \ soup-message.c \ soup-method.c \ soup-misc.c \ soup-nss.h \ soup-nss.c \ - soup-ntlm.h \ soup-ntlm.c \ - soup-parser.c \ soup-private.h \ soup-queue.h \ soup-queue.c \ - soup-serializer.c \ soup-server.c \ soup-server-auth.c \ soup-socket.c \ @@ -78,5 +64,19 @@ libsoup_la_SOURCES = \ soup-transfer.c \ soup-uri.c -EXTRA_DIST = +noinst_PROGRAMS = libsoup-ssl-proxy + +libsoup_ssl_proxy_LDADD = \ + $(LINK_STATIC) \ + $(OPENSSL_LIBS) \ + $(GLIB_LIBS) \ + $(LINK_DYNAMIC) + +libsoup_ssl_proxy_SOURCES = \ + soup-openssl.h \ + soup-openssl.c \ + soup-ssl-proxy.c +install-exec-hook: + $(mkinstalldirs) $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) libsoup-ssl-proxy $(DESTDIR)$(bindir)/$(SSL_PROXY_NAME) diff --git a/libsoup/soup-auth.c b/libsoup/soup-auth.c index dd282925..2b3b22d4 100644 --- a/libsoup/soup-auth.c +++ b/libsoup/soup-auth.c @@ -14,14 +14,7 @@ #include #endif -#ifdef HAVE_UNISTD_H #include -#endif - -#ifdef SOUP_WIN32 -#include -#endif - #include #include #include @@ -46,12 +39,6 @@ typedef struct { gchar *token; } SoupAuthBasic; -static gboolean -basic_compare_func (SoupAuth *a, SoupAuth *b) -{ - return FALSE; -} - static char * basic_auth_func (SoupAuth *auth, SoupMessage *message) { @@ -105,7 +92,6 @@ soup_auth_new_basic (void) auth = (SoupAuth *) basic; auth->type = SOUP_AUTH_TYPE_BASIC; - auth->compare_func = basic_compare_func; auth->parse_func = basic_parse_func; auth->init_func = basic_init_func; auth->auth_func = basic_auth_func; @@ -140,7 +126,6 @@ typedef struct { char *nonce; QOPType qop_options; AlgorithmType algorithm; - gboolean stale; /* These are generated by the client */ char *cnonce; @@ -148,12 +133,6 @@ typedef struct { QOPType qop; } SoupAuthDigest; -static gboolean -digest_compare_func (SoupAuth *a, SoupAuth *b) -{ - return ((SoupAuthDigest *) a)->stale; -} - static void digest_hex (guchar *digest, guchar hex[33]) { @@ -285,6 +264,7 @@ digest_auth_func (SoupAuth *auth, SoupMessage *message) url, response); + g_free (response); g_free (url); g_free (nc); @@ -369,15 +349,6 @@ digest_parse_func (SoupAuth *auth, const char *header) g_free (tmp); - tmp = soup_header_param_copy_token (tokens, "stale"); - - if (tmp && g_strcasecmp (tmp, "true") == 0) - digest->stale = TRUE; - else - digest->stale = FALSE; - - g_free (tmp); - tmp = soup_header_param_copy_token (tokens, "algorithm"); digest->algorithm = decode_algorithm (tmp); g_free (tmp); @@ -447,7 +418,6 @@ soup_auth_new_digest (void) auth = (SoupAuth *) digest; auth->type = SOUP_AUTH_TYPE_DIGEST; - auth->compare_func = digest_compare_func; auth->parse_func = digest_parse_func; auth->init_func = digest_init_func; auth->auth_func = digest_auth_func; @@ -462,6 +432,8 @@ soup_auth_new_digest (void) /* We're just going to do qop=auth for now */ digest->qop = QOP_AUTH; + g_free (bgen); + return auth; } @@ -474,15 +446,8 @@ typedef struct { SoupAuth auth; gchar *response; gchar *header; - gboolean completed; } SoupAuthNTLM; -static gboolean -ntlm_compare_func (SoupAuth *a, SoupAuth *b) -{ - return !((SoupAuthNTLM *)b)->completed; -} - /* * SoupAuthNTLMs are one time use. Just return the response, and set our * reference to NULL so future requests do not include this header. @@ -530,41 +495,42 @@ ntlm_parse (SoupAuth *sa, const char *header) g_strstrip (auth->header); } -/* - * FIXME: Because NTLM is a two step process, we parse the host and domain out - * of the context's uri twice. This is because there is no way to reparse - * a new header with an existing SoupAuth, so a new one is created for - * each negotiation step. - */ static void ntlm_init (SoupAuth *sa, const SoupUri *uri) { SoupAuthNTLM *auth = (SoupAuthNTLM *) sa; - gchar *host, *domain; - - host = ntlm_get_authmech_token (uri, "host="); - domain = ntlm_get_authmech_token (uri, "domain="); if (strlen (auth->header) < sizeof ("NTLM")) auth->response = soup_ntlm_request (); else { - gchar lm_hash [21], nt_hash [21]; - - soup_ntlm_lanmanager_hash (uri->passwd, lm_hash); - soup_ntlm_nt_hash (uri->passwd, nt_hash); - - auth->response = - soup_ntlm_response (auth->header, - uri->user, - (gchar *) &lm_hash, - (gchar *) &nt_hash, - host, - domain); - auth->completed = TRUE; - } + gchar *host, *domain, *nonce; + + host = ntlm_get_authmech_token (uri, "host="); + domain = ntlm_get_authmech_token (uri, "domain="); + + if (!soup_ntlm_parse_challenge (auth->header, + &nonce, + domain ? NULL : &domain)) + auth->response = NULL; + else { + auth->response = + soup_ntlm_response (nonce, + uri->user, + uri->passwd, + host, + domain); + g_free (nonce); + } - g_free (host); - g_free (domain); + g_free (host); + g_free (domain); + + /* Set this now so that if the server returns 401, + * soup will fail instead of looping (since that + * probably means the password was incorrect). + */ + sa->status = SOUP_AUTH_STATUS_SUCCESSFUL; + } g_free (auth->header); auth->header = NULL; @@ -587,7 +553,6 @@ ntlm_new (void) auth = g_new0 (SoupAuthNTLM, 1); auth->auth.type = SOUP_AUTH_TYPE_NTLM; - auth->auth.compare_func = ntlm_compare_func; auth->auth.parse_func = ntlm_parse; auth->auth.init_func = ntlm_init; auth->auth.auth_func = ntlm_auth; @@ -625,6 +590,33 @@ soup_auth_lookup (SoupContext *ctx) return ret; } +void +soup_auth_invalidate (SoupAuth *auth, SoupContext *ctx) +{ + SoupHost *server; + const SoupUri *uri; + SoupAuth *old_auth; + char *old_path; + + g_return_if_fail (ctx != NULL); + g_return_if_fail (auth != NULL); + + server = ctx->server; + + if (!server->valid_auths) + return; + + uri = soup_context_get_uri (ctx); + if (g_hash_table_lookup_extended (server->valid_auths, + uri->path, + (gpointer *) &old_path, + (gpointer *) &old_auth)) { + g_hash_table_remove (server->valid_auths, old_path); + g_free (old_path); + soup_auth_free (old_auth); + } +} + void soup_auth_set_context (SoupAuth *auth, SoupContext *ctx) { @@ -647,6 +639,9 @@ soup_auth_set_context (SoupAuth *auth, SoupContext *ctx) uri->path, (gpointer *) &old_path, (gpointer *) &old_auth)) { + if (auth == old_auth) + return; + g_hash_table_remove (server->valid_auths, old_path); g_free (old_path); soup_auth_free (old_auth); @@ -673,7 +668,8 @@ static AuthScheme known_auth_schemes [] = { }; SoupAuth * -soup_auth_new_from_header_list (const GSList *vals) +soup_auth_new_from_header_list (const SoupUri *uri, + const GSList *vals) { gchar *header = NULL; AuthScheme *scheme = NULL, *iter; @@ -682,9 +678,14 @@ soup_auth_new_from_header_list (const GSList *vals) g_return_val_if_fail (vals != NULL, NULL); while (vals) { - for (iter = known_auth_schemes; iter->scheme; iter++) { - gchar *tryheader = vals->data; + gchar *tryheader = vals->data; + for (iter = known_auth_schemes; iter->scheme; iter++) { + if (uri->authmech && + g_strncasecmp (uri->authmech, + iter->scheme, + strlen (iter->scheme)) != 0) + continue; if (!g_strncasecmp (tryheader, iter->scheme, strlen (iter->scheme))) { @@ -706,8 +707,7 @@ soup_auth_new_from_header_list (const GSList *vals) auth = scheme->ctor (); if (!auth) return NULL; - if (!auth->compare_func || - !auth->parse_func || + if (!auth->parse_func || !auth->init_func || !auth->auth_func || !auth->free_func) @@ -744,18 +744,3 @@ soup_auth_free (SoupAuth *auth) g_free (auth->realm); auth->free_func (auth); } - -gboolean -soup_auth_invalidates_prior (SoupAuth *new_auth, SoupAuth *old_auth) -{ - g_return_val_if_fail (new_auth != NULL, FALSE); - g_return_val_if_fail (old_auth != NULL, TRUE); - - if (new_auth == old_auth) - return FALSE; - - if (new_auth->type != old_auth->type) - return TRUE; - - return new_auth->compare_func (new_auth, old_auth); -} diff --git a/libsoup/soup-auth.h b/libsoup/soup-auth.h index 75a49459..f1634539 100644 --- a/libsoup/soup-auth.h +++ b/libsoup/soup-auth.h @@ -15,13 +15,22 @@ #include #include -typedef struct _SoupAuth SoupAuth; +typedef enum _SoupAuthStatus SoupAuthStatus; +typedef struct _SoupAuth SoupAuth; + +enum _SoupAuthStatus { + SOUP_AUTH_STATUS_INVALID = 0, + SOUP_AUTH_STATUS_PENDING, + SOUP_AUTH_STATUS_FAILED, + SOUP_AUTH_STATUS_SUCCESSFUL +}; + struct _SoupAuth { SoupAuthType type; gchar *realm; - gboolean (*compare_func) (SoupAuth *a, - SoupAuth *b); + SoupAuthStatus status; + SoupMessage *controlling_msg; void (*parse_func) (SoupAuth *auth, const gchar *header); @@ -40,7 +49,11 @@ SoupAuth *soup_auth_lookup (SoupContext *ctx); void soup_auth_set_context (SoupAuth *auth, SoupContext *ctx); -SoupAuth *soup_auth_new_from_header_list (const GSList *header); +void soup_auth_invalidate (SoupAuth *auth, + SoupContext *ctx); + +SoupAuth *soup_auth_new_from_header_list (const SoupUri *uri, + const GSList *header); void soup_auth_initialize (SoupAuth *auth, const SoupUri *uri); @@ -50,7 +63,4 @@ void soup_auth_free (SoupAuth *auth); gchar *soup_auth_authorize (SoupAuth *auth, SoupMessage *msg); -gboolean soup_auth_invalidates_prior (SoupAuth *new_auth, - SoupAuth *old_auth); - #endif /* SOUP_AUTH_H */ diff --git a/libsoup/soup-context.c b/libsoup/soup-context.c index 28d2c5f3..bd21d69d 100644 --- a/libsoup/soup-context.c +++ b/libsoup/soup-context.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-context.c: Asyncronous Callback-based SOAP Request Queue. + * soup-context.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -12,10 +12,7 @@ #include #endif -#ifdef HAVE_UNISTD_H #include -#endif - #include #include #include @@ -23,16 +20,9 @@ #include #include -#ifdef HAVE_SYS_SOCKET_H #include -#endif - -#ifdef HAVE_NETINET_TCP_H #include -#endif -#ifdef HAVE_NETINET_IN_H #include -#endif #include "soup-auth.h" #include "soup-context.h" @@ -85,17 +75,31 @@ static guint soup_context_uri_hash (gconstpointer key) { const SoupUri *uri = key; - guint ret = 0; - - ret += uri->protocol; - ret += g_str_hash (uri->path ? uri->path : ""); - ret += g_str_hash (uri->querystring ? uri->querystring : ""); - ret += g_str_hash (uri->user ? uri->user : ""); - ret += g_str_hash (uri->passwd ? uri->passwd : ""); + guint ret; + + ret = uri->protocol; + if (uri->path) + ret += g_str_hash (uri->path); + if (uri->querystring) + ret += g_str_hash (uri->querystring); + if (uri->user) + ret += g_str_hash (uri->user); + if (uri->passwd) + ret += g_str_hash (uri->passwd); return ret; } +static inline gboolean +parts_equal (const char *one, const char *two) +{ + if (!one && !two) + return TRUE; + if (!one || !two) + return FALSE; + return !strcmp (one, two); +} + /** * soup_context_uri_equal: * @v1: a %SoupUri @@ -110,18 +114,18 @@ soup_context_uri_equal (gconstpointer v1, gconstpointer v2) const SoupUri *one = v1; const SoupUri *two = v2; - if (one->protocol == two->protocol && - !strcmp (one->path ? one->path : "", - two->path ? two->path : "") && - !strcmp (one->querystring ? one->querystring : "", - two->querystring ? two->querystring : "") && - !strcmp (one->user ? one->user : "", - two->user ? two->user : "") && - !strcmp (one->passwd ? one->passwd : "", - two->passwd ? two->passwd : "")) - return TRUE; + if (one->protocol != two->protocol) + return FALSE; + if (!parts_equal (one->path, two->path)) + return FALSE; + if (!parts_equal (one->user, two->user)) + return FALSE; + if (!parts_equal (one->passwd, two->passwd)) + return FALSE; + if (!parts_equal (one->querystring, two->querystring)) + return FALSE; - return FALSE; + return TRUE; } /** @@ -545,8 +549,10 @@ soup_context_cancel_connect (SoupConnectId tag) if (data->timeout_tag) g_source_remove (data->timeout_tag); - else if (data->connect_tag) + else if (data->connect_tag) { + connection_count--; soup_socket_connect_cancel (data->connect_tag); + } g_free (data); } @@ -590,14 +596,12 @@ soup_connection_release (SoupConnection *conn) static void soup_connection_setup_socket (GIOChannel *channel) { -#if TCP_NODELAY && !SOUP_WIN32 int yes = 1, flags = 0, fd = g_io_channel_unix_get_fd (channel); setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); flags = fcntl(fd, F_GETFL, 0); fcntl (fd, F_SETFL, flags | O_NONBLOCK); -#endif } /** @@ -628,7 +632,7 @@ soup_connection_get_iochannel (SoupConnection *conn) } /** - * soup_connection_set_keepalive: + * soup_connection_set_keep_alive: * @conn: a %SoupConnection. * @keep_alive: boolean keep-alive value. * @@ -642,7 +646,7 @@ soup_connection_set_keep_alive (SoupConnection *conn, gboolean keep_alive) } /** - * soup_connection_set_keepalive: + * soup_connection_is_keep_alive: * @conn: a %SoupConnection. * * Returns the keep-alive flag for the %SoupConnection pointed to by diff --git a/libsoup/soup-context.h b/libsoup/soup-context.h index c10fe217..e0b008aa 100644 --- a/libsoup/soup-context.h +++ b/libsoup/soup-context.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-context.h: Asyncronous Callback-based SOAP Request Queue. + * soup-context.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c index 99cf232f..6924f392 100644 --- a/libsoup/soup-headers.c +++ b/libsoup/soup-headers.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-headers.c: Asyncronous Callback-based SOAP Request Queue. + * soup-headers.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -121,7 +121,7 @@ soup_headers_parse_request (gchar *str, guint http_major, http_minor; gchar method[16], path[1024]; - if (!str || !*str || len < sizeof ("GET / HTTP/0.0\r\n\r\n")) + if (!str || !*str || len < sizeof ("GET / HTTP/0.0\r\n\r\n") - 1) goto THROW_MALFORMED_HEADER; if (sscanf (str, diff --git a/libsoup/soup-headers.h b/libsoup/soup-headers.h index 5f33480c..70aaa7ba 100644 --- a/libsoup/soup-headers.h +++ b/libsoup/soup-headers.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-headers.h: Asyncronous Callback-based SOAP Request Queue. + * soup-headers.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c index 654ee19c..16e87fce 100644 --- a/libsoup/soup-message.c +++ b/libsoup/soup-message.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-message.c: Asyncronous Callback-based SOAP Request Queue. + * soup-message.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -17,18 +17,6 @@ #include "soup-queue.h" #include "soup-transfer.h" -typedef struct { - SoupHandlerEvent type; - gchar *name; - SoupHandlerWhen order; - SoupHandlerFilter filter; - SoupHandlerFn handler_cb; - gpointer user_data; - - SoupMessage *msg; - guint timeout_tag; -} SoupHandlerData; - /** * soup_message_new: * @context: a %SoupContext for the destination endpoint. @@ -193,6 +181,11 @@ soup_message_cleanup (SoupMessage *req) req->connection); req->priv->read_tag = 0; req->connection = NULL; + /* + * The buffer doesn't belong to us until the message is + * finished. + */ + req->response.owner = SOUP_BUFFER_STATIC; } if (req->priv->read_tag) { @@ -218,22 +211,6 @@ soup_message_cleanup (SoupMessage *req) soup_queue_remove_request (req); } -static void -handler_free (SoupHandlerData *data) -{ - if (data->filter.type == SOUP_FILTER_HEADER) - g_free ((gchar *) data->filter.data.header); - - if (data->timeout_tag) - g_source_remove (data->timeout_tag); - - data->msg->priv->content_handlers = - g_slist_remove (data->msg->priv->content_handlers, data); - - g_free (data->name); - g_free (data); -} - static void finalize_message (SoupMessage *req) { @@ -251,10 +228,8 @@ finalize_message (SoupMessage *req) soup_message_clear_headers (req->response_headers); g_hash_table_destroy (req->response_headers); - while (req->priv->content_handlers) { - SoupHandlerData *data = req->priv->content_handlers->data; - handler_free (data); - } + g_slist_foreach (req->priv->content_handlers, (GFunc) g_free, NULL); + g_slist_free (req->priv->content_handlers); g_free ((gchar *) req->errorphrase); g_free (req->priv); @@ -322,6 +297,11 @@ void soup_message_cancel (SoupMessage *msg) { soup_message_set_error (msg, SOUP_ERROR_CANCELLED); + + /* Kill the connection as a safety measure */ + if (msg->connection) + soup_connection_set_keep_alive (msg->connection, FALSE); + soup_message_issue_callback (msg); } @@ -512,6 +492,122 @@ soup_message_foreach_remove_header (GHashTable *hash, &data); } +/** + * soup_message_set_request_header: + * @req: a %SoupMessage. + * @name: header name. + * @value: header value. + * + * ** DEPRECATED ** + * + * Adds a new transport header to be sent on an outgoing request. Passing a NULL + * @value will remove all headers with a name equal to @name. + */ +void +soup_message_set_request_header (SoupMessage *req, + const gchar *name, + const gchar *value) +{ + g_return_if_fail (req != NULL); + g_return_if_fail (name != NULL || name [0] != '\0'); + + g_warning ("soup_message_set_request_header is DEPRECATED. Use " + "soup_message_add_header, with msg->request_headers as " + "the first argument.\n"); + + soup_message_add_header (req->request_headers, name, value); +} + +/** + * soup_message_get_request_header: + * @req: a %SoupMessage. + * @name: header name. + * + * ** DEPRECATED ** + * + * Lookup the first transport request header with a key equal to @name. + * + * Return value: the header's value or NULL if not found. + */ +const gchar * +soup_message_get_request_header (SoupMessage *req, + const gchar *name) +{ + GSList *vals; + g_return_val_if_fail (req != NULL, NULL); + g_return_val_if_fail (name != NULL || name [0] != '\0', NULL); + + g_warning ("soup_message_get_request_header is DEPRECATED. Use " + "soup_message_get_header, with msg->request_headers as " + "the first argument.\n"); + + if (req->request_headers) { + vals = g_hash_table_lookup (req->request_headers, name); + if (vals) + return vals->data; + } + + return NULL; +} + +/** + * soup_message_set_response_header: + * @req: a %SoupMessage. + * @name: header name. + * @value: header value. + * + * ** DEPRECATED ** + * + * Adds a new transport header to be sent on an outgoing response. Passing a + * NULL @value will remove all headers with a name equal to @name. + */ +void +soup_message_set_response_header (SoupMessage *req, + const gchar *name, + const gchar *value) +{ + g_return_if_fail (req != NULL); + g_return_if_fail (name != NULL || name [0] != '\0'); + + g_warning ("soup_message_set_response_header is DEPRECATED. Use " + "soup_message_add_header, with msg->response_headers as " + "the first argument.\n"); + + soup_message_add_header (req->response_headers, name, value); +} + +/** + * soup_message_get_response_header: + * @req: a %SoupMessage. + * @name: header name. + * + * ** DEPRECATED ** + * + * Lookup the transport response header with a key equal to @name. + * + * Return value: the header's value or NULL if not found. + */ +const gchar * +soup_message_get_response_header (SoupMessage *req, + const gchar *name) +{ + GSList *vals; + g_return_val_if_fail (req != NULL, NULL); + g_return_val_if_fail (name != NULL || name [0] != '\0', NULL); + + g_warning ("soup_message_get_response_header is DEPRECATED. Use " + "soup_message_get_header, with msg->response_headers as " + "the first argument.\n"); + + if (req->response_headers) { + vals = g_hash_table_lookup (req->response_headers, name); + if (vals) + return vals->data; + } + + return NULL; +} + /** * soup_message_queue: * @req: a %SoupMessage. @@ -604,6 +700,7 @@ requeue_read_finished (const SoupDataBuffer *buf, if (!soup_connection_is_keep_alive (msg->connection)) requeue_read_error (FALSE, data); else { + g_free (data); msg->connection = NULL; soup_queue_message (msg, @@ -677,15 +774,56 @@ soup_message_send (SoupMessage *msg) return msg->errorclass; } -static SoupHandlerResult -authorize_handler (SoupMessage *msg, gpointer user_data) +static void +maybe_validate_auth (SoupMessage *msg, gpointer user_data) { gboolean proxy = GPOINTER_TO_INT (user_data); + int auth_failure; + SoupContext *ctx; + SoupAuth *auth; + + if (proxy) { + ctx = soup_get_proxy (); + auth_failure = SOUP_ERROR_PROXY_UNAUTHORIZED; /* 407 */ + } + else { + ctx = msg->context; + auth_failure = SOUP_ERROR_UNAUTHORIZED; /* 401 */ + } + + auth = soup_auth_lookup (ctx); + if (!auth) + return; + + if (msg->errorcode == auth_failure) { + /* Pass through */ + } + else if (msg->errorclass == SOUP_ERROR_CLASS_SERVER_ERROR) { + /* + * We have no way of knowing whether our auth is any good + * anymore, so just invalidate it and start from the + * beginning next time. + */ + soup_auth_invalidate (auth, ctx); + } + else { + auth->status = SOUP_AUTH_STATUS_SUCCESSFUL; + auth->controlling_msg = NULL; + } +} /* maybe_validate_auth */ + +static void +authorize_handler (SoupMessage *msg, gboolean proxy) +{ const GSList *vals; - SoupAuth *auth, *old_auth; + SoupAuth *auth; SoupContext *ctx; const SoupUri *uri; + if (msg->connection->auth && + msg->connection->auth->status == SOUP_AUTH_STATUS_SUCCESSFUL) + goto THROW_CANT_AUTHENTICATE; + ctx = proxy ? soup_get_proxy () : msg->context; uri = soup_context_get_uri (ctx); @@ -695,18 +833,59 @@ authorize_handler (SoupMessage *msg, gpointer user_data) "WWW-Authenticate"); if (!vals) goto THROW_CANT_AUTHENTICATE; - auth = soup_auth_new_from_header_list (vals); + auth = soup_auth_lookup (ctx); + if (auth) { + g_assert (auth->status != SOUP_AUTH_STATUS_INVALID); + + if (auth->status == SOUP_AUTH_STATUS_PENDING) { + if (auth->controlling_msg == msg) { + auth->status = SOUP_AUTH_STATUS_FAILED; + goto THROW_CANT_AUTHENTICATE; + } + else { + soup_message_requeue (msg); + return; + } + } + else if (auth->status == SOUP_AUTH_STATUS_FAILED || + auth->status == SOUP_AUTH_STATUS_SUCCESSFUL) { + /* + * We've failed previously, but we'll give it + * another go, or we've been successful + * previously, but it's not working anymore. + * + * Invalidate the auth, so it's removed from the + * hash and try it again as if we never had it + * in the first place. + */ + soup_auth_invalidate (auth, ctx); + soup_message_requeue (msg); + return; + } + } + if (!auth) { - soup_message_set_error_full ( - msg, - proxy ? - SOUP_ERROR_CANT_AUTHENTICATE_PROXY : - SOUP_ERROR_CANT_AUTHENTICATE, - proxy ? - "Unknown authentication scheme required by " - "proxy" : - "Unknown authentication scheme required"); - return SOUP_HANDLER_RESTART; + auth = soup_auth_new_from_header_list (uri, vals); + + if (!auth) { + soup_message_set_error_full ( + msg, + proxy ? + SOUP_ERROR_CANT_AUTHENTICATE_PROXY : + SOUP_ERROR_CANT_AUTHENTICATE, + proxy ? + "Unknown authentication scheme " + "required by proxy" : + "Unknown authentication scheme " + "required"); + return; + } + + auth->status = SOUP_AUTH_STATUS_PENDING; + auth->controlling_msg = msg; + soup_message_add_handler (msg, SOUP_HANDLER_PRE_BODY, + maybe_validate_auth, + GINT_TO_POINTER (proxy)); } /* @@ -724,47 +903,38 @@ authorize_handler (SoupMessage *msg, gpointer user_data) } /* - * Initialize with auth data (possibly returned from auth callback). + * Initialize with auth data (possibly returned from + * auth callback). */ soup_auth_initialize (auth, uri); - if (auth->type == SOUP_AUTH_TYPE_NTLM) - old_auth = msg->connection->auth; - else - old_auth = soup_auth_lookup (ctx); - - if (old_auth) { - if (!soup_auth_invalidates_prior (auth, old_auth)) { - soup_auth_free (auth); - goto THROW_CANT_AUTHENTICATE; - } - } - if (auth->type == SOUP_AUTH_TYPE_NTLM) { - if (old_auth) + SoupAuth *old_auth = msg->connection->auth; + + if (old_auth) soup_auth_free (old_auth); msg->connection->auth = auth; } else soup_auth_set_context (auth, ctx); - return SOUP_HANDLER_RESEND; + soup_message_requeue (msg); + + return; THROW_CANT_AUTHENTICATE: soup_message_set_error (msg, proxy ? SOUP_ERROR_CANT_AUTHENTICATE_PROXY : SOUP_ERROR_CANT_AUTHENTICATE); - return SOUP_HANDLER_RESTART; } -static SoupHandlerResult +static void redirect_handler (SoupMessage *msg, gpointer user_data) { const gchar *new_loc; if (msg->errorclass != SOUP_ERROR_CLASS_REDIRECT || - msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT) - return SOUP_HANDLER_CONTINUE; + msg->priv->msg_flags & SOUP_MESSAGE_NO_REDIRECT) return; new_loc = soup_message_get_header (msg->response_headers, "Location"); @@ -798,141 +968,96 @@ redirect_handler (SoupMessage *msg, gpointer user_data) soup_message_set_context (msg, new_ctx); soup_context_unref (new_ctx); - return SOUP_HANDLER_RESEND; + soup_message_requeue (msg); } - return SOUP_HANDLER_CONTINUE; + return; INVALID_REDIRECT: soup_message_set_error_full (msg, SOUP_ERROR_MALFORMED, "Invalid Redirect URL"); - return SOUP_HANDLER_RESTART; } +typedef enum { + RESPONSE_HEADER_HANDLER = 1, + RESPONSE_ERROR_CODE_HANDLER, + RESPONSE_ERROR_CLASS_HANDLER +} SoupHandlerKind; + +typedef struct { + SoupHandlerType type; + SoupCallbackFn handler_cb; + gpointer user_data; + + SoupHandlerKind kind; + union { + guint errorcode; + SoupErrorClass errorclass; + const gchar *header; + } data; +} SoupHandlerData; + static SoupHandlerData global_handlers [] = { /* * Handle redirect response codes 300, 301, 302, 303, and 305. */ { - SOUP_HANDLER_HEADERS, - "redirect", - 0, - { - SOUP_FILTER_HEADER, - { - (guint) "Location" - }, - }, + SOUP_HANDLER_PRE_BODY, redirect_handler, NULL, + RESPONSE_HEADER_HANDLER, + { (guint) "Location" } }, /* * Handle authorization. */ { - SOUP_HANDLER_HEADERS, - "authenticate", - 0, - { - SOUP_FILTER_ERROR_CODE, - { - 401 - }, - }, - authorize_handler, + SOUP_HANDLER_PRE_BODY, + (SoupCallbackFn) authorize_handler, GINT_TO_POINTER (FALSE), + RESPONSE_ERROR_CODE_HANDLER, + { 401 } }, /* * Handle proxy authorization. */ { - SOUP_HANDLER_HEADERS, - "proxy-authenticate", - 0, - { - SOUP_FILTER_ERROR_CODE, - { - 407 - }, - }, - authorize_handler, + SOUP_HANDLER_PRE_BODY, + (SoupCallbackFn) authorize_handler, GINT_TO_POINTER (TRUE), + RESPONSE_ERROR_CODE_HANDLER, + { 407 } }, { 0 } }; -static inline SoupHandlerResult -run_handler (SoupMessage *msg, - SoupHandlerEvent invoke_type, - SoupHandlerEvent when, - SoupHandlerData *data) +static inline void +run_handler (SoupMessage *msg, + SoupHandlerType invoke_type, + SoupHandlerData *data) { - SoupHandlerResult result; + if (data->type != invoke_type) return; - if (data->type != invoke_type || data->order != when) - return SOUP_HANDLER_CONTINUE; - - switch (data->filter.type) { - case SOUP_FILTER_HEADER: + switch (data->kind) { + case RESPONSE_HEADER_HANDLER: if (!soup_message_get_header (msg->response_headers, - data->filter.data.header)) - return SOUP_HANDLER_CONTINUE; - break; - case SOUP_FILTER_ERROR_CODE: - if (msg->errorcode != data->filter.data.errorcode) - return SOUP_HANDLER_CONTINUE; - break; - case SOUP_FILTER_ERROR_CLASS: - if (msg->errorclass != data->filter.data.errorclass) - return SOUP_HANDLER_CONTINUE; - break; - case SOUP_FILTER_TIMEOUT: - return SOUP_HANDLER_CONTINUE; - default: - break; - } - - result = (*data->handler_cb) (msg, data->user_data); - - switch (result) { - case SOUP_HANDLER_STOP: - if (invoke_type == SOUP_HANDLER_FINISHED && - msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL) - soup_message_issue_callback (msg); + data->data.header)) + return; break; - case SOUP_HANDLER_KILL: - soup_message_issue_callback (msg); + case RESPONSE_ERROR_CODE_HANDLER: + if (msg->errorcode != data->data.errorcode) return; break; - case SOUP_HANDLER_RESEND: - if (msg->status != SOUP_STATUS_QUEUED) - soup_message_queue (msg, - msg->priv->callback, - msg->priv->user_data); + case RESPONSE_ERROR_CLASS_HANDLER: + if (msg->errorclass != data->data.errorclass) return; break; default: - if (msg->status == SOUP_STATUS_QUEUED) - result = SOUP_HANDLER_RESEND; break; } - return result; + (*data->handler_cb) (msg, data->user_data); } -#define PROCESS_HANDLER_RESULT(result) ({ \ - switch (result) { \ - case SOUP_HANDLER_STOP: \ - return FALSE; \ - case SOUP_HANDLER_KILL: \ - case SOUP_HANDLER_RESEND: \ - return TRUE; \ - case SOUP_HANDLER_RESTART: \ - goto RESTART; \ - default: \ - break; \ - } \ -}) - /* * Run each handler with matching criteria (first per-message then global * handlers). If a handler requeues a message, we stop processing and terminate @@ -945,55 +1070,34 @@ run_handler (SoupMessage *msg, * processing. */ gboolean -soup_message_run_handlers (SoupMessage *msg, SoupHandlerEvent invoke_type) +soup_message_run_handlers (SoupMessage *msg, SoupHandlerType invoke_type) { GSList *list; SoupHandlerData *data; - SoupHandlerResult result; g_return_val_if_fail (msg != NULL, FALSE); - RESTART: - /* - * Pre-Global handlers - */ for (list = msg->priv->content_handlers; list; list = list->next) { data = list->data; - result = run_handler (msg, - invoke_type, - SOUP_HANDLER_FIRST, - data); - PROCESS_HANDLER_RESULT (result); + + run_handler (msg, invoke_type, data); + + if (msg->status == SOUP_STATUS_QUEUED || + msg->status == SOUP_STATUS_CONNECTING) return TRUE; } - /* - * Global handlers - */ for (data = global_handlers; data->type; data++) { - result = run_handler (msg, - invoke_type, - 0, - data); - PROCESS_HANDLER_RESULT (result); - } + run_handler (msg, invoke_type, data); - /* - * Post-Global handlers - */ - for (list = msg->priv->content_handlers; list; list = list->next) { - data = list->data; - result = run_handler (msg, - invoke_type, - SOUP_HANDLER_LAST, - data); - PROCESS_HANDLER_RESULT (result); + if (msg->status == SOUP_STATUS_QUEUED || + msg->status == SOUP_STATUS_CONNECTING) return TRUE; } /* - * Issue final callback if the invoke_type is FINISHED and the error + * Issue final callback if the invoke_type is POST_BODY and the error * class is not INFORMATIONAL. */ - if (invoke_type == SOUP_HANDLER_FINISHED && + if (invoke_type == SOUP_HANDLER_POST_BODY && msg->errorclass != SOUP_ERROR_CLASS_INFORMATIONAL) { soup_message_issue_callback (msg); return TRUE; @@ -1002,201 +1106,146 @@ soup_message_run_handlers (SoupMessage *msg, SoupHandlerEvent invoke_type) return FALSE; } -static gboolean -timeout_handler (gpointer user_data) +static void +add_handler (SoupMessage *msg, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data, + SoupHandlerKind kind, + const gchar *header, + guint errorcode, + guint errorclass) { - SoupHandlerData *data = user_data; - SoupMessage *msg = data->msg; - SoupHandlerResult result; - - switch (data->type) { - case SOUP_HANDLER_PREPARE: - if (msg->status >= SOUP_STATUS_SENDING_REQUEST) - goto REMOVE_SOURCE; - case SOUP_HANDLER_HEADERS: - case SOUP_HANDLER_DATA: - if (msg->status >= SOUP_STATUS_READING_RESPONSE && - g_hash_table_size (msg->response_headers) > 0) - goto REMOVE_SOURCE; - case SOUP_HANDLER_FINISHED: - if (msg->status == SOUP_STATUS_FINISHED) - goto REMOVE_SOURCE; - } + SoupHandlerData *data; - result = (*data->handler_cb) (msg, data->user_data); + data = g_new0 (SoupHandlerData, 1); + data->type = type; + data->handler_cb = handler_cb; + data->user_data = user_data; + data->kind = kind; - switch (result) { - case SOUP_HANDLER_KILL: - soup_message_cancel (msg); + switch (kind) { + case RESPONSE_HEADER_HANDLER: + data->data.header = header; break; - case SOUP_HANDLER_RESEND: - soup_message_queue (msg, - msg->priv->callback, - msg->priv->user_data); + case RESPONSE_ERROR_CODE_HANDLER: + data->data.errorcode = errorcode; + break; + case RESPONSE_ERROR_CLASS_HANDLER: + data->data.errorclass = errorclass; break; default: break; } - REMOVE_SOURCE: - data->timeout_tag = 0; - return FALSE; + msg->priv->content_handlers = + g_slist_append (msg->priv->content_handlers, data); } void -soup_message_add_handler_full (SoupMessage *msg, - const gchar *name, - SoupHandlerEvent type, - SoupHandlerWhen order, - SoupHandlerFilter *filter, - SoupHandlerFn handler_cb, - gpointer user_data) +soup_message_add_header_handler (SoupMessage *msg, + const gchar *header, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data) { - SoupHandlerData *data; - g_return_if_fail (msg != NULL); - g_return_if_fail (type != 0); - g_return_if_fail (order != 0); + g_return_if_fail (header != NULL); g_return_if_fail (handler_cb != NULL); - data = g_new0 (SoupHandlerData, 1); - data->type = type; - data->handler_cb = handler_cb; - data->user_data = user_data; - data->name = g_strdup (name); - data->order = order; - data->msg = msg; - - if (filter) { - data->filter.type = filter->type; - - switch (filter->type) { - case SOUP_FILTER_HEADER: - data->filter.data.header = - g_strdup (filter->data.header); - break; - case SOUP_FILTER_ERROR_CODE: - data->filter.data.errorcode = filter->data.errorcode; - break; - case SOUP_FILTER_ERROR_CLASS: - data->filter.data.errorclass = filter->data.errorclass; - break; - case SOUP_FILTER_TIMEOUT: - data->filter.data.timeout = filter->data.timeout; - data->timeout_tag = - g_timeout_add (filter->data.timeout * 1000, - timeout_handler, - data); - break; - default: - break; - } - } - - msg->priv->content_handlers = - g_slist_append (msg->priv->content_handlers, data); + add_handler (msg, + type, + handler_cb, + user_data, + RESPONSE_HEADER_HANDLER, + header, + 0, + 0); } void -soup_message_add_handler (SoupMessage *msg, - SoupHandlerEvent type, - SoupHandlerFilter *filter, - SoupHandlerFn handler_cb, - gpointer user_data) +soup_message_add_error_code_handler (SoupMessage *msg, + guint errorcode, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data) { g_return_if_fail (msg != NULL); - g_return_if_fail (type != 0); + g_return_if_fail (errorcode != 0); g_return_if_fail (handler_cb != NULL); - soup_message_add_handler_full (msg, - NULL, - type, - SOUP_HANDLER_LAST, - filter, - handler_cb, - user_data); -} - -GSList * -soup_message_list_handlers (SoupMessage *msg) -{ - GSList *ret = NULL, *list; - - g_return_val_if_fail (msg != NULL, NULL); - - for (list = msg->priv->content_handlers; list; list = list->next) { - SoupHandlerData *data = list->data; - if (data->name) - ret = g_slist_append (ret, data->name); - } - - return ret; + add_handler (msg, + type, + handler_cb, + user_data, + RESPONSE_ERROR_CODE_HANDLER, + NULL, + errorcode, + 0); } void -soup_message_remove_handler (SoupMessage *msg, - gchar *name) +soup_message_add_error_class_handler (SoupMessage *msg, + SoupErrorClass errorclass, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data) { - GSList *iter; - g_return_if_fail (msg != NULL); - g_return_if_fail (name != NULL); - - iter = msg->priv->content_handlers; - while (iter) { - SoupHandlerData *data = iter->data; - - if (data->name && !g_strcasecmp (data->name, name)) { - handler_free (data); - break; - } + g_return_if_fail (errorclass != 0); + g_return_if_fail (handler_cb != NULL); - iter = iter->next; - } + add_handler (msg, + type, + handler_cb, + user_data, + RESPONSE_ERROR_CLASS_HANDLER, + NULL, + 0, + errorclass); } void -soup_message_remove_handler_by_func (SoupMessage *msg, - SoupHandlerFn handler_cb) +soup_message_add_handler (SoupMessage *msg, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data) { - GSList *iter; - g_return_if_fail (msg != NULL); g_return_if_fail (handler_cb != NULL); - iter = msg->priv->content_handlers; - while (iter) { - SoupHandlerData *data = iter->data; - - if (data->handler_cb == handler_cb) { - handler_free (data); - break; - } - - iter = iter->next; - } + add_handler (msg, + type, + handler_cb, + user_data, + 0, + NULL, + 0, + 0); } -void -soup_message_remove_handler_by_func_and_data (SoupMessage *msg, - SoupHandlerFn handler_cb, - gpointer user_data) +void +soup_message_remove_handler (SoupMessage *msg, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data) { - GSList *iter; - - g_return_if_fail (msg != NULL); - g_return_if_fail (handler_cb != NULL); + GSList *iter = msg->priv->content_handlers; - iter = msg->priv->content_handlers; while (iter) { SoupHandlerData *data = iter->data; - if (data->handler_cb == handler_cb && - data->user_data == user_data) { - handler_free (data); + if (data->handler_cb == handler_cb && + data->user_data == user_data && + data->type == type) { + msg->priv->content_handlers = + g_slist_remove_link ( + msg->priv->content_handlers, + iter); + g_free (data); break; } - + iter = iter->next; } } diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h index 631da19d..c46c6e94 100644 --- a/libsoup/soup-message.h +++ b/libsoup/soup-message.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-message.h: Asyncronous Callback-based SOAP Request Queue. + * soup-message.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -173,103 +173,39 @@ guint soup_message_get_flags (SoupMessage *msg); * Handler Registration */ typedef enum { - SOUP_HANDLER_PREPARE = 0, - SOUP_HANDLER_HEADERS, - SOUP_HANDLER_DATA, - SOUP_HANDLER_FINISHED, -} SoupHandlerEvent; - -typedef enum { - SOUP_FILTER_HEADER = (1 << 0), - SOUP_FILTER_ERROR_CODE = (1 << 1), - SOUP_FILTER_ERROR_CLASS = (1 << 2), - SOUP_FILTER_TIMEOUT = (1 << 3), -} SoupHandlerFilterType; - -typedef struct { - gint type; - - union { - guint errorcode; - SoupErrorClass errorclass; - const gchar *header; - guint timeout; - } data; -} SoupHandlerFilter; - -typedef enum { - /* - * Continue processing as normal. - */ - SOUP_HANDLER_CONTINUE, - - /* - * Do not process further handlers. Continue receiving data. - */ - SOUP_HANDLER_STOP, - - /* - * do not process further handlers. Stop receiving data and - * issue final callback. - */ - SOUP_HANDLER_KILL, - - /* - * Restart handler processing. This should be returned if a - * handler changes the message's errorcode. - */ - SOUP_HANDLER_RESTART, - - /* - * Requeue the request immediately. Stop processing handlers - * and do not issue final callback. - */ - SOUP_HANDLER_RESEND -} SoupHandlerResult; - -typedef SoupHandlerResult (*SoupHandlerFn) (SoupMessage *req, - gpointer user_data); + SOUP_HANDLER_PRE_BODY = 1, + SOUP_HANDLER_BODY_CHUNK, + SOUP_HANDLER_POST_BODY +} SoupHandlerType; void soup_message_add_handler (SoupMessage *msg, - SoupHandlerEvent type, - SoupHandlerFilter *filter, - SoupHandlerFn handler_cb, + SoupHandlerType type, + SoupCallbackFn handler_cb, gpointer user_data); -typedef enum { - /* - * Run before global handlers and previously registered message - * handlers. - */ - SOUP_HANDLER_FIRST, - - /* - * Run after global handlers and previously registered message - * handlers. - */ - SOUP_HANDLER_LAST -} SoupHandlerWhen; +void soup_message_add_header_handler (SoupMessage *msg, + const gchar *header, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data); -void soup_message_add_handler_full (SoupMessage *msg, - const gchar *name, - SoupHandlerEvent type, - SoupHandlerWhen order, - SoupHandlerFilter *filter, - SoupHandlerFn handler_cb, +void soup_message_add_error_code_handler ( + SoupMessage *msg, + guint errorcode, + SoupHandlerType type, + SoupCallbackFn handler_cb, gpointer user_data); -GSList *soup_message_list_handlers (SoupMessage *msg); +void soup_message_add_error_class_handler ( + SoupMessage *msg, + SoupErrorClass errorclass, + SoupHandlerType type, + SoupCallbackFn handler_cb, + gpointer user_data); void soup_message_remove_handler (SoupMessage *msg, - gchar *name); - -void soup_message_remove_handler_by_func ( - SoupMessage *msg, - SoupHandlerFn handler_cb); - -void soup_message_remove_handler_by_func_and_data ( - SoupMessage *msg, - SoupHandlerFn handler_cb, + SoupHandlerType type, + SoupCallbackFn handler_cb, gpointer user_data); /* @@ -286,4 +222,24 @@ void soup_message_set_handler_error (SoupMessage *msg, guint errcode, const gchar *errphrase); +/** DEPRECATED API **/ + +/** DEPRECATED **/ +void soup_message_set_request_header (SoupMessage *req, + const gchar *name, + const gchar *value); + +/** DEPRECATED **/ +const gchar *soup_message_get_request_header (SoupMessage *req, + const gchar *name); + +/** DEPRECATED **/ +void soup_message_set_response_header (SoupMessage *req, + const gchar *name, + const gchar *value); + +/** DEPRECATED **/ +const gchar *soup_message_get_response_header (SoupMessage *req, + const gchar *name); + #endif /*SOUP_MESSAGE_H*/ diff --git a/libsoup/soup-misc.c b/libsoup/soup-misc.c index 1310fe5c..aa7765c4 100644 --- a/libsoup/soup-misc.c +++ b/libsoup/soup-misc.c @@ -687,6 +687,11 @@ soup_shutdown () soup_queue_shutdown (); } +static char *ssl_ca_file = NULL; +static char *ssl_ca_dir = NULL; +static char *ssl_cert_file = NULL; +static char *ssl_key_file = NULL; + /** * soup_set_ca_file: * @ca_file: the path to a CA file @@ -695,9 +700,11 @@ soup_shutdown () * peers. */ void -soup_set_ssl_ca_file (gchar *ca_file) +soup_set_ssl_ca_file (const gchar *ca_file) { - putenv (g_strdup_printf ("HTTPS_CA_FILE=%s", ca_file)); + g_free (ssl_ca_file); + + ssl_ca_file = g_strdup (ca_file); } /** @@ -708,9 +715,11 @@ soup_set_ssl_ca_file (gchar *ca_file) * peers. */ void -soup_set_ssl_ca_dir (gchar *ca_dir) +soup_set_ssl_ca_dir (const gchar *ca_dir) { - putenv (g_strdup_printf ("HTTPS_CA_DIR=%s", ca_dir)); + g_free (ssl_ca_dir); + + ssl_ca_dir = g_strdup (ca_dir); } /** @@ -719,13 +728,58 @@ soup_set_ssl_ca_dir (gchar *ca_dir) * @key_file: the file containing the SSL private key * * Specify a SSL client certificate to be used for client - * authentication with the SOAP server + * authentication with the HTTP server */ void -soup_set_ssl_cert_files (gchar *cert_file, gchar *key_file) +soup_set_ssl_cert_files (const gchar *cert_file, const gchar *key_file) { - putenv (g_strdup_printf ("HTTPS_CERT_FILE=%s", cert_file)); - putenv (g_strdup_printf ("HTTPS_KEY_FILE=%s", key_file)); + g_free (ssl_cert_file); + g_free (ssl_key_file); + + ssl_cert_file = g_strdup (cert_file); + ssl_key_file = g_strdup (key_file); +} + +/** + * soup_get_ca_file: + * + * Return value: A file containing CA certificates to be used to verify + * peers. + */ +const char * +soup_get_ssl_ca_file (void) +{ + return ssl_ca_file; +} + +/** + * soup_get_ca_dir + * + * Return value: A directory containing CA certificates to be used to verify + * peers. + */ +const char * +soup_get_ssl_ca_dir (void) +{ + return ssl_ca_dir; +} + +/** + * soup_get_ssl_cert_files + * @cert_file: the file containing the SSL client certificate + * @key_file: the file containing the SSL private key + * + * Specify a SSL client certificate to be used for client + * authentication with the HTTP server + */ +void +soup_get_ssl_cert_files (const gchar **cert_file, const gchar **key_file) +{ + if (cert_file) + *cert_file = ssl_cert_file; + + if (key_file) + *key_file = ssl_key_file; } SoupAuthorizeFn soup_auth_fn = NULL; diff --git a/libsoup/soup-misc.h b/libsoup/soup-misc.h index be80993b..ba3aa8c5 100644 --- a/libsoup/soup-misc.h +++ b/libsoup/soup-misc.h @@ -42,12 +42,17 @@ SoupSecurityPolicy soup_get_security_policy (void); /* SSL setup routines */ -void soup_set_ssl_ca_file (gchar *ca_file); +void soup_set_ssl_ca_file (const gchar *ca_file); -void soup_set_ssl_ca_dir (gchar *ca_dir); +void soup_set_ssl_ca_dir (const gchar *ca_dir); -void soup_set_ssl_cert_files (gchar *cert_file, - gchar *key_file); +void soup_set_ssl_cert_files (const gchar *cert_file, + const gchar *key_file); + +const char *soup_get_ssl_ca_file (void); +const char *soup_get_ssl_ca_dir (void); +void soup_get_ssl_cert_files (const gchar **cert_file, + const gchar **key_file); /* Authentication callback */ diff --git a/libsoup/soup-nss.c b/libsoup/soup-nss.c index edadbd93..a9517528 100644 --- a/libsoup/soup-nss.c +++ b/libsoup/soup-nss.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-nss.c: Asyncronous Callback-based SOAP Request Queue. + * soup-nss.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -295,7 +295,7 @@ soup_nss_bad_cert (void *data, PRFileDesc *fd) } GIOChannel * -soup_nss_get_iochannel (GIOChannel *sock) +soup_nss_get_iochannel (GIOChannel *sock, SoupSSLType type) { SoupNSSChannel *chan; GIOChannel *gchan; @@ -322,7 +322,10 @@ soup_nss_get_iochannel (GIOChannel *sock) } SSL_OptionSet (fdesc, SSL_SECURITY, PR_TRUE); - SSL_OptionSet (fdesc, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + if (type == SOUP_SSL_TYPE_CLIENT) + SSL_OptionSet (fdesc, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + else + SSL_OptionSet (fdesc, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); SSL_BadCertHook (fdesc, soup_nss_bad_cert, NULL); if (SSL_ResetHandshake (fdesc, PR_FALSE) == PR_FAILURE) { diff --git a/libsoup/soup-nss.h b/libsoup/soup-nss.h index 1aaa0a45..99ac3fe6 100644 --- a/libsoup/soup-nss.h +++ b/libsoup/soup-nss.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-nss.h: Asyncronous Callback-based SOAP Request Queue. + * soup-nss.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -13,8 +13,9 @@ #include #include +#include -GIOChannel *soup_nss_get_iochannel (GIOChannel *sock); +GIOChannel *soup_nss_get_iochannel (GIOChannel *sock, SoupSSLType type); void soup_nss_set_security_policy (SoupSecurityPolicy policy); diff --git a/libsoup/soup-ntlm.c b/libsoup/soup-ntlm.c index 64f809fe..734c7eec 100644 --- a/libsoup/soup-ntlm.c +++ b/libsoup/soup-ntlm.c @@ -44,7 +44,7 @@ static void calc_response (const guchar *key, "\x00\x00\x00\x00\x00" void -soup_ntlm_lanmanager_hash (const char *password, char hash[21]) +soup_ntlm_lanmanager_hash (const char *password, guchar hash[21]) { guchar lm_password [15]; DES_KS ks; @@ -66,7 +66,7 @@ soup_ntlm_lanmanager_hash (const char *password, char hash[21]) } void -soup_ntlm_nt_hash (const char *password, char hash[21]) +soup_ntlm_nt_hash (const char *password, guchar hash[21]) { unsigned char *buf, *p; @@ -90,13 +90,12 @@ typedef struct { guchar zero_pad[2]; } NTLMString; -#define NTLM_CHALLENGE_NONCE_OFFSET 24 -#define NTLM_CHALLENGE_NONCE_LENGTH 8 -#define NTLM_CHALLENGE_DOMAIN_OFFSET 48 -#define NTLM_CHALLENGE_DOMAIN_LEN_OFFSET 44 +#define NTLM_CHALLENGE_NONCE_OFFSET 24 +#define NTLM_CHALLENGE_NONCE_LENGTH 8 +#define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00" -#define NTLM_RESPONSE_FLAGS "\x82\x01" +#define NTLM_RESPONSE_FLAGS 0x8202 typedef struct { guchar header[12]; @@ -106,25 +105,16 @@ typedef struct { NTLMString domain; NTLMString user; NTLMString host; + NTLMString session_key; - guint16 msg_len; - guchar zero_pad[2]; - - guchar flags[2]; - guchar zero_pad2[2]; + guint32 flags; } NTLMResponse; -#if G_BYTE_ORDER == G_BIG_ENDIAN -#define LE16(x) (((x & 0xFF) << 8) | ((x >> 8) & 0xFF)) -#else -#define LE16(x) x -#endif - static void ntlm_set_string (NTLMString *string, int *offset, int len) { - string->offset = LE16 (*offset); - string->length = string->length2 = LE16 (len); + string->offset = GUINT16_TO_LE (*offset); + string->length = string->length2 = GUINT16_TO_LE (len); *offset += len; } @@ -134,53 +124,82 @@ soup_ntlm_request (void) return g_strdup ("NTLM TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA"); } -char * -soup_ntlm_response (const char *challenge, - const char *user, - const char *lm_hash, - const char *nt_hash, - const char *host, - const char *domain) +gboolean +soup_ntlm_parse_challenge (const char *challenge, + char **nonce, + char **default_domain) { - int hlen, dlen, ulen, offset, decodelen; - guchar lm_resp[24], nt_resp[24], *nonce; - NTLMResponse resp; + int clen, decodelen; + NTLMString domain; char *chall; - unsigned char *out, *p; int state, save; if (strncmp (challenge, "NTLM ", 5) != 0) - return NULL; + return FALSE; decodelen = strlen (challenge) - 5; chall = g_malloc (decodelen); state = save = 0; - soup_base64_decode_step ((guchar *) challenge + 5, - decodelen, - chall, - &state, - &save); + clen = soup_base64_decode_step ((guchar *) challenge + 5, + decodelen, + chall, + &state, + &save); + + if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET || + clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) { + g_free (chall); + return FALSE; + } + + if (default_domain) { + memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain)); + domain.length = GUINT16_FROM_LE (domain.length); + domain.offset = GUINT16_FROM_LE (domain.offset); + + if (clen < domain.length + domain.offset) { + g_free (chall); + return FALSE; + } + + *default_domain = g_strndup (chall + domain.offset, domain.length); + } + + if (nonce) { + *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET, + NTLM_CHALLENGE_NONCE_LENGTH); + } - nonce = chall + NTLM_CHALLENGE_NONCE_OFFSET; - nonce [NTLM_CHALLENGE_NONCE_LENGTH] = '\0'; + g_free (chall); + return TRUE; +} - calc_response (lm_hash, nonce, lm_resp); - calc_response (nt_hash, nonce, nt_resp); +char * +soup_ntlm_response (const char *nonce, + const char *user, + const char *password, + const char *host, + const char *domain) +{ + int hlen, dlen, ulen, offset; + guchar hash[21], lm_resp[24], nt_resp[24]; + NTLMResponse resp; + unsigned char *out, *p; + int state, save; + + soup_ntlm_lanmanager_hash (password, hash); + calc_response (hash, nonce, lm_resp); + soup_ntlm_nt_hash (password, hash); + calc_response (hash, nonce, nt_resp); memset (&resp, 0, sizeof (resp)); memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header)); - memcpy (resp.flags, NTLM_RESPONSE_FLAGS, sizeof (resp.flags)); + resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS); offset = sizeof (resp); - if (domain) - dlen = strlen (domain); - else { - /* Grab the default domain from the challenge */ - domain = chall + NTLM_CHALLENGE_DOMAIN_OFFSET; - dlen = atoi (chall + NTLM_CHALLENGE_DOMAIN_LEN_OFFSET); - } + dlen = strlen (domain); ntlm_set_string (&resp.domain, &offset, dlen); ulen = strlen (user); ntlm_set_string (&resp.user, &offset, ulen); @@ -235,14 +254,10 @@ soup_ntlm_response (const char *challenge, &state, &save); *p = '\0'; - g_free (chall); return out; } -#define KEYBITS(k,s) \ - (((k[(s)/8] << ((s)%8)) & 0xFF) | (k[(s)/8+1] >> (8-(s)%8))) - /* DES utils */ /* Set up a key schedule based on a 56bit key */ static void @@ -251,15 +266,22 @@ setup_schedule (const guchar *key_56, DES_KS ks) guchar key[8]; int i, c, bit; - for (i = 0; i < 8; i++) { - key [i] = KEYBITS (key_56, i * 7); + key[0] = (key_56[0]) ; + key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF); + key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF); + key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF); + key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF); + key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF); + key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF); + key[7] = ((key_56[6] << 1) & 0xFF); - /* Fix parity */ + /* Fix parity */ + for (i = 0; i < 8; i++) { for (c = bit = 0; bit < 8; bit++) - if (key [i] & (1 << bit)) + if (key[i] & (1 << bit)) c++; if (!(c & 1)) - key [i] ^= 0x01; + key[i] ^= 0x01; } deskey (ks, key, 0); @@ -410,134 +432,134 @@ md4sum (const unsigned char *in, int nbytes, unsigned char digest[16]) /* Public domain DES implementation from Phil Karn */ static unsigned long Spbox[8][64] = { - 0x01010400,0x00000000,0x00010000,0x01010404, - 0x01010004,0x00010404,0x00000004,0x00010000, - 0x00000400,0x01010400,0x01010404,0x00000400, - 0x01000404,0x01010004,0x01000000,0x00000004, - 0x00000404,0x01000400,0x01000400,0x00010400, - 0x00010400,0x01010000,0x01010000,0x01000404, - 0x00010004,0x01000004,0x01000004,0x00010004, - 0x00000000,0x00000404,0x00010404,0x01000000, - 0x00010000,0x01010404,0x00000004,0x01010000, - 0x01010400,0x01000000,0x01000000,0x00000400, - 0x01010004,0x00010000,0x00010400,0x01000004, - 0x00000400,0x00000004,0x01000404,0x00010404, - 0x01010404,0x00010004,0x01010000,0x01000404, - 0x01000004,0x00000404,0x00010404,0x01010400, - 0x00000404,0x01000400,0x01000400,0x00000000, - 0x00010004,0x00010400,0x00000000,0x01010004, - 0x80108020,0x80008000,0x00008000,0x00108020, - 0x00100000,0x00000020,0x80100020,0x80008020, - 0x80000020,0x80108020,0x80108000,0x80000000, - 0x80008000,0x00100000,0x00000020,0x80100020, - 0x00108000,0x00100020,0x80008020,0x00000000, - 0x80000000,0x00008000,0x00108020,0x80100000, - 0x00100020,0x80000020,0x00000000,0x00108000, - 0x00008020,0x80108000,0x80100000,0x00008020, - 0x00000000,0x00108020,0x80100020,0x00100000, - 0x80008020,0x80100000,0x80108000,0x00008000, - 0x80100000,0x80008000,0x00000020,0x80108020, - 0x00108020,0x00000020,0x00008000,0x80000000, - 0x00008020,0x80108000,0x00100000,0x80000020, - 0x00100020,0x80008020,0x80000020,0x00100020, - 0x00108000,0x00000000,0x80008000,0x00008020, - 0x80000000,0x80100020,0x80108020,0x00108000, - 0x00000208,0x08020200,0x00000000,0x08020008, - 0x08000200,0x00000000,0x00020208,0x08000200, - 0x00020008,0x08000008,0x08000008,0x00020000, - 0x08020208,0x00020008,0x08020000,0x00000208, - 0x08000000,0x00000008,0x08020200,0x00000200, - 0x00020200,0x08020000,0x08020008,0x00020208, - 0x08000208,0x00020200,0x00020000,0x08000208, - 0x00000008,0x08020208,0x00000200,0x08000000, - 0x08020200,0x08000000,0x00020008,0x00000208, - 0x00020000,0x08020200,0x08000200,0x00000000, - 0x00000200,0x00020008,0x08020208,0x08000200, - 0x08000008,0x00000200,0x00000000,0x08020008, - 0x08000208,0x00020000,0x08000000,0x08020208, - 0x00000008,0x00020208,0x00020200,0x08000008, - 0x08020000,0x08000208,0x00000208,0x08020000, - 0x00020208,0x00000008,0x08020008,0x00020200, - 0x00802001,0x00002081,0x00002081,0x00000080, - 0x00802080,0x00800081,0x00800001,0x00002001, - 0x00000000,0x00802000,0x00802000,0x00802081, - 0x00000081,0x00000000,0x00800080,0x00800001, - 0x00000001,0x00002000,0x00800000,0x00802001, - 0x00000080,0x00800000,0x00002001,0x00002080, - 0x00800081,0x00000001,0x00002080,0x00800080, - 0x00002000,0x00802080,0x00802081,0x00000081, - 0x00800080,0x00800001,0x00802000,0x00802081, - 0x00000081,0x00000000,0x00000000,0x00802000, - 0x00002080,0x00800080,0x00800081,0x00000001, - 0x00802001,0x00002081,0x00002081,0x00000080, - 0x00802081,0x00000081,0x00000001,0x00002000, - 0x00800001,0x00002001,0x00802080,0x00800081, - 0x00002001,0x00002080,0x00800000,0x00802001, - 0x00000080,0x00800000,0x00002000,0x00802080, - 0x00000100,0x02080100,0x02080000,0x42000100, - 0x00080000,0x00000100,0x40000000,0x02080000, - 0x40080100,0x00080000,0x02000100,0x40080100, - 0x42000100,0x42080000,0x00080100,0x40000000, - 0x02000000,0x40080000,0x40080000,0x00000000, - 0x40000100,0x42080100,0x42080100,0x02000100, - 0x42080000,0x40000100,0x00000000,0x42000000, - 0x02080100,0x02000000,0x42000000,0x00080100, - 0x00080000,0x42000100,0x00000100,0x02000000, - 0x40000000,0x02080000,0x42000100,0x40080100, - 0x02000100,0x40000000,0x42080000,0x02080100, - 0x40080100,0x00000100,0x02000000,0x42080000, - 0x42080100,0x00080100,0x42000000,0x42080100, - 0x02080000,0x00000000,0x40080000,0x42000000, - 0x00080100,0x02000100,0x40000100,0x00080000, - 0x00000000,0x40080000,0x02080100,0x40000100, - 0x20000010,0x20400000,0x00004000,0x20404010, - 0x20400000,0x00000010,0x20404010,0x00400000, - 0x20004000,0x00404010,0x00400000,0x20000010, - 0x00400010,0x20004000,0x20000000,0x00004010, - 0x00000000,0x00400010,0x20004010,0x00004000, - 0x00404000,0x20004010,0x00000010,0x20400010, - 0x20400010,0x00000000,0x00404010,0x20404000, - 0x00004010,0x00404000,0x20404000,0x20000000, - 0x20004000,0x00000010,0x20400010,0x00404000, - 0x20404010,0x00400000,0x00004010,0x20000010, - 0x00400000,0x20004000,0x20000000,0x00004010, - 0x20000010,0x20404010,0x00404000,0x20400000, - 0x00404010,0x20404000,0x00000000,0x20400010, - 0x00000010,0x00004000,0x20400000,0x00404010, - 0x00004000,0x00400010,0x20004010,0x00000000, - 0x20404000,0x20000000,0x00400010,0x20004010, - 0x00200000,0x04200002,0x04000802,0x00000000, - 0x00000800,0x04000802,0x00200802,0x04200800, - 0x04200802,0x00200000,0x00000000,0x04000002, - 0x00000002,0x04000000,0x04200002,0x00000802, - 0x04000800,0x00200802,0x00200002,0x04000800, - 0x04000002,0x04200000,0x04200800,0x00200002, - 0x04200000,0x00000800,0x00000802,0x04200802, - 0x00200800,0x00000002,0x04000000,0x00200800, - 0x04000000,0x00200800,0x00200000,0x04000802, - 0x04000802,0x04200002,0x04200002,0x00000002, - 0x00200002,0x04000000,0x04000800,0x00200000, - 0x04200800,0x00000802,0x00200802,0x04200800, - 0x00000802,0x04000002,0x04200802,0x04200000, - 0x00200800,0x00000000,0x00000002,0x04200802, - 0x00000000,0x00200802,0x04200000,0x00000800, - 0x04000002,0x04000800,0x00000800,0x00200002, - 0x10001040,0x00001000,0x00040000,0x10041040, - 0x10000000,0x10001040,0x00000040,0x10000000, - 0x00040040,0x10040000,0x10041040,0x00041000, - 0x10041000,0x00041040,0x00001000,0x00000040, - 0x10040000,0x10000040,0x10001000,0x00001040, - 0x00041000,0x00040040,0x10040040,0x10041000, - 0x00001040,0x00000000,0x00000000,0x10040040, - 0x10000040,0x10001000,0x00041040,0x00040000, - 0x00041040,0x00040000,0x10041000,0x00001000, - 0x00000040,0x10040040,0x00001000,0x00041040, - 0x10001000,0x00000040,0x10000040,0x10040000, - 0x10040040,0x10000000,0x00040000,0x10001040, - 0x00000000,0x10041040,0x00040040,0x10000040, - 0x10040000,0x10001000,0x10001040,0x00000000, - 0x10041040,0x00041000,0x00041000,0x00001040, - 0x00001040,0x00040040,0x10000000,0x10041000, + { 0x01010400,0x00000000,0x00010000,0x01010404, + 0x01010004,0x00010404,0x00000004,0x00010000, + 0x00000400,0x01010400,0x01010404,0x00000400, + 0x01000404,0x01010004,0x01000000,0x00000004, + 0x00000404,0x01000400,0x01000400,0x00010400, + 0x00010400,0x01010000,0x01010000,0x01000404, + 0x00010004,0x01000004,0x01000004,0x00010004, + 0x00000000,0x00000404,0x00010404,0x01000000, + 0x00010000,0x01010404,0x00000004,0x01010000, + 0x01010400,0x01000000,0x01000000,0x00000400, + 0x01010004,0x00010000,0x00010400,0x01000004, + 0x00000400,0x00000004,0x01000404,0x00010404, + 0x01010404,0x00010004,0x01010000,0x01000404, + 0x01000004,0x00000404,0x00010404,0x01010400, + 0x00000404,0x01000400,0x01000400,0x00000000, + 0x00010004,0x00010400,0x00000000,0x01010004 }, + { 0x80108020,0x80008000,0x00008000,0x00108020, + 0x00100000,0x00000020,0x80100020,0x80008020, + 0x80000020,0x80108020,0x80108000,0x80000000, + 0x80008000,0x00100000,0x00000020,0x80100020, + 0x00108000,0x00100020,0x80008020,0x00000000, + 0x80000000,0x00008000,0x00108020,0x80100000, + 0x00100020,0x80000020,0x00000000,0x00108000, + 0x00008020,0x80108000,0x80100000,0x00008020, + 0x00000000,0x00108020,0x80100020,0x00100000, + 0x80008020,0x80100000,0x80108000,0x00008000, + 0x80100000,0x80008000,0x00000020,0x80108020, + 0x00108020,0x00000020,0x00008000,0x80000000, + 0x00008020,0x80108000,0x00100000,0x80000020, + 0x00100020,0x80008020,0x80000020,0x00100020, + 0x00108000,0x00000000,0x80008000,0x00008020, + 0x80000000,0x80100020,0x80108020,0x00108000 }, + { 0x00000208,0x08020200,0x00000000,0x08020008, + 0x08000200,0x00000000,0x00020208,0x08000200, + 0x00020008,0x08000008,0x08000008,0x00020000, + 0x08020208,0x00020008,0x08020000,0x00000208, + 0x08000000,0x00000008,0x08020200,0x00000200, + 0x00020200,0x08020000,0x08020008,0x00020208, + 0x08000208,0x00020200,0x00020000,0x08000208, + 0x00000008,0x08020208,0x00000200,0x08000000, + 0x08020200,0x08000000,0x00020008,0x00000208, + 0x00020000,0x08020200,0x08000200,0x00000000, + 0x00000200,0x00020008,0x08020208,0x08000200, + 0x08000008,0x00000200,0x00000000,0x08020008, + 0x08000208,0x00020000,0x08000000,0x08020208, + 0x00000008,0x00020208,0x00020200,0x08000008, + 0x08020000,0x08000208,0x00000208,0x08020000, + 0x00020208,0x00000008,0x08020008,0x00020200 }, + { 0x00802001,0x00002081,0x00002081,0x00000080, + 0x00802080,0x00800081,0x00800001,0x00002001, + 0x00000000,0x00802000,0x00802000,0x00802081, + 0x00000081,0x00000000,0x00800080,0x00800001, + 0x00000001,0x00002000,0x00800000,0x00802001, + 0x00000080,0x00800000,0x00002001,0x00002080, + 0x00800081,0x00000001,0x00002080,0x00800080, + 0x00002000,0x00802080,0x00802081,0x00000081, + 0x00800080,0x00800001,0x00802000,0x00802081, + 0x00000081,0x00000000,0x00000000,0x00802000, + 0x00002080,0x00800080,0x00800081,0x00000001, + 0x00802001,0x00002081,0x00002081,0x00000080, + 0x00802081,0x00000081,0x00000001,0x00002000, + 0x00800001,0x00002001,0x00802080,0x00800081, + 0x00002001,0x00002080,0x00800000,0x00802001, + 0x00000080,0x00800000,0x00002000,0x00802080 }, + { 0x00000100,0x02080100,0x02080000,0x42000100, + 0x00080000,0x00000100,0x40000000,0x02080000, + 0x40080100,0x00080000,0x02000100,0x40080100, + 0x42000100,0x42080000,0x00080100,0x40000000, + 0x02000000,0x40080000,0x40080000,0x00000000, + 0x40000100,0x42080100,0x42080100,0x02000100, + 0x42080000,0x40000100,0x00000000,0x42000000, + 0x02080100,0x02000000,0x42000000,0x00080100, + 0x00080000,0x42000100,0x00000100,0x02000000, + 0x40000000,0x02080000,0x42000100,0x40080100, + 0x02000100,0x40000000,0x42080000,0x02080100, + 0x40080100,0x00000100,0x02000000,0x42080000, + 0x42080100,0x00080100,0x42000000,0x42080100, + 0x02080000,0x00000000,0x40080000,0x42000000, + 0x00080100,0x02000100,0x40000100,0x00080000, + 0x00000000,0x40080000,0x02080100,0x40000100 }, + { 0x20000010,0x20400000,0x00004000,0x20404010, + 0x20400000,0x00000010,0x20404010,0x00400000, + 0x20004000,0x00404010,0x00400000,0x20000010, + 0x00400010,0x20004000,0x20000000,0x00004010, + 0x00000000,0x00400010,0x20004010,0x00004000, + 0x00404000,0x20004010,0x00000010,0x20400010, + 0x20400010,0x00000000,0x00404010,0x20404000, + 0x00004010,0x00404000,0x20404000,0x20000000, + 0x20004000,0x00000010,0x20400010,0x00404000, + 0x20404010,0x00400000,0x00004010,0x20000010, + 0x00400000,0x20004000,0x20000000,0x00004010, + 0x20000010,0x20404010,0x00404000,0x20400000, + 0x00404010,0x20404000,0x00000000,0x20400010, + 0x00000010,0x00004000,0x20400000,0x00404010, + 0x00004000,0x00400010,0x20004010,0x00000000, + 0x20404000,0x20000000,0x00400010,0x20004010 }, + { 0x00200000,0x04200002,0x04000802,0x00000000, + 0x00000800,0x04000802,0x00200802,0x04200800, + 0x04200802,0x00200000,0x00000000,0x04000002, + 0x00000002,0x04000000,0x04200002,0x00000802, + 0x04000800,0x00200802,0x00200002,0x04000800, + 0x04000002,0x04200000,0x04200800,0x00200002, + 0x04200000,0x00000800,0x00000802,0x04200802, + 0x00200800,0x00000002,0x04000000,0x00200800, + 0x04000000,0x00200800,0x00200000,0x04000802, + 0x04000802,0x04200002,0x04200002,0x00000002, + 0x00200002,0x04000000,0x04000800,0x00200000, + 0x04200800,0x00000802,0x00200802,0x04200800, + 0x00000802,0x04000002,0x04200802,0x04200000, + 0x00200800,0x00000000,0x00000002,0x04200802, + 0x00000000,0x00200802,0x04200000,0x00000800, + 0x04000002,0x04000800,0x00000800,0x00200002 }, + { 0x10001040,0x00001000,0x00040000,0x10041040, + 0x10000000,0x10001040,0x00000040,0x10000000, + 0x00040040,0x10040000,0x10041040,0x00041000, + 0x10041000,0x00041040,0x00001000,0x00000040, + 0x10040000,0x10000040,0x10001000,0x00001040, + 0x00041000,0x00040040,0x10040040,0x10041000, + 0x00001040,0x00000000,0x00000000,0x10040040, + 0x10000040,0x10001000,0x00041040,0x00040000, + 0x00041040,0x00040000,0x10041000,0x00001000, + 0x00000040,0x10040040,0x00001000,0x00041040, + 0x10001000,0x00000040,0x10000040,0x10040000, + 0x10040040,0x10000000,0x00040000,0x10001040, + 0x00000000,0x10041040,0x00040040,0x10000040, + 0x10040000,0x10001000,0x10001040,0x00000000, + 0x10041040,0x00041000,0x00041000,0x00001040, + 0x00001040,0x00040040,0x10000000,0x10041000 } }; #undef F diff --git a/libsoup/soup-ntlm.h b/libsoup/soup-ntlm.h index 3149805a..5b35f429 100644 --- a/libsoup/soup-ntlm.h +++ b/libsoup/soup-ntlm.h @@ -13,19 +13,22 @@ #include -void soup_ntlm_lanmanager_hash (const char *password, - char hash[21]); +void soup_ntlm_lanmanager_hash (const char *password, + guchar hash[21]); -void soup_ntlm_nt_hash (const char *password, - char hash[21]); +void soup_ntlm_nt_hash (const char *password, + guchar hash[21]); -char *soup_ntlm_request (void); +char *soup_ntlm_request (void); -char *soup_ntlm_response (const char *challenge, - const char *user, - const char *lm_hash, - const char *nt_hash, - const char *host, - const char *domain); +gboolean soup_ntlm_parse_challenge (const char *challenge, + char **nonce, + char **default_domain); + +char *soup_ntlm_response (const char *nonce, + const char *user, + const char *password, + const char *host, + const char *domain); #endif /* NTLM_H */ diff --git a/libsoup/soup-openssl.c b/libsoup/soup-openssl.c index d8c8eac9..015cbf50 100644 --- a/libsoup/soup-openssl.c +++ b/libsoup/soup-openssl.c @@ -14,10 +14,7 @@ #ifdef HAVE_OPENSSL_SSL_H -#ifdef HAVE_UNISTD_H #include -#endif - #include #include @@ -27,6 +24,8 @@ #include "soup-openssl.h" +static gboolean server_mode = FALSE; + typedef struct { GIOChannel channel; gint fd; @@ -34,11 +33,21 @@ typedef struct { SSL *ssl; } SoupOpenSSLChannel; -static GIOError +static void +soup_openssl_free (GIOChannel *channel) +{ + SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; + g_io_channel_unref (chan->real_sock); + SSL_free (chan->ssl); + g_free (chan); +} + +static GIOStatus soup_openssl_read (GIOChannel *channel, gchar *buf, guint count, - guint *bytes_read) + guint *bytes_read, + GError **err) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; gint result; @@ -49,27 +58,32 @@ soup_openssl_read (GIOChannel *channel, /* This occurs when a re-handshake is required */ *bytes_read = 0; if (SSL_get_error (chan->ssl, result) == SSL_ERROR_WANT_READ) - return G_IO_ERROR_AGAIN; + return G_IO_STATUS_AGAIN; switch (errno) { case EINVAL: +#if 0 return G_IO_ERROR_INVAL; +#else + return G_IO_STATUS_ERROR; +#endif case EAGAIN: case EINTR: - return G_IO_ERROR_AGAIN; + return G_IO_STATUS_AGAIN; default: - return G_IO_ERROR_UNKNOWN; + return G_IO_STATUS_ERROR; } } else { *bytes_read = result; - return G_IO_ERROR_NONE; + return G_IO_STATUS_NORMAL; } } -static GIOError +static GIOStatus soup_openssl_write (GIOChannel *channel, - gchar *buf, - guint count, - guint *bytes_written) + const gchar *buf, + gsize count, + gsize *bytes_written, + GError **err) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; gint result; @@ -78,119 +92,183 @@ soup_openssl_write (GIOChannel *channel, if (result < 0) { *bytes_written = 0; - if (SSL_get_error (chan->ssl, result) == SSL_ERROR_WANT_READ) - return G_IO_ERROR_AGAIN; + if (SSL_get_error (chan->ssl, result) == SSL_ERROR_WANT_WRITE) + return G_IO_STATUS_AGAIN; switch (errno) { case EINVAL: +#if 0 return G_IO_ERROR_INVAL; +#else + return G_IO_STATUS_ERROR; +#endif case EAGAIN: case EINTR: - return G_IO_ERROR_AGAIN; + return G_IO_STATUS_AGAIN; default: - return G_IO_ERROR_UNKNOWN; + return G_IO_STATUS_ERROR; } } else { *bytes_written = result; - return G_IO_ERROR_NONE; + + return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF; } } -static GIOError -soup_openssl_seek (GIOChannel *channel, gint offset, GSeekType type) +static GIOStatus +soup_openssl_seek (GIOChannel *channel, + gint64 offset, + GSeekType type, + GError **err) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; - return g_io_channel_seek (chan->real_sock, offset, type); + GIOError e; + + e = g_io_channel_seek (chan->real_sock, offset, type); + + if (e != G_IO_ERROR_NONE) + return G_IO_STATUS_ERROR; + else + return G_IO_STATUS_NORMAL; } -static void -soup_openssl_close (GIOChannel *channel) +static GIOStatus +soup_openssl_close (GIOChannel *channel, + GError **err) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; g_io_channel_close (chan->real_sock); + + return G_IO_STATUS_NORMAL; } -static void -soup_openssl_free (GIOChannel *channel) +typedef struct { + GSource source; + GPollFD pollfd; + GIOChannel *channel; + GIOCondition condition; +} SoupOpenSSLWatch; + +static gboolean +soup_openssl_prepare (GSource *source, + gint *timeout) { - SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; - g_io_channel_unref (chan->real_sock); - SSL_free (chan->ssl); - g_free (chan); + SoupOpenSSLWatch *watch = (SoupOpenSSLWatch *) source; + GIOCondition buffer_condition = g_io_channel_get_buffer_condition ( + watch->channel); + + *timeout = -1; + + /* Only return TRUE here if _all_ bits in watch->condition will be set + */ + return ((watch->condition & buffer_condition) == watch->condition); } -#if 0 +static gboolean +soup_openssl_check (GSource *source) +{ + SoupOpenSSLWatch *watch = (SoupOpenSSLWatch *) source; + GIOCondition buffer_condition = g_io_channel_get_buffer_condition ( + watch->channel); + GIOCondition poll_condition = watch->pollfd.revents; -/* Commented out until we can figure out why SSL_pending always fails */ + return ((poll_condition | buffer_condition) & watch->condition); +} -typedef struct { - GIOFunc func; - gpointer user_data; -} SoupOpenSSLReadData; - -static gboolean -soup_openssl_read_cb (GIOChannel *channel, - GIOCondition condition, - gpointer user_data) +static gboolean +soup_openssl_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) { - SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; - SoupOpenSSLReadData *data = user_data; + GIOFunc func = (GIOFunc) callback; + SoupOpenSSLWatch *watch = (SoupOpenSSLWatch *) source; + SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) watch->channel; + GIOCondition buffer_condition = g_io_channel_get_buffer_condition ( + watch->channel); + GIOCondition cond; + + if (!func) { + g_warning ("IO watch dispatched without callback\n" + "You must call g_source_connect()."); + return FALSE; + } + + cond = (watch->pollfd.revents | buffer_condition) & watch->condition; - if (condition & G_IO_IN) { - if (SSL_pending (chan->ssl) && - !(*data->func) (channel, condition, data->user_data)) { - g_free (data); + if (cond & G_IO_IN) { + do { + if (!(*func) (watch->channel, cond, user_data)) return FALSE; - } + } while (SSL_pending (chan->ssl)); + return TRUE; - } else return (*data->func) (channel, condition, data->user_data); + } else + return (*func) (watch->channel, cond, user_data); +} + +static void +soup_openssl_finalize (GSource *source) +{ + SoupOpenSSLWatch *watch = (SoupOpenSSLWatch *) source; + + g_io_channel_unref (watch->channel); } -static guint -soup_openssl_add_watch (GIOChannel *channel, - gint priority, - GIOCondition condition, - GIOFunc func, - gpointer user_data, - GDestroyNotify notify) +/* All of these functions were basically cut-and-pasted from glib */ +GSourceFuncs soup_openssl_watch_funcs = { + soup_openssl_prepare, + soup_openssl_check, + soup_openssl_dispatch, + soup_openssl_finalize +}; + +static GSource * +soup_openssl_create_watch (GIOChannel *channel, + GIOCondition condition) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; if (condition & G_IO_IN) { - SoupOpenSSLReadData *data = g_new0 (SoupOpenSSLReadData, 1); - data->func = func; - data->user_data = user_data; - - return chan->real_sock->funcs->io_add_watch (channel, - priority, - condition, - soup_openssl_read_cb, - data, - notify); - } else return chan->real_sock->funcs->io_add_watch (channel, - priority, - condition, - func, - user_data, - notify); + GSource *source; + SoupOpenSSLWatch *watch; + + source = g_source_new (&soup_openssl_watch_funcs, + sizeof (SoupOpenSSLWatch)); + watch = (SoupOpenSSLWatch *) source; + + watch->channel = channel; + g_io_channel_ref (channel); + + watch->condition = condition; + + watch->pollfd.fd = chan->fd; + watch->pollfd.events = condition; + + g_source_add_poll (source, &watch->pollfd); + + return source; + } + else { + return chan->real_sock->funcs->io_create_watch (channel, + condition); + } } -#endif /* 0 */ +static GIOStatus +soup_openssl_set_flags (GIOChannel *channel, + GIOFlags flags, + GError **err) +{ + SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; -static guint -soup_openssl_add_watch (GIOChannel *channel, - gint priority, - GIOCondition condition, - GIOFunc func, - gpointer user_data, - GDestroyNotify notify) + return chan->real_sock->funcs->io_set_flags (channel, flags, err); +} + +static GIOFlags +soup_openssl_get_flags (GIOChannel *channel) { SoupOpenSSLChannel *chan = (SoupOpenSSLChannel *) channel; - return chan->real_sock->funcs->io_add_watch (channel, - priority, - condition, - func, - user_data, - notify); + + return chan->real_sock->funcs->io_get_flags (channel); } GIOFuncs soup_openssl_channel_funcs = { @@ -198,8 +276,10 @@ GIOFuncs soup_openssl_channel_funcs = { soup_openssl_write, soup_openssl_seek, soup_openssl_close, - soup_openssl_add_watch, + soup_openssl_create_watch, soup_openssl_free, + soup_openssl_set_flags, + soup_openssl_get_flags }; static SSL_CTX *ssl_context = NULL; @@ -258,7 +338,7 @@ soup_openssl_get_iochannel (GIOChannel *sock) g_return_val_if_fail (sock != NULL, NULL); - if (!ssl_context && !soup_openssl_init ()) + if (!ssl_context && !soup_openssl_init (server_mode)) goto THROW_CREATE_ERROR; if (!soup_openssl_seed ()) @@ -283,12 +363,13 @@ soup_openssl_get_iochannel (GIOChannel *sock) goto THROW_CREATE_ERROR; } - if (!SSL_use_RSAPrivateKey_file (ssl, ckey_file, 1)) { + if (!SSL_use_RSAPrivateKey_file (ssl, ckey_file, SSL_FILETYPE_PEM)) { g_warning ("Unable to use private key file."); + ERR_print_errors_fp(stderr); goto THROW_CREATE_ERROR; } - if (!SSL_use_certificate_file (ssl, ccert_file, 1)) { + if (!SSL_use_certificate_file (ssl, ccert_file, SSL_FILETYPE_PEM)) { g_warning ("Unable to use certificate file."); goto THROW_CREATE_ERROR; } @@ -307,25 +388,31 @@ soup_openssl_get_iochannel (GIOChannel *sock) goto THROW_CREATE_ERROR; } - while (1) { - err = SSL_connect (ssl); - switch (SSL_get_error (ssl, err)) { - case SSL_ERROR_NONE: - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - { - fd_set readfds; - FD_ZERO (&readfds); - FD_SET (sockfd, &readfds); - select (1, &readfds, NULL, NULL, NULL); - continue; + do { + fd_set ssl_fdset; + + if (server_mode) + err = SSL_accept (ssl); + else + err = SSL_connect (ssl); + + err = SSL_get_error (ssl, err); + + if (err == SSL_ERROR_WANT_READ) { + FD_ZERO (&ssl_fdset); + FD_SET (sockfd, &ssl_fdset); + select (sockfd + 1, &ssl_fdset, NULL, NULL, NULL); } - default: + else if (err == SSL_ERROR_WANT_WRITE) { + FD_ZERO (&ssl_fdset); + FD_SET (sockfd, &ssl_fdset); + select (sockfd + 1, NULL, &ssl_fdset, NULL, NULL); + } + else if (err != SSL_ERROR_NONE) { g_warning ("Could not establish secure connection."); goto THROW_CREATE_ERROR; } - } + } while (err != SSL_ERROR_NONE); bits = SSL_get_cipher_bits (ssl, &alg_bits); if (bits == 0) { @@ -333,12 +420,15 @@ soup_openssl_get_iochannel (GIOChannel *sock) goto THROW_CREATE_ERROR; } - cert = SSL_get_peer_certificate (ssl); - if (!cert) { - g_warning ("Server certificate unavailable"); - goto THROW_CREATE_ERROR; + if (!server_mode) { + cert = SSL_get_peer_certificate (ssl); + if (!cert) { + g_warning ("Server certificate unavailable"); + goto THROW_CREATE_ERROR; + } + else + X509_free (cert); } - X509_free (cert); chan = g_new0 (SoupOpenSSLChannel, 1); chan->fd = sockfd; @@ -356,8 +446,17 @@ soup_openssl_get_iochannel (GIOChannel *sock) return NULL; } +static int +verify_cb (int verified, X509_STORE_CTX *x509_ctx) +{ + if (!verified) + g_warning ("Unable to verify server's CA"); + + return verified; +} + gboolean -soup_openssl_init (void) +soup_openssl_init (gboolean server) { static gchar *ssl_ca_file = NULL; static gchar *ssl_ca_dir = NULL; @@ -365,7 +464,13 @@ soup_openssl_init (void) SSL_library_init (); SSL_load_error_strings (); - ssl_context = SSL_CTX_new (SSLv23_client_method ()); + server_mode = server; + + if (server_mode) + ssl_context = SSL_CTX_new (SSLv23_server_method ()); + else + ssl_context = SSL_CTX_new (SSLv23_client_method ()); + if (!ssl_context) { g_warning ("Unable to initialize OpenSSL library"); return FALSE; @@ -380,7 +485,7 @@ soup_openssl_init (void) SSL_CTX_load_verify_locations (ssl_context, ssl_ca_file, ssl_ca_dir); - SSL_CTX_set_verify (ssl_context, SSL_VERIFY_PEER, NULL); + SSL_CTX_set_verify (ssl_context, SSL_VERIFY_PEER, verify_cb); } return TRUE; diff --git a/libsoup/soup-openssl.h b/libsoup/soup-openssl.h index 2a00983b..dbcd25a7 100644 --- a/libsoup/soup-openssl.h +++ b/libsoup/soup-openssl.h @@ -18,6 +18,6 @@ GIOChannel *soup_openssl_get_iochannel (GIOChannel *sock); void soup_openssl_set_security_policy (SoupSecurityPolicy policy); -gboolean soup_openssl_init (void); +gboolean soup_openssl_init (gboolean server_mode); #endif /* SOUP_OPENSSL_H */ diff --git a/libsoup/soup-private.h b/libsoup/soup-private.h index 55005081..f31e979c 100644 --- a/libsoup/soup-private.h +++ b/libsoup/soup-private.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-private.h: Asyncronous Callback-based SOAP Request Queue. + * soup-private.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -13,46 +13,16 @@ * extraneous circumstances. */ -#ifndef SOAP_PRIVATE_H -#define SOAP_PRIVATE_H 1 +#ifndef SOUP_PRIVATE_H +#define SOUP_PRIVATE_H 1 #ifdef HAVE_CONFIG_H #include #endif -#ifdef SOUP_WIN32 -# include -# define alloca _alloca -#else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifdef _AIX -# pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ - char *alloca (); -# endif -# endif -# endif -#endif - #include - -#ifdef HAVE_NETINET_IN_H #include -#endif - -#ifdef HAVE_SYS_SOCKET_H #include -#endif - -#ifdef SOUP_WIN32 -#define VERSION "Win/0.7.99" -#include -#include -#include -#endif #include #include @@ -137,6 +107,8 @@ struct _SoupMessagePrivate { guint write_tag; guint timeout_tag; + guint retries; + SoupCallbackFn callback; gpointer user_data; @@ -156,7 +128,7 @@ struct _SoupMessagePrivate { void soup_message_issue_callback (SoupMessage *req); gboolean soup_message_run_handlers (SoupMessage *msg, - SoupHandlerEvent invoke_type); + SoupHandlerType invoke_type); void soup_message_cleanup (SoupMessage *req); diff --git a/libsoup/soup-queue.c b/libsoup/soup-queue.c index 365a582a..e0153657 100644 --- a/libsoup/soup-queue.c +++ b/libsoup/soup-queue.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -79,9 +79,19 @@ soup_queue_error_cb (gboolean body_started, gpointer user_data) case SOUP_STATUS_SENDING_REQUEST: if (!body_started) { /* - * FIXME: Use exponential backoff here + * This can easily happen if we are using the OpenSSL + * out-of-process proxy and we couldn't establish an + * SSL connection. */ - soup_message_requeue (req); + if (req->priv->retries >= 3) { + soup_message_set_error ( + req, + SOUP_ERROR_CANT_CONNECT); + soup_message_issue_callback (req); + } else { + req->priv->retries++; + soup_message_requeue (req); + } } else { soup_message_set_error (req, SOUP_ERROR_IO); soup_message_issue_callback (req); @@ -198,7 +208,7 @@ soup_queue_read_headers_cb (const GString *headers, } SUCCESS_CONTINUE: - soup_message_run_handlers (req, SOUP_HANDLER_HEADERS); + soup_message_run_handlers (req, SOUP_HANDLER_PRE_BODY); return SOUP_TRANSFER_CONTINUE; THROW_MALFORMED_HEADER: @@ -217,7 +227,7 @@ soup_queue_read_chunk_cb (const SoupDataBuffer *data, req->response.length = data->length; req->response.body = data->body; - soup_message_run_handlers (req, SOUP_HANDLER_DATA); + soup_message_run_handlers (req, SOUP_HANDLER_BODY_CHUNK); return SOUP_TRANSFER_CONTINUE; } @@ -255,7 +265,7 @@ soup_queue_read_done_cb (const SoupDataBuffer *data, req->priv->read_tag = 0; } - soup_message_run_handlers (req, SOUP_HANDLER_FINISHED); + soup_message_run_handlers (req, SOUP_HANDLER_POST_BODY); } static void @@ -497,7 +507,7 @@ start_request (SoupContext *ctx, SoupMessage *req) req->status = SOUP_STATUS_SENDING_REQUEST; } -static SoupHandlerResult +static void proxy_https_connect_cb (SoupMessage *msg, gpointer user_data) { gboolean *ret = user_data; @@ -516,8 +526,6 @@ proxy_https_connect_cb (SoupMessage *msg, gpointer user_data) *ret = TRUE; } - - return SOUP_HANDLER_CONTINUE; } static gboolean @@ -538,8 +546,7 @@ proxy_https_connect (SoupContext *proxy, connect_msg = soup_message_new (dest_ctx, SOUP_METHOD_CONNECT); connect_msg->connection = conn; soup_message_add_handler (connect_msg, - SOUP_HANDLER_FINISHED, - NULL, + SOUP_HANDLER_POST_BODY, proxy_https_connect_cb, &ret); soup_message_send (connect_msg); diff --git a/libsoup/soup-queue.h b/libsoup/soup-queue.h index 30ba5d3f..0def1f44 100644 --- a/libsoup/soup-queue.h +++ b/libsoup/soup-queue.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.h: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c index 82c4179a..fe689ad0 100644 --- a/libsoup/soup-server.c +++ b/libsoup/soup-server.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-server.c: Asyncronous Callback-based SOAP Request Queue. + * soup-server.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -16,9 +16,7 @@ #include #endif -#ifdef HAVE_UNISTD_H #include -#endif #ifdef HAVE_SYS_FILIO_H #include @@ -28,12 +26,6 @@ #include #endif -#ifdef SOUP_WIN32 -#define ioctl ioctlsocket -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#endif - extern char **environ; #include @@ -200,6 +192,33 @@ static gboolean start_another_request (GIOChannel *serv_chan, GIOCondition condition, gpointer user_data); +static gboolean +check_close_connection (SoupMessage *msg) +{ + const char *connection_hdr; + gboolean close_connection; + + connection_hdr = soup_message_get_header (msg->request_headers, + "Connection"); + + if (msg->priv->http_version == SOUP_HTTP_1_0) { + if (connection_hdr && g_strcasecmp (connection_hdr, + "keep-alive") == 0) + close_connection = FALSE; + else + close_connection = TRUE; + } + else { + if (connection_hdr && g_strcasecmp (connection_hdr, + "close") == 0) + close_connection = TRUE; + else + close_connection = FALSE; + } + + return close_connection; +} /* check_close_connection */ + static void destroy_message (SoupMessage *msg) { @@ -208,18 +227,24 @@ destroy_message (SoupMessage *msg) SoupServerMessage *server_msg = msg->priv->server_msg; if (server_sock) { - if (server_msg && msg->priv->http_version == SOUP_HTTP_1_0) - /* - * Close the socket if we are using HTTP/1.0 and - * did not specify a Content-Length response header. - */ + GIOChannel *chan; + + chan = soup_socket_get_iochannel (server_sock); + + /* + * Close the socket if we're using HTTP/1.0 and + * "Connection: keep-alive" isn't specified, or if we're + * using HTTP/1.1 and "Connection: close" was specified. + */ + if (check_close_connection (msg)) { + g_io_channel_close (chan); soup_socket_unref (server_sock); + } else { /* * Listen for another request on this connection */ ServerConnectData *data; - GIOChannel *chan; data = g_new0 (ServerConnectData, 1); data->server = msg->priv->server; @@ -413,6 +438,85 @@ get_server_sockname (gint fd) return host; } +static void +write_header (gchar *key, gchar *value, GString *ret) +{ + g_string_sprintfa (ret, "%s: %s\r\n", key, value); +} + +static GString * +get_response_header (SoupMessage *req, + gboolean status_line, + SoupTransferEncoding encoding) +{ + GString *ret = g_string_new (NULL); + + if (status_line) + g_string_sprintfa (ret, + "HTTP/1.1 %d %s\r\n", + req->errorcode, + req->errorphrase); + else + g_string_sprintfa (ret, + "Status: %d %s\r\n", + req->errorcode, + req->errorphrase); + + if (encoding == SOUP_TRANSFER_CONTENT_LENGTH) + g_string_sprintfa (ret, + "Content-Length: %d\r\n", + req->response.length); + else if (encoding == SOUP_TRANSFER_CHUNKED) + g_string_append (ret, "Transfer-Encoding: chunked\r\n"); + + soup_message_foreach_header (req->response_headers, + (GHFunc) write_header, + ret); + + g_string_append (ret, "\r\n"); + + return ret; +} + +static inline void +set_response_error (SoupMessage *req, + guint code, + gchar *phrase, + gchar *body) +{ + if (phrase) + soup_message_set_error_full (req, code, phrase); + else + soup_message_set_error (req, code); + + req->response.owner = SOUP_BUFFER_STATIC; + req->response.body = body; + req->response.length = body ? strlen (req->response.body) : 0; +} + +static void +issue_bad_request (SoupMessage *msg) +{ + GString *header; + GIOChannel *channel; + + set_response_error (msg, SOUP_ERROR_BAD_REQUEST, NULL, NULL); + + header = get_response_header (msg, + FALSE, + SOUP_TRANSFER_CONTENT_LENGTH); + + channel = soup_socket_get_iochannel (msg->priv->server_sock); + + msg->priv->write_tag = + soup_transfer_write_simple (channel, + header, + &msg->response, + write_done_cb, + error_cb, + msg); +} /* issue_bad_request */ + static SoupTransferDone read_headers_cb (const GString *headers, SoupTransferEncoding *encoding, @@ -473,17 +577,7 @@ read_headers_cb (const GString *headers, req_host = soup_message_get_header (msg->request_headers, "Host"); - if (req_host) { - url = - g_strdup_printf ( - "%s%s:%d%s", - server->proto == SOUP_PROTOCOL_HTTPS ? - "https://" : - "http://", - req_host, - server->port, - req_path); - } else if (*req_path != '/') { + if (*req_path != '/') { /* * Check for absolute URI */ @@ -495,6 +589,16 @@ read_headers_cb (const GString *headers, soup_uri_free (absolute); } else goto THROW_MALFORMED_HEADER; + } else if (req_host) { + url = + g_strdup_printf ( + "%s%s:%d%s", + server->proto == SOUP_PROTOCOL_HTTPS ? + "https://" : + "http://", + req_host, + server->port, + req_path); } else { /* * No Host header, no AbsoluteUri @@ -531,65 +635,9 @@ read_headers_cb (const GString *headers, THROW_MALFORMED_HEADER: g_free (req_path); - destroy_message (msg); - - return SOUP_TRANSFER_END; -} - -static void -write_header (gchar *key, gchar *value, GString *ret) -{ - g_string_sprintfa (ret, "%s: %s\r\n", key, value); -} - -static GString * -get_response_header (SoupMessage *req, - gboolean status_line, - SoupTransferEncoding encoding) -{ - GString *ret = g_string_new (NULL); - - if (status_line) - g_string_sprintfa (ret, - "HTTP/1.1 %d %s\r\n", - req->errorcode, - req->errorphrase); - else - g_string_sprintfa (ret, - "Status: %d %s\r\n", - req->errorcode, - req->errorphrase); + issue_bad_request(msg); - if (encoding == SOUP_TRANSFER_CONTENT_LENGTH) - g_string_sprintfa (ret, - "Content-Length: %d\r\n", - req->response.length); - else if (encoding == SOUP_TRANSFER_CHUNKED) - g_string_append (ret, "Transfer-Encoding: chunked\r\n"); - - soup_message_foreach_header (req->response_headers, - (GHFunc) write_header, - ret); - - g_string_append (ret, "\r\n"); - - return ret; -} - -static inline void -set_response_error (SoupMessage *req, - guint code, - gchar *phrase, - gchar *body) -{ - if (phrase) - soup_message_set_error_full (req, code, phrase); - else - soup_message_set_error (req, code); - - req->response.owner = SOUP_BUFFER_STATIC; - req->response.body = body; - req->response.length = body ? strlen (req->response.body) : 0; + return SOUP_TRANSFER_CONTINUE; } static void @@ -792,19 +840,6 @@ read_done_cb (const SoupDataBuffer *data, req->priv->read_tag = 0; - /* FIXME: Do this in soap handler - action = soup_message_get_header (req->request_headers, "SOAPAction"); - if (!action) { - g_print ("No SOAPAction found in request.\n"); - set_response_error ( - req, - 403, - "Missing SOAPAction", - "The required SOAPAction header was not supplied."); - goto START_WRITE; - } - */ - call_handler (req, data, soup_context_get_uri (req->context)->path); channel = soup_socket_get_iochannel (server_sock); @@ -860,6 +895,7 @@ message_new (SoupServer *server) */ msg = soup_message_new (NULL, NULL); if (msg) { + msg->method = NULL; msg->priv->server = server; soup_server_ref (server); } @@ -926,7 +962,7 @@ conn_accept (GIOChannel *serv_chan, chan = soup_socket_get_iochannel (sock); if (server->proto == SOUP_PROTOCOL_HTTPS) { - chan = soup_ssl_get_iochannel (chan); + chan = soup_ssl_get_server_iochannel (chan); g_io_channel_unref (sock->iochannel); g_io_channel_ref (chan); sock->iochannel = chan; @@ -1156,6 +1192,33 @@ soup_server_get_handler (SoupServer *server, const gchar *path) return server->default_handler; } +SoupAddress * +soup_server_context_get_client_address (SoupServerContext *context) +{ + SoupSocket *socket; + SoupAddress *address; + + g_return_val_if_fail (context != NULL, NULL); + + socket = context->msg->priv->server_sock; + address = soup_socket_get_address (socket); + + return address; +} + +gchar * +soup_server_context_get_client_host (SoupServerContext *context) +{ + gchar *host; + SoupAddress *address; + + address = soup_server_context_get_client_address (context); + host = g_strdup (soup_address_get_canonical_name (address)); + soup_address_unref (address); + + return host; +} + static SoupServerAuthContext * auth_context_copy (SoupServerAuthContext *auth_ctx) { diff --git a/libsoup/soup-server.h b/libsoup/soup-server.h index 9245381a..c4bb6285 100644 --- a/libsoup/soup-server.h +++ b/libsoup/soup-server.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-server.h: Asyncronous Callback-based SOAP Request Queue. + * soup-server.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,12 @@ SoupServerHandler *soup_server_get_handler (SoupServer *serv, GSList *soup_server_list_handlers (SoupServer *serv); +/* Functions for accessing information about the specific connection */ + +SoupAddress *soup_server_context_get_client_address (SoupServerContext *context); + +gchar *soup_server_context_get_client_host (SoupServerContext *context); + /* * Apache/soup-httpd module initializtion * Implement soup_server_init() in your shared library. diff --git a/libsoup/soup-socket-unix.c b/libsoup/soup-socket-unix.c index a46fecc8..c5dd86ba 100644 --- a/libsoup/soup-socket-unix.c +++ b/libsoup/soup-socket-unix.c @@ -36,7 +36,6 @@ #include "soup-socket.h" #include -#include #include #include #include @@ -69,6 +68,11 @@ # endif #endif +/* this generally causes problems, so remove from build atm */ +#ifdef SOUP_PTRACE_ATTACH +#undef SOUP_PTRACE_ATTACH +#endif + #ifndef socklen_t #define socklen_t size_t #endif @@ -192,7 +196,7 @@ soup_gethostbyname(const char* hostname, g_free(buf); } #else -#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS +#ifdef HAVE_GETHOSTBYNAME_R_SOLARIS { struct hostent result; size_t len; @@ -348,7 +352,7 @@ soup_gethostbyaddr (const char* addr, size_t length, int type) g_free(buf); } #else -#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS +#ifdef HAVE_GETHOSTBYNAME_R_SOLARIS { struct hostent result; size_t len; diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index 4b733205..0b51ce30 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -22,17 +22,9 @@ #include "soup-private.h" #include "soup-socket.h" -#ifdef SOUP_WIN32 -# define socklen_t gint32 -# define SOUP_CLOSE_SOCKET(fd) closesocket(fd) -# define SOUP_SOCKET_IOCHANNEL_NEW(fd) g_io_channel_win32_new_socket(fd) -#else -# include -# ifndef socklen_t -# define socklen_t size_t -# endif -# define SOUP_CLOSE_SOCKET(fd) close(fd) -# define SOUP_SOCKET_IOCHANNEL_NEW(fd) g_io_channel_unix_new(fd) +#include +#ifndef socklen_t +# define socklen_t size_t #endif #ifndef INET_ADDRSTRLEN @@ -315,8 +307,6 @@ soup_socket_connect_tcp_cb (SoupSocket* socket, SoupSocketConnectFn func = state->func; gpointer user_data = state->data; - g_free (state); - if (status == SOUP_SOCKET_NEW_STATUS_OK) (*func) (socket, SOUP_SOCKET_CONNECT_ERROR_NONE, @@ -325,6 +315,9 @@ soup_socket_connect_tcp_cb (SoupSocket* socket, (*func) (NULL, SOUP_SOCKET_CONNECT_ERROR_NETWORK, user_data); + + if (state->tcp_id) + g_free (state); } static void @@ -335,31 +328,23 @@ soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr, SoupSocketConnectState* state = (SoupSocketConnectState*) data; if (status == SOUP_ADDRESS_STATUS_OK) { - gpointer tcp_id; - - state->inetaddr_id = NULL; - - tcp_id = soup_socket_new (inetaddr, - soup_socket_connect_tcp_cb, - state); - /* - * NOTE: soup_socket_new can fail immediately and call our - * callback which will delete the state. - */ - if (tcp_id) - state->tcp_id = tcp_id; - + state->tcp_id = soup_socket_new (inetaddr, + soup_socket_connect_tcp_cb, + state); soup_address_unref (inetaddr); } else { SoupSocketConnectFn func = state->func; gpointer user_data = state->data; - g_free (state); - (*func) (NULL, SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE, user_data); } + + if (state->inetaddr_id && !state->tcp_id) + g_free (state); + else + state->inetaddr_id = NULL; } /** @@ -377,8 +362,8 @@ soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr, * returns. It will call the callback if there is a failure. * * Returns: ID of the connection which can be used with - * soup_socket_connect_cancel() to cancel it; NULL on - * failure. + * soup_socket_connect_cancel() to cancel it; NULL if it succeeds + * or fails immediately. **/ SoupSocketConnectId soup_socket_connect (const gchar* hostname, @@ -388,7 +373,6 @@ soup_socket_connect (const gchar* hostname, { SoupSocketConnectState* state; SoupAddress *cached_addr; - gpointer addr_id, tcp_id; g_return_val_if_fail (hostname != NULL, NULL); g_return_val_if_fail (func != NULL, NULL); @@ -400,35 +384,26 @@ soup_socket_connect (const gchar* hostname, /* Check if a cached version of the address already exists */ cached_addr = soup_address_lookup_in_cache (hostname, port); if (cached_addr) { - tcp_id = soup_socket_new (cached_addr, - soup_socket_connect_tcp_cb, - state); + state->tcp_id = soup_socket_new (cached_addr, + soup_socket_connect_tcp_cb, + state); soup_address_unref (cached_addr); - - /* - * NOTE: soup_socket_new can fail immediately and call our - * callback which will delete the state. - */ - if (tcp_id) { - state->tcp_id = tcp_id; - return state; - } else - return NULL; } else { - addr_id = soup_address_new (hostname, - port, - soup_socket_connect_inetaddr_cb, - state); - - /* - * NOTE: soup_address_new can fail immediately and call our - * callback which will delete the state. + state->inetaddr_id = soup_address_new (hostname, + port, + soup_socket_connect_inetaddr_cb, + state); + /* NOTE: soup_address_new could succeed immediately + * and call our callback, in which case state->inetaddr_id + * will be NULL but state->tcp_id may be set. */ - if (addr_id) { - state->inetaddr_id = addr_id; - return state; - } else - return NULL; + } + + if (state->tcp_id || state->inetaddr_id) + return state; + else { + g_free (state); + return NULL; } } @@ -532,7 +507,7 @@ soup_socket_unref (SoupSocket* s) --s->ref_count; if (s->ref_count == 0) { - SOUP_CLOSE_SOCKET (s->sockfd); + close (s->sockfd); if (s->addr) soup_address_unref (s->addr); if (s->iochannel) g_io_channel_unref (s->iochannel); @@ -567,7 +542,7 @@ soup_socket_get_iochannel (SoupSocket* socket) g_return_val_if_fail (socket != NULL, NULL); if (socket->iochannel == NULL) - socket->iochannel = SOUP_SOCKET_IOCHANNEL_NEW (socket->sockfd); + socket->iochannel = g_io_channel_unix_new (socket->sockfd); g_io_channel_ref (socket->iochannel); @@ -631,6 +606,8 @@ soup_socket_server_new (const gint port) SoupSocket* s; struct sockaddr_in* sa_in; socklen_t socklen; + const int on = 1; + gint flags; /* Create socket */ s = g_new0 (SoupSocket, 1); @@ -650,32 +627,21 @@ soup_socket_server_new (const gint port) sa_in->sin_addr.s_addr = g_htonl (INADDR_ANY); sa_in->sin_port = g_htons (port); - /* - * For Unix, set REUSEADDR and NONBLOCK. - * For Windows, set NONBLOCK during accept. - */ -#ifndef SOUP_WIN32 - { - const int on = 1; - gint flags; - - /* Set REUSEADDR so we can reuse the port */ - if (setsockopt (s->sockfd, - SOL_SOCKET, - SO_REUSEADDR, - &on, - sizeof (on)) != 0) - g_warning("Can't set reuse on tcp socket\n"); - - /* Get the flags (should all be 0?) */ - flags = fcntl (s->sockfd, F_GETFL, 0); - if (flags == -1) goto SETUP_ERROR; - - /* Make the socket non-blocking */ - if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1) - goto SETUP_ERROR; - } -#endif + /* Set REUSEADDR so we can reuse the port */ + if (setsockopt (s->sockfd, + SOL_SOCKET, + SO_REUSEADDR, + &on, + sizeof (on)) != 0) + g_warning("Can't set reuse on tcp socket\n"); + + /* Get the flags (should all be 0?) */ + flags = fcntl (s->sockfd, F_GETFL, 0); + if (flags == -1) goto SETUP_ERROR; + + /* Make the socket non-blocking */ + if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1) + goto SETUP_ERROR; /* Bind */ if (bind (s->sockfd, &s->addr->sa, sizeof (s->addr->sa)) != 0) @@ -691,7 +657,7 @@ soup_socket_server_new (const gint port) return s; SETUP_ERROR: - SOUP_CLOSE_SOCKET (s->sockfd); + close (s->sockfd); g_free (s->addr); g_free (s); return NULL; diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index a190ecfb..e9d942c5 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-socket.c: ronous Callback-based SOAP Request Queue. + * soup-socket.c: ronous Callback-based HTTP Request Queue. * * Authors: * David Helder (dhelder@umich.edu) diff --git a/libsoup/soup-socks.c b/libsoup/soup-socks.c index 623be186..22948590 100644 --- a/libsoup/soup-socks.c +++ b/libsoup/soup-socks.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) diff --git a/libsoup/soup-socks.h b/libsoup/soup-socks.h index a1d84616..e602cfa0 100644 --- a/libsoup/soup-socks.h +++ b/libsoup/soup-socks.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-socks.h: Asyncronous Callback-based SOAP Request Queue. + * soup-socks.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) diff --git a/libsoup/soup-ssl-proxy.c b/libsoup/soup-ssl-proxy.c index 5d94066a..e161acce 100644 --- a/libsoup/soup-ssl-proxy.c +++ b/libsoup/soup-ssl-proxy.c @@ -12,10 +12,7 @@ #include #endif -#ifdef HAVE_UNISTD_H #include -#endif - #include #include #include @@ -33,6 +30,8 @@ static gint ssl_library = 0; /* -1 = fail, 1 = openssl */ static SoupSecurityPolicy ssl_security_level = SOUP_SECURITY_DOMESTIC; +static gboolean server_mode = FALSE; + static GMainLoop *loop; static void @@ -58,7 +57,8 @@ soup_ssl_proxy_init (void) ssl_library = -1; #ifdef HAVE_OPENSSL_SSL_H - if (ssl_library == -1) ssl_library = soup_openssl_init () ? 1 : -1; + if (ssl_library == -1) + ssl_library = soup_openssl_init (server_mode) ? 1 : -1; #endif if (ssl_library == -1) return; @@ -115,7 +115,8 @@ soup_ssl_proxy_readwrite (GIOChannel *iochannel, write_total += bytes_written; } - if (condition & (G_IO_HUP | G_IO_ERR)) goto FINISH; + if (condition & G_IO_ERR) + goto FINISH; return TRUE; @@ -131,6 +132,11 @@ main (int argc, char** argv) GIOChannel *read_chan, *write_chan, *sock_chan; int sockfd, secpol, flags; + if (getenv ("SOUP_PROXY_DELAY")) { + g_warning ("Proxy delay set: sleeping for 20 seconds"); + sleep (20); + } + loop = g_main_new (FALSE); env = getenv ("SOCKFD"); @@ -148,6 +154,10 @@ main (int argc, char** argv) secpol = atoi (env); soup_ssl_proxy_set_security_policy (secpol); + env = getenv ("IS_SERVER"); + if (env) + server_mode = TRUE; + read_chan = g_io_channel_unix_new (STDIN_FILENO); if (!read_chan) g_error ("Unable to open STDIN"); @@ -156,13 +166,13 @@ main (int argc, char** argv) if (!write_chan) g_error ("Unable to open STDOUT"); - /* Block on socket write */ + /* We use select. All fds should block. */ flags = fcntl(sockfd, F_GETFL, 0); fcntl (sockfd, F_SETFL, flags & ~O_NONBLOCK); - - /* Don't block on STDIN read */ flags = fcntl(STDIN_FILENO, F_GETFL, 0); - fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); + fcntl (STDIN_FILENO, F_SETFL, flags & ~O_NONBLOCK); + flags = fcntl(STDOUT_FILENO, F_GETFL, 0); + fcntl (STDOUT_FILENO, F_SETFL, flags & ~O_NONBLOCK); sock_chan = g_io_channel_unix_new (sockfd); sock_chan = soup_ssl_proxy_get_iochannel (sock_chan); @@ -170,12 +180,12 @@ main (int argc, char** argv) g_error ("Unable to establish SSL connection"); g_io_add_watch (read_chan, - G_IO_IN | G_IO_HUP | G_IO_ERR, + G_IO_IN | G_IO_PRI | G_IO_ERR, (GIOFunc) soup_ssl_proxy_readwrite, sock_chan); g_io_add_watch (sock_chan, - G_IO_IN | G_IO_HUP | G_IO_ERR, + G_IO_IN | G_IO_PRI | G_IO_ERR, (GIOFunc) soup_ssl_proxy_readwrite, write_chan); diff --git a/libsoup/soup-ssl.c b/libsoup/soup-ssl.c index 05302cad..63adb338 100644 --- a/libsoup/soup-ssl.c +++ b/libsoup/soup-ssl.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@ximian.com) @@ -12,21 +12,12 @@ #include #endif -#ifdef HAVE_UNISTD_H #include -#endif - -#ifdef HAVE_SYS_WAIT_H +#include #include -#endif - -#ifdef HAVE_SYS_SOCKET_H #include -#endif - #include #include -#include #include #include @@ -34,23 +25,14 @@ #include "soup-nss.h" #include "soup-misc.h" -#ifdef SOUP_WIN32 - -GIOChannel * -soup_ssl_get_iochannel (GIOChannel *sock) -{ - return NULL; -} - -#else /* SOUP_WIN32 */ #ifdef HAVE_NSS GIOChannel * -soup_ssl_get_iochannel (GIOChannel *sock) +soup_ssl_get_iochannel_real (GIOChannel *sock, SoupSSLType type) { g_return_val_if_fail (sock != NULL, NULL); - return soup_nss_get_iochannel (sock); + return soup_nss_get_iochannel (sock, type); } #else /* HAVE_NSS */ @@ -63,13 +45,14 @@ soup_ssl_hup_waitpid (GIOChannel *source, GIOCondition condition, gpointer ppid) return FALSE; } -GIOChannel * -soup_ssl_get_iochannel (GIOChannel *sock) +static GIOChannel * +soup_ssl_get_iochannel_real (GIOChannel *sock, SoupSSLType type) { GIOChannel *new_chan; int sock_fd; int pid; int pair[2], flags; + const char *cert_file, *key_file; g_return_val_if_fail (sock != NULL, NULL); @@ -101,6 +84,31 @@ soup_ssl_get_iochannel (GIOChannel *sock) putenv (g_strdup_printf ("SECURITY_POLICY=%d", soup_get_security_policy ())); + if (type == SOUP_SSL_TYPE_SERVER) + putenv ("IS_SERVER=1"); + + if (soup_get_ssl_ca_file ()) { + putenv (g_strdup_printf ("HTTPS_CA_FILE=%s", + soup_get_ssl_ca_file ())); + } + + if (soup_get_ssl_ca_dir ()) { + putenv (g_strdup_printf ("HTTPS_CA_DIR=%s", + soup_get_ssl_ca_dir ())); + } + + soup_get_ssl_cert_files (&cert_file, &key_file); + + if (cert_file) { + putenv (g_strdup_printf ("HTTPS_CERT_FILE=%s", + cert_file)); + } + + if (key_file) { + putenv (g_strdup_printf ("HTTPS_KEY_FILE=%s", + key_file)); + } + execl (BINDIR G_DIR_SEPARATOR_S SSL_PROXY_NAME, BINDIR G_DIR_SEPARATOR_S SSL_PROXY_NAME, NULL); @@ -116,11 +124,9 @@ soup_ssl_get_iochannel (GIOChannel *sock) fcntl (pair [1], F_SETFL, flags | O_NONBLOCK); new_chan = g_io_channel_unix_new (pair [1]); - g_io_add_watch (new_chan, G_IO_HUP, + g_io_add_watch (new_chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL, soup_ssl_hup_waitpid, GINT_TO_POINTER (pid)); - /* FIXME: Why is this needed?? */ - g_io_channel_ref (new_chan); return new_chan; ERROR: @@ -132,4 +138,15 @@ soup_ssl_get_iochannel (GIOChannel *sock) } #endif /* HAVE_NSS */ -#endif /* SOUP_WIN32 */ + +GIOChannel * +soup_ssl_get_iochannel (GIOChannel *sock) +{ + return soup_ssl_get_iochannel_real (sock, SOUP_SSL_TYPE_CLIENT); +} + +GIOChannel * +soup_ssl_get_server_iochannel (GIOChannel *sock) +{ + return soup_ssl_get_iochannel_real (sock, SOUP_SSL_TYPE_SERVER); +} diff --git a/libsoup/soup-ssl.h b/libsoup/soup-ssl.h index 0cfd438b..9e398e48 100644 --- a/libsoup/soup-ssl.h +++ b/libsoup/soup-ssl.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -13,6 +13,12 @@ #include +typedef enum { + SOUP_SSL_TYPE_CLIENT = 0, + SOUP_SSL_TYPE_SERVER +} SoupSSLType; + GIOChannel *soup_ssl_get_iochannel (GIOChannel *sock); +GIOChannel *soup_ssl_get_server_iochannel (GIOChannel *sock); #endif /* SOUP_SSL_H */ diff --git a/libsoup/soup-transfer.c b/libsoup/soup-transfer.c index 332cd7c0..fdbc4562 100644 --- a/libsoup/soup-transfer.c +++ b/libsoup/soup-transfer.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -50,7 +50,7 @@ DUMP_WRITE (guchar *data, gint bytes_written) typedef struct { /* - * Length remaining to be downloaded of the current chunk data. + * Length of the current chunk data. */ guint len; @@ -219,34 +219,6 @@ remove_block_at_index (GByteArray *arr, gint offset, gint length) g_byte_array_set_size (arr, arr->len - length); } -/* - * Count number of hex digits, and convert to decimal. Store number of hex - * digits read in @width. - */ -static gint -decode_hex (const gchar *src, gint *width) -{ - gint new_len = 0, j; - - *width = 0; - - while (isxdigit (*src)) { - (*width)++; - src++; - } - src -= *width; - - for (j = *width - 1; j + 1; j--) { - if (isdigit (*src)) - new_len += (*src - 0x30) << (4*j); - else - new_len += (tolower (*src) - 0x57) << (4*j); - src++; - } - - return new_len; -} - static gboolean decode_chunk (SoupTransferChunkState *s, GByteArray *arr, @@ -259,73 +231,68 @@ decode_chunk (SoupTransferChunkState *s, while (TRUE) { gint new_len = 0; gint len = 0; - gchar *i = &arr->data [s->idx + s->len]; - - /* - * Not enough data to finish the chunk (and the smallest - * possible next chunk header), break - */ - if (s->idx + s->len + 5 > arr->len) - break; - /* - * Check for end of chunk header, otherwise break. Avoid - * trailing \r\n from previous chunk body if this is not the - * opening chunk. - */ if (s->len) { - if (soup_substring_index ( - i + 2, - arr->len - s->idx - s->len - 2, - "\r\n") <= 0) - break; - } else if (soup_substring_index (arr->data, - arr->len, - "\r\n") <= 0) + /* We're in the middle of a chunk. If we don't + * have the entire chunk and the trailing CRLF + * yet, read more. + */ + if (s->idx + s->len + 2 > arr->len) break; - /* - * Remove trailing \r\n after previous chunk body + /* + * Increment datalen and s->idx, and remove + * the trailing CRLF. + */ + s->idx += s->len; + *datalen += s->len; + remove_block_at_index (arr, s->idx, 2); + + /* + * Ready for the next chunk. + */ + s->len = 0; + } + + /* + * We're at the start of a new chunk. If we don't have + * the complete chunk header, wait for more. */ - if (s->len) - remove_block_at_index (arr, s->idx + s->len, 2); + len = soup_substring_index (&arr->data [s->idx], + arr->len - s->idx, + "\r\n"); + if (len < 0) + break; + len += 2; - new_len = decode_hex (i, &len); + new_len = strtol (&arr->data [s->idx], NULL, 16); g_assert (new_len >= 0); - /* - * Previous chunk is now processed, add its length to index and - * datalen. + /* + * If this is the final (zero-length) chunk, we need + * to have all of the trailing entity headers as well. */ - s->idx += s->len; - *datalen += s->len; + if (new_len == 0) { + len = soup_substring_index (&arr->data [s->idx], + arr->len - s->idx, + "\r\n\r\n"); + if (len < 0) + break; - /* - * Update length for next chunk's size - */ - s->len = new_len; - - /* - * FIXME: Add entity headers we find here to - * req->response_headers. - */ - len += soup_substring_index (&arr->data [s->idx + len], - arr->len - s->idx - len, - "\r\n"); + /* + * FIXME: Add entity headers we find here to + * req->response_headers. + */ - /* - * Zero-length chunk closes transfer. Include final \r\n after - * empty chunk. - */ - if (s->len == 0) { - len += 2; + len += 4; ret = TRUE; } /* - * Remove hexified length, entity headers, and trailing \r\n + * Remove chunk header and get ready for chunk data. */ - remove_block_at_index (arr, s->idx, len + 2); + remove_block_at_index (arr, s->idx, len); + s->len = new_len; } return ret; @@ -378,7 +345,8 @@ read_chunk (SoupReader *r, gboolean *cancelled) if (*cancelled) goto CANCELLED; /* - * If overwrite, remove datalen worth of data from start of buffer + * If overwrite, remove already-processed data from start + * of buffer */ if (r->overwrite_chunks) { remove_block_at_index (arr, 0, s->idx); diff --git a/libsoup/soup-transfer.h b/libsoup/soup-transfer.h index ba0d6af1..ab556b1d 100644 --- a/libsoup/soup-transfer.h +++ b/libsoup/soup-transfer.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup-queue.c: Asyncronous Callback-based SOAP Request Queue. + * soup-queue.c: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c index 970e2b4f..8d11f467 100644 --- a/libsoup/soup-uri.c +++ b/libsoup/soup-uri.c @@ -58,6 +58,7 @@ SoupKnownProtocols known_protocols [] = { { SOUP_PROTOCOL_SMTP, "mailto:", 25 }, { SOUP_PROTOCOL_SOCKS4, "socks4://", -1 }, { SOUP_PROTOCOL_SOCKS5, "socks5://", -1 }, + { SOUP_PROTOCOL_FILE, "file://", -1 }, { 0 } }; @@ -325,7 +326,10 @@ soup_uri_new (const gchar* uri_string) } /* Must have a protocol */ - if (!g_uri->protocol) return NULL; + if (!g_uri->protocol) { + g_free (g_uri); + return NULL; + } /* If there is an @ sign, look for user, authmech, and * password before it. diff --git a/libsoup/soup-uri.h b/libsoup/soup-uri.h index f7d297a4..c83952bf 100644 --- a/libsoup/soup-uri.h +++ b/libsoup/soup-uri.h @@ -34,7 +34,8 @@ typedef enum { SOUP_PROTOCOL_HTTPS, SOUP_PROTOCOL_SMTP, SOUP_PROTOCOL_SOCKS4, - SOUP_PROTOCOL_SOCKS5 + SOUP_PROTOCOL_SOCKS5, + SOUP_PROTOCOL_FILE } SoupProtocol; typedef struct { diff --git a/libsoup/soup.h b/libsoup/soup.h index bda95f1f..f5fc25e0 100644 --- a/libsoup/soup.h +++ b/libsoup/soup.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* - * soup.h: Asyncronous Callback-based SOAP Request Queue. + * soup.h: Asyncronous Callback-based HTTP Request Queue. * * Authors: * Alex Graveley (alex@helixcode.com) @@ -16,14 +16,8 @@ extern "C" { #endif #include -#include -#include #include #include -#include -#include -#include -#include #include #include -- cgit v1.2.1