From b2ae3979ad3c3634fe9e4f84951d67bae172f656 Mon Sep 17 00:00:00 2001 From: Søren Sandmann Date: Wed, 1 Aug 2007 04:16:58 -0400 Subject: Support https; deal with http servers closing immediately after accepting --- src/lac.h | 2 +- src/lachttp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------- src/lacuri.c | 34 ++++++++++++++++++++++++++++------ tests/lacwget.c | 6 +++--- tests/uri-test.c | 7 +++---- 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/lac.h b/src/lac.h index 407b548..dc4f84e 100644 --- a/src/lac.h +++ b/src/lac.h @@ -355,9 +355,9 @@ LacUri * lac_uri_new_from_string (const LacUri *base, const gchar *str); LacUri * lac_uri_copy (const LacUri *uri); gchar * lac_uri_string (const LacUri *uri); -void lac_uri_free (LacUri *uri); gboolean lac_uri_equal (const LacUri *uri1, const LacUri *uri2); +void lac_uri_free (LacUri *uri); /* * HTTP diff --git a/src/lachttp.c b/src/lachttp.c index 9e63556..343f4ad 100644 --- a/src/lachttp.c +++ b/src/lachttp.c @@ -73,7 +73,7 @@ struct _HttpHeader gchar *value; }; -#define junk_detected() g_print (G_STRLOC ": WARNING: junk detected after response") +#define junk_detected() g_print (G_STRLOC ": WARNING: junk detected after response\n") GQuark lac_http_error_quark (void) @@ -207,7 +207,8 @@ struct _HttpHost { GQueue * unsent; gboolean optimistic; /* whether newly created transports are pipelines */ - + gboolean use_tls; + /* handling broken servers */ gboolean broken_server; /* if TRUE, _never_ try pipelining */ gboolean recovering; /* if TRUE, don't create new connections. */ @@ -217,7 +218,8 @@ struct _HttpHost { }; static HttpHost *http_host_new (const LacAddress *addr, - gint port); + gint port, + gboolean use_tls); static void http_host_add_request (HttpHost *host, LacHttpRequest *request); static void http_host_cancel_request (HttpHost *host, @@ -1568,7 +1570,7 @@ address_callback (const LacAddress *new_addr, HttpHost *http_host; http_host = http_host_new ( - new_addr, request->uri->u.http.port); + new_addr, request->uri->u.http.port, request->uri->u.http.is_https); request_emit_host_found (request, request->uri->u.http.host, new_addr); @@ -1676,7 +1678,9 @@ host_dump_spam (HttpHost *host) #endif static HttpHost * -http_host_new (const LacAddress *addr, gint port) +http_host_new (const LacAddress *addr, + gint port, + gboolean use_tls) { HttpHost *host; GList *list; @@ -1684,8 +1688,12 @@ http_host_new (const LacAddress *addr, gint port) for (list = all_hosts; list != NULL; list = list->next) { host = list->data; - if (lac_address_equal (host->address, addr) && host->port == port) + if (lac_address_equal (host->address, addr) && + host->port == port && + host->use_tls == use_tls) + { return host; + } } host = g_new0 (HttpHost, 1); @@ -1697,6 +1705,7 @@ http_host_new (const LacAddress *addr, gint port) host->unsent = g_queue_new (); host->recovering = FALSE; host->timeout_id = 0; + host->use_tls = use_tls; if (USE_PIPELINING) { @@ -2395,6 +2404,25 @@ http_transport_handle_close (HttpTransport *transport) lac_http_request_unref (transport->current); transport->current = NULL; } + else if (transport->successful_requests == 0) + { + /* If there is no current request, and we haven't succesfully + * processed any requests at all, then that means the server + * closed the connection before we even sent it anything. + * + * In that case, we should not return outstanding requests, + * as we would just spin forever. Instead we just fail + * all of them. Further conversation with this server is not + * going to be productive. + */ + GError *err = g_error_new ( + LAC_HTTP_ERROR, LAC_HTTP_ERROR_PREMATURE_CLOSE, + "Server closed connection before sending a complete response"); + + http_transport_all_requests_failed (transport, err); + + g_error_free (err); + } if (transport->pipelining && !g_queue_is_empty (transport->in_progress)) { @@ -2404,7 +2432,8 @@ http_transport_handle_close (HttpTransport *transport) * connection. * * This is known to happen with Netscape/Enterprise 3.6 SP. - * We should perhaps special case that particular server + * We should perhaps special case that particular server. + * news.google.com also does this. */ g_print ("server indicated it supported pipelining, but it didn't\n"); @@ -2559,8 +2588,17 @@ http_transport_new (HttpHost *host, #endif transport->host = host; - transport->connection = lac_connection_new_tcp ( - host->address, host->port, connection_callback, transport); + + if (host->use_tls) + { + transport->connection = lac_connection_new_tls ( + host->address, host->port, connection_callback, transport); + } + else + { + transport->connection = lac_connection_new_tcp ( + host->address, host->port, connection_callback, transport); + } transport->unsent = g_queue_new (); transport->in_progress = g_queue_new (); diff --git a/src/lacuri.c b/src/lacuri.c index 7107815..ad01147 100644 --- a/src/lacuri.c +++ b/src/lacuri.c @@ -331,6 +331,7 @@ lac_uri_path_to_ftp_type (const gchar *path, LacFtpType *type) } enum { + LAC_HTTPS_DEFAULT_PORT = 443, LAC_HTTP_DEFAULT_PORT = 80, LAC_FTP_DEFAULT_PORT = 21 }; @@ -350,7 +351,12 @@ lac_uri_unknown_to_http (LacUri *uri, lac_uri_authority_to_port_and_host (uri->u.unknown.authority, &host, &port); if (port == -1) - port = LAC_HTTP_DEFAULT_PORT; + { + if (is_https) + port = LAC_HTTPS_DEFAULT_PORT; + else + port = LAC_HTTP_DEFAULT_PORT; + } g_free (uri->u.unknown.authority); if (uri->u.unknown.path == NULL) @@ -895,7 +901,7 @@ lac_uri_copy (const LacUri *uri) copy->u.http.port = uri->u.http.port; copy->u.http.path = g_strdup (uri->u.http.path); copy->u.http.query = g_strdup (uri->u.http.query); - copy->u.http.is_https = uri->u.http.port; + copy->u.http.is_https = uri->u.http.is_https; break; case LAC_SCHEME_FTP: copy->u.ftp.host = g_strdup (uri->u.ftp.host); @@ -931,22 +937,38 @@ lac_uri_string (const LacUri *uri) { gchar *port_str; gchar *query_str; + gchar *scheme_str; + + if (uri->u.http.is_https) + { + if (uri->u.http.port != LAC_HTTPS_DEFAULT_PORT) + port_str = g_strdup_printf (":%d", uri->u.http.port); + else + port_str = g_strdup (""); - if (uri->u.http.port != LAC_HTTP_DEFAULT_PORT) - port_str = g_strdup_printf (":%d", uri->u.http.port); + scheme_str = g_strdup ("https://"); + } else - port_str = g_strdup (""); + { + if (uri->u.http.port != LAC_HTTP_DEFAULT_PORT) + port_str = g_strdup_printf (":%d", uri->u.http.port); + else + port_str = g_strdup (""); + + scheme_str = g_strdup ("http://"); + } if (uri->u.http.query) query_str = g_strdup_printf ("?%s", uri->u.http.query); else query_str = g_strdup (""); - str = g_strconcat (uri->u.http.is_https? "https://" : "http://", + str = g_strconcat (scheme_str, uri->u.http.host, port_str, uri->u.http.path, query_str, NULL); + g_free (scheme_str); g_free (port_str); g_free (query_str); break; diff --git a/tests/lacwget.c b/tests/lacwget.c index c7a182d..f992613 100644 --- a/tests/lacwget.c +++ b/tests/lacwget.c @@ -622,10 +622,10 @@ do_download (LacUri *base_uri, const gchar *uri_str, gboolean try_parse) if (already_downloaded (uri)) return FALSE; -#if 0 - printf ("download: %s\n", uri_str); -#endif + printf ("generated uri: %s\n", lac_uri_string (uri)); + printf ("download: %s\n", uri_str); + request = lac_http_request_new_get ( uri, http_callback, page_info); diff --git a/tests/uri-test.c b/tests/uri-test.c index c040098..839aeab 100644 --- a/tests/uri-test.c +++ b/tests/uri-test.c @@ -41,11 +41,10 @@ print_uri (LacUri *uri, gchar *base_uri_str, gchar *uri_str) g_print (" fragment: %s\n", uri->fragment); break; case LAC_SCHEME_HTTP: - case LAC_SCHEME_HTTPS: - if (uri->scheme == LAC_SCHEME_HTTP) - g_print ("HTTP\n"); - else + if (uri->u.http.is_https) g_print ("HTTPS\n"); + else + g_print ("HTTP\n"); g_print (" host: %s\n", uri->u.http.host); g_print (" port: %d\n", uri->u.http.port); g_print (" path: %s\n", uri->u.http.path); -- cgit v1.2.3