summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
diff options
context:
space:
mode:
authorderaadt <deraadt@openbsd.org>2014-07-23 19:13:23 +0000
committerderaadt <deraadt@openbsd.org>2014-07-23 19:13:23 +0000
commitb19b5cc7cf960498d196b6f133d2a51271a8e79e (patch)
treeb5108354da4bc0dea7c6028d0639170cfa1a4d6d /gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
parentAdd canonicalize_path() to canonicalize the requested URL path. (diff)
downloadwireguard-openbsd-b19b5cc7cf960498d196b6f133d2a51271a8e79e.tar.xz
wireguard-openbsd-b19b5cc7cf960498d196b6f133d2a51271a8e79e.zip
delinked from tree, now it goes to the bit bucket
Diffstat (limited to 'gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c')
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c2532
1 files changed, 0 insertions, 2532 deletions
diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
deleted file mode 100644
index 1527e5c2184..00000000000
--- a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
+++ /dev/null
@@ -1,2532 +0,0 @@
-/*
- * $LynxId: HTTP.c,v 1.135 2014/01/11 16:52:29 tom Exp $
- *
- * HyperText Tranfer Protocol - Client implementation HTTP.c
- * ==========================
- * Modified:
- * 27 Jan 1994 PDM Added Ari Luotonen's Fix for Reload when using proxy
- * servers.
- * 28 Apr 1997 AJL,FM Do Proxy Authorisation.
- */
-
-#include <HTUtils.h>
-#include <HTTP.h>
-#include <LYUtils.h>
-
-#ifdef USE_SSL
-#include <HTNews.h>
-#endif
-
-#define HTTP_VERSION "HTTP/1.0"
-
-#define HTTP_PORT 80
-#define HTTPS_PORT 443
-#define SNEWS_PORT 563
-
-#define INIT_LINE_SIZE 1536 /* Start with line buffer this big */
-#define LINE_EXTEND_THRESH 256 /* Minimum read size */
-#define VERSION_LENGTH 20 /* for returned protocol version */
-
-#include <HTParse.h>
-#include <HTTCP.h>
-#include <HTFormat.h>
-#include <HTFile.h>
-#include <HTAlert.h>
-#include <HTMIME.h>
-#include <HTML.h>
-#include <HTInit.h>
-#include <HTAABrow.h>
-#include <HTAccess.h> /* Are we using an HTTP gateway? */
-
-#include <LYCookie.h>
-#include <LYGlobalDefs.h>
-#include <GridText.h>
-#include <LYStrings.h>
-#include <LYUtils.h>
-#include <LYrcFile.h>
-#include <LYLeaks.h>
-
-#ifdef USE_SSL
-#ifdef USE_OPENSSL_INCL
-#include <openssl/x509v3.h>
-#endif
-#ifdef USE_GNUTLS_INCL
-#include <gnutls/x509.h>
-#endif
-#endif
-
-BOOLEAN reloading = FALSE; /* Reloading => send no-cache pragma to proxy */
-char *redirecting_url = NULL; /* Location: value. */
-BOOL permanent_redirection = FALSE; /* Got 301 status? */
-BOOL redirect_post_content = FALSE; /* Don't convert to GET? */
-
-#ifdef USE_SSL
-SSL_CTX *ssl_ctx = NULL; /* SSL ctx */
-SSL *SSL_handle = NULL;
-static int ssl_okay;
-
-static void free_ssl_ctx(void)
-{
- if (ssl_ctx != NULL)
- SSL_CTX_free(ssl_ctx);
-}
-
-static int HTSSLCallback(int preverify_ok, X509_STORE_CTX * x509_ctx GCC_UNUSED)
-{
- char *msg = NULL;
- int result = 1;
-
-#ifdef USE_X509_SUPPORT
- HTSprintf0(&msg,
- gettext("SSL callback:%s, preverify_ok=%d, ssl_okay=%d"),
- X509_verify_cert_error_string((long) X509_STORE_CTX_get_error(x509_ctx)),
- preverify_ok, ssl_okay);
- _HTProgress(msg);
- FREE(msg);
-#endif
-
-#ifndef USE_NSS_COMPAT_INCL
- if (!(preverify_ok || ssl_okay || ssl_noprompt)) {
-#ifdef USE_X509_SUPPORT
- HTSprintf0(&msg, SSL_FORCED_PROMPT,
- X509_verify_cert_error_string((long)
- X509_STORE_CTX_get_error(x509_ctx)));
- if (HTForcedPrompt(ssl_noprompt, msg, YES))
- ssl_okay = 1;
- else
- result = 0;
-#endif
-
- FREE(msg);
- }
-#endif
- return result;
-}
-
-SSL *HTGetSSLHandle(void)
-{
-#ifdef USE_GNUTLS_INCL
- static char *certfile = NULL;
-#endif
-
- if (ssl_ctx == NULL) {
- /*
- * First time only.
- */
-#if SSLEAY_VERSION_NUMBER < 0x0800
- ssl_ctx = SSL_CTX_new();
- X509_set_default_verify_paths(ssl_ctx->cert);
-#else
- SSLeay_add_ssl_algorithms();
- ssl_ctx = SSL_CTX_new(SSLv23_client_method());
- SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
-#ifdef SSL_OP_NO_COMPRESSION
- SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_COMPRESSION);
-#endif
-#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
-#endif
- SSL_CTX_set_default_verify_paths(ssl_ctx);
- SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, HTSSLCallback);
-#endif /* SSLEAY_VERSION_NUMBER < 0x0800 */
-#if defined(USE_PROGRAM_DIR) & !defined(USE_GNUTLS_INCL)
- {
- X509_LOOKUP *lookup;
-
- lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
- X509_LOOKUP_file());
- if (lookup != NULL) {
- char *certfile = NULL;
-
- HTSprintf0(&certfile, "%s\\cert.pem", program_dir);
- X509_LOOKUP_load_file(lookup, certfile, X509_FILETYPE_PEM);
- FREE(certfile);
- }
- }
-#endif
-#ifdef USE_GNUTLS_INCL
- if ((certfile = LYGetEnv("SSL_CERT_FILE")) != NULL) {
- CTRACE((tfp,
- "HTGetSSLHandle: certfile is set to %s by SSL_CERT_FILE\n",
- certfile));
- } else {
- if (non_empty(SSL_cert_file)) {
- certfile = SSL_cert_file;
- CTRACE((tfp,
- "HTGetSSLHandle: certfile is set to %s by config SSL_CERT_FILE\n",
- certfile));
- }
-#if defined(USE_PROGRAM_DIR)
- else {
- HTSprintf0(&(certfile), "%s\\cert.pem", program_dir);
- CTRACE((tfp,
- "HTGetSSLHandle: certfile is set to %s by installed directory\n", certfile));
- }
-#endif
- }
-#endif
- atexit(free_ssl_ctx);
- }
-#ifdef USE_GNUTLS_INCL
- ssl_ctx->certfile = certfile;
- ssl_ctx->certfile_type = GNUTLS_X509_FMT_PEM;
-#endif
- ssl_okay = 0;
- return (SSL_new(ssl_ctx));
-}
-
-void HTSSLInitPRNG(void)
-{
-#if SSLEAY_VERSION_NUMBER >= 0x00905100
- if (RAND_status() == 0) {
- char rand_file[256];
- time_t t;
- long l, seed;
-
-#ifndef _WINDOWS
- pid_t pid;
-
-#else
- DWORD pid;
-#endif
-
- t = time(NULL);
-
-#ifndef _WINDOWS
- pid = getpid();
-#else
- pid = GetCurrentThreadId();
-#endif
-
- RAND_file_name(rand_file, 256L);
- CTRACE((tfp, "HTTP: Seeding PRNG\n"));
- /* Seed as much as 1024 bytes from RAND_file_name */
- RAND_load_file(rand_file, 1024L);
- /* Seed in time (mod_ssl does this) */
- RAND_seed((unsigned char *) &t, (int) sizeof(time_t));
-
- /* Seed in pid (mod_ssl does this) */
- RAND_seed((unsigned char *) &pid, (int) sizeof(pid));
- /* Initialize system's random number generator */
- RAND_bytes((unsigned char *) &seed, (int) sizeof(long));
-
- lynx_srand((unsigned) seed);
- while (RAND_status() == 0) {
- /* Repeatedly seed the PRNG using the system's random number generator until it has been seeded with enough data */
- l = lynx_rand();
- RAND_seed((unsigned char *) &l, (int) sizeof(long));
- }
- /* Write a rand_file */
- RAND_write_file(rand_file);
- }
-#endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
- return;
-}
-
-#define HTTP_NETREAD(sock, buff, size, handle) \
- (handle \
- ? SSL_read(handle, buff, size) \
- : NETREAD(sock, buff, size))
-
-#define HTTP_NETWRITE(sock, buff, size, handle) \
- (handle \
- ? SSL_write(handle, buff, size) \
- : NETWRITE(sock, buff, size))
-
-#define HTTP_NETCLOSE(sock, handle) \
- { (void)NETCLOSE(sock); \
- if (handle) \
- SSL_free(handle); \
- SSL_handle = handle = NULL; \
- }
-
-#else
-#define HTTP_NETREAD(a, b, c, d) NETREAD(a, b, c)
-#define HTTP_NETWRITE(a, b, c, d) NETWRITE(a, b, c)
-#define HTTP_NETCLOSE(a, b) (void)NETCLOSE(a)
-#endif /* USE_SSL */
-
-#ifdef _WINDOWS /* 1997/11/06 (Thu) 13:00:08 */
-
-#define BOX_TITLE "Lynx " __FILE__
-#define BOX_FLAG (MB_ICONINFORMATION | MB_SETFOREGROUND)
-
-typedef struct {
- int fd;
- char *buf;
- int len;
-} recv_data_t;
-
-int ws_read_per_sec = 0;
-static int ws_errno = 0;
-
-static DWORD g_total_times = 0;
-static DWORD g_total_bytes = 0;
-
-/* The same like read, but takes care of EINTR and uses select to
- timeout the stale connections. */
-
-static int ws_read(int fd, char *buf, int len)
-{
- int res;
- int retry = 3;
-
- do {
- res = recv(fd, buf, len, 0);
- if (WSAEWOULDBLOCK == WSAGetLastError()) {
- Sleep(100);
- if (retry-- > 0)
- continue;
- }
- } while (res == SOCKET_ERROR && SOCKET_ERRNO == EINTR);
-
- return res;
-}
-
-#define DWORD_ERR ((DWORD)-1)
-
-static DWORD __stdcall _thread_func(void *p)
-{
- DWORD result;
- int i, val;
- recv_data_t *q = (recv_data_t *) p;
-
- i = 0;
- i++;
- val = ws_read(q->fd, q->buf, q->len);
-
- if (val == SOCKET_ERROR) {
- ws_errno = WSAGetLastError();
-#if 0
- char buff[256];
-
- sprintf(buff, "Thread read: %d, error (%ld), fd = %d, len = %d",
- i, ws_errno, q->fd, q->len);
- MessageBox(NULL, buff, BOX_TITLE, BOX_FLAG);
-#endif
- result = DWORD_ERR;
- } else {
- result = val;
- }
-
- return result;
-}
-
-/* The same like read, but takes care of EINTR and uses select to
- timeout the stale connections. */
-
-int ws_netread(int fd, char *buf, int len)
-{
- int i;
- char buff[256];
-
- /* 1998/03/30 (Mon) 09:01:21 */
- HANDLE hThread;
- DWORD dwThreadID;
- DWORD exitcode = 0;
- DWORD ret_val = DWORD_ERR;
- DWORD val, process_time, now_TickCount, save_TickCount;
-
- static recv_data_t para;
-
-#define TICK 5
-#define STACK_SIZE 0x2000uL
-
- InitializeCriticalSection(&critSec_READ);
-
- para.fd = fd;
- para.buf = buf;
- para.len = len;
-
- ws_read_per_sec = 0;
- save_TickCount = GetTickCount();
-
- hThread = CreateThread(NULL, STACK_SIZE,
- _thread_func,
- (void *) &para, 0UL, &dwThreadID);
-
- if (hThread == 0) {
- HTInfoMsg("CreateThread Failed (read)");
- goto read_exit;
- }
-
- i = 0;
- while (1) {
- val = WaitForSingleObject(hThread, 1000 / TICK);
- i++;
- if (val == WAIT_FAILED) {
- HTInfoMsg("Wait Failed");
- ret_val = DWORD_ERR;
- break;
- } else if (val == WAIT_TIMEOUT) {
- i++;
- if (i / TICK > (AlertSecs + 2)) {
- sprintf(buff, "Read Waiting (%2d.%01d) for %d Bytes",
- i / TICK, (i % TICK) * 10 / TICK, len);
- SetConsoleTitle(buff);
- }
- if (win32_check_interrupt() || ((i / TICK) > lynx_timeout)) {
- if (CloseHandle(hThread) == FALSE) {
- HTInfoMsg("Thread terminate Failed");
- }
- WSASetLastError(ETIMEDOUT);
- ret_val = HT_INTERRUPTED;
- break;
- }
- } else if (val == WAIT_OBJECT_0) {
- if (GetExitCodeThread(hThread, &exitcode) == FALSE) {
- exitcode = DWORD_ERR;
- }
- if (CloseHandle(hThread) == FALSE) {
- HTInfoMsg("Thread terminate Failed");
- }
- now_TickCount = GetTickCount();
- if (now_TickCount >= save_TickCount)
- process_time = now_TickCount - save_TickCount;
- else
- process_time = now_TickCount + (0xffffffff - save_TickCount);
-
- if (process_time == 0)
- process_time = 1;
- g_total_times += process_time;
-
- /*
- * DWORD is unsigned, and could be an error code which is signed.
- */
- if ((long) exitcode > 0)
- g_total_bytes += exitcode;
-
- ws_read_per_sec = g_total_bytes;
- if (ws_read_per_sec > 2000000) {
- if (g_total_times > 1000)
- ws_read_per_sec /= (g_total_times / 1000);
- } else {
- ws_read_per_sec *= 1000;
- ws_read_per_sec /= g_total_times;
- }
-
- ret_val = exitcode;
- break;
- }
- } /* end while(1) */
-
- read_exit:
- LeaveCriticalSection(&critSec_READ);
- return ret_val;
-}
-#endif /* _WINDOWS */
-
-/*
- * Strip any username from the given string so we retain only the host.
- */
-static void strip_userid(char *host)
-{
- char *p1 = host;
- char *p2 = StrChr(host, '@');
- char *fake;
-
- if (p2 != 0) {
- *p2++ = '\0';
- if ((fake = HTParse(host, "", PARSE_HOST)) != NULL) {
- char *msg = NULL;
-
- CTRACE((tfp, "parsed:%s\n", fake));
- HTSprintf0(&msg, gettext("Address contains a username: %s"), host);
- HTAlert(msg);
- FREE(msg);
- }
- while ((*p1++ = *p2++) != '\0') {
- ;
- }
- }
-}
-
-/*
- * Check if the user's options specified to use the given encoding. Normally
- * all encodings with compiled-in support are specified (encodingALL).
- */
-static BOOL acceptEncoding(int code)
-{
- BOOL result = FALSE;
-
- if ((code & LYAcceptEncoding) != 0) {
- const char *program = 0;
-
- switch (code) {
- case encodingGZIP:
- program = HTGetProgramPath(ppGZIP);
- break;
- case encodingDEFLATE:
- program = HTGetProgramPath(ppINFLATE);
- break;
- case encodingCOMPRESS:
- program = HTGetProgramPath(ppCOMPRESS);
- break;
- case encodingBZIP2:
- program = HTGetProgramPath(ppBZIP2);
- break;
- default:
- break;
- }
- /*
- * FIXME: if lynx did not rely upon external programs to decompress
- * files for external viewers, this check could be relaxed.
- */
- result = (BOOL) (program != 0);
- }
- return result;
-}
-
-#ifdef USE_SSL
-static void show_cert_issuer(X509 * peer_cert GCC_UNUSED)
-{
-#if defined(USE_OPENSSL_INCL) || defined(USE_GNUTLS_FUNCS)
- char ssl_dn[1024];
- char *msg = NULL;
-
- X509_NAME_oneline(X509_get_issuer_name(peer_cert), ssl_dn, (int) sizeof(ssl_dn));
- HTSprintf0(&msg, gettext("Certificate issued by: %s"), ssl_dn);
- _HTProgress(msg);
- FREE(msg);
-#elif defined(USE_GNUTLS_INCL)
- /* the OpenSSL "compat" code compiles but dumps core with GNU TLS */
-#endif
-}
-#endif
-
-/*
- * Remove IPv6 brackets (and any port-number) from the given host-string.
- */
-#ifdef USE_SSL
-static char *StripIpv6Brackets(char *host)
-{
- int port_number;
- char *p;
-
- if ((p = HTParsePort(host, &port_number)) != 0)
- *p = '\0';
-
- if (*host == '[') {
- p = host + strlen(host) - 1;
- if (*p == ']') {
- *p = '\0';
- ++host;
- }
- }
- return host;
-}
-#endif
-
-/* Load Document from HTTP Server HTLoadHTTP()
- * ==============================
- *
- * Given a hypertext address, this routine loads a document.
- *
- *
- * On entry,
- * arg is the hypertext reference of the article to be loaded.
- *
- * On exit,
- * returns >=0 If no error, a good socket number
- * <0 Error.
- *
- * The socket must be closed by the caller after the document has been
- * read.
- *
- */
-static int HTLoadHTTP(const char *arg,
- HTParentAnchor *anAnchor,
- HTFormat format_out,
- HTStream *sink)
-{
- static char empty[1];
- int s; /* Socket number for returned data */
- const char *url = arg; /* The URL which get_physical() returned */
- bstring *command = NULL; /* The whole command */
- char *eol; /* End of line if found */
- char *start_of_data; /* Start of body of reply */
- int status; /* tcp return */
- off_t bytes_already_read;
- char crlf[3]; /* A CR LF equivalent string */
- HTStream *target; /* Unconverted data */
- HTFormat format_in; /* Format arriving in the message */
- BOOL do_head = FALSE; /* Whether or not we should do a head */
- BOOL do_post = FALSE; /* ARE WE posting ? */
- const char *METHOD;
-
- char *line_buffer = NULL;
- char *line_kept_clean = NULL;
-
-#ifdef SH_EX /* FIX BUG by kaz@maczuka.hitachi.ibaraki.jp */
- int real_length_of_line = 0;
-#endif
- BOOL extensions; /* Assume good HTTP server */
- char *linebuf = NULL;
- char temp[80];
- BOOL first_Accept = TRUE;
- BOOL show_401 = FALSE;
- BOOL show_407 = FALSE;
- BOOL auth_proxy = NO; /* Generate a proxy authorization. - AJL */
-
- int length, rawlength, rv;
- int server_status = 0;
- BOOL doing_redirect, already_retrying = FALSE;
- int len = 0;
-
-#ifdef USE_SSL
- unsigned long SSLerror;
- BOOL do_connect = FALSE; /* ARE WE going to use a proxy tunnel ? */
- BOOL did_connect = FALSE; /* ARE WE actually using a proxy tunnel ? */
- const char *connect_url = NULL; /* The URL being proxied */
- char *connect_host = NULL; /* The host being proxied */
- SSL *handle = NULL; /* The SSL handle */
- X509 *peer_cert; /* The peer certificate */
- char ssl_dn[1024];
- char *cert_host;
- char *ssl_host;
- char *p;
- char *msg = NULL;
- int status_sslcertcheck;
- char *ssl_dn_start;
- char *ssl_all_cns = NULL;
-
-#ifdef USE_GNUTLS_INCL
- int ret;
- unsigned tls_status;
-#endif
-
-#if SSLEAY_VERSION_NUMBER >= 0x0900
- BOOL try_tls = TRUE;
-#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
- SSL_handle = NULL;
-#else
- void *handle = NULL;
-#endif /* USE_SSL */
-
- if (anAnchor->isHEAD)
- do_head = TRUE;
- else if (anAnchor->post_data)
- do_post = TRUE;
-
- if (!url) {
- status = -3;
- _HTProgress(BAD_REQUEST);
- goto done;
- }
- if (!*url) {
- status = -2;
- _HTProgress(BAD_REQUEST);
- goto done;
- }
-#ifdef USE_SSL
- if (using_proxy && !StrNCmp(url, "http://", 7)) {
- int portnumber;
-
- if ((connect_url = strstr((url + 7), "https://"))) {
- do_connect = TRUE;
- connect_host = HTParse(connect_url, "https", PARSE_HOST);
- if (!HTParsePort(connect_host, &portnumber)) {
- sprintf(temp, ":%d", HTTPS_PORT);
- StrAllocCat(connect_host, temp);
- }
- CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
- CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
- } else if ((connect_url = strstr((url + 7), "snews://"))) {
- do_connect = TRUE;
- connect_host = HTParse(connect_url, "snews", PARSE_HOST);
- if (!HTParsePort(connect_host, &portnumber)) {
- sprintf(temp, ":%d", SNEWS_PORT);
- StrAllocCat(connect_host, temp);
- }
- CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
- CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
- }
- }
-#endif /* USE_SSL */
-
- sprintf(crlf, "%c%c", CR, LF);
-
- /*
- * At this point, we're talking HTTP/1.0.
- */
- extensions = YES;
-
- try_again:
- /*
- * All initializations are moved down here from up above, so we can start
- * over here...
- */
- eol = 0;
- length = 0;
- doing_redirect = FALSE;
- permanent_redirection = FALSE;
- redirect_post_content = FALSE;
- target = NULL;
- line_buffer = NULL;
- line_kept_clean = NULL;
-
-#ifdef USE_SSL
- if (!StrNCmp(url, "https", 5))
- status = HTDoConnect(url, "HTTPS", HTTPS_PORT, &s);
- else
- status = HTDoConnect(url, "HTTP", HTTP_PORT, &s);
-#else
- if (!StrNCmp(url, "https", 5)) {
- HTAlert(gettext("This client does not contain support for HTTPS URLs."));
- status = HT_NOT_LOADED;
- goto done;
- }
- status = HTDoConnect(arg, "HTTP", HTTP_PORT, &s);
-#endif /* USE_SSL */
- if (status == HT_INTERRUPTED) {
- /*
- * Interrupt cleanly.
- */
- CTRACE((tfp, "HTTP: Interrupted on connect; recovering cleanly.\n"));
- _HTProgress(CONNECTION_INTERRUPTED);
- status = HT_NOT_LOADED;
- goto done;
- }
- if (status < 0) {
-#ifdef _WINDOWS
- CTRACE((tfp, "HTTP: Unable to connect to remote host for `%s'\n"
- " (status = %d, sock_errno = %d).\n",
- url, status, SOCKET_ERRNO));
-#else
- CTRACE((tfp,
- "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n",
- url, SOCKET_ERRNO));
-#endif
- HTAlert(gettext("Unable to connect to remote host."));
- status = HT_NOT_LOADED;
- goto done;
- }
-#ifdef USE_SSL
- use_tunnel:
- /*
- * If this is an https document, then do the SSL stuff here.
- */
- if (did_connect || !StrNCmp(url, "https", 5)) {
- SSL_handle = handle = HTGetSSLHandle();
- SSL_set_fd(handle, s);
- /* get host we're connecting to */
- ssl_host = HTParse(url, "", PARSE_HOST);
- ssl_host = StripIpv6Brackets(ssl_host);
-#if defined(USE_GNUTLS_FUNCS)
- ret = gnutls_server_name_set(handle->gnutls_state,
- GNUTLS_NAME_DNS,
- ssl_host, strlen(ssl_host));
- CTRACE((tfp, "...called gnutls_server_name_set(%s) ->%d\n", ssl_host, ret));
-#elif SSLEAY_VERSION_NUMBER >= 0x0900
-#ifndef USE_NSS_COMPAT_INCL
- if (!try_tls) {
- handle->options |= SSL_OP_NO_TLSv1;
-#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
- } else {
- int ret = (int) SSL_set_tlsext_host_name(handle, ssl_host);
-
- CTRACE((tfp, "...called SSL_set_tlsext_host_name(%s) ->%d\n",
- ssl_host, ret));
-#endif
- }
-#endif
-#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
- HTSSLInitPRNG();
- status = SSL_connect(handle);
-
- if (status <= 0) {
-#if SSLEAY_VERSION_NUMBER >= 0x0900
- if (try_tls) {
- _HTProgress(gettext("Retrying connection without TLS."));
- try_tls = FALSE;
- if (did_connect)
- HTTP_NETCLOSE(s, handle);
- goto try_again;
- } else {
- CTRACE((tfp,
- "HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
- url, status));
- SSL_load_error_strings();
- while ((SSLerror = ERR_get_error()) != 0) {
- CTRACE((tfp, "HTTP: SSL: %s\n", ERR_error_string(SSLerror, NULL)));
- }
- HTAlert("Unable to make secure connection to remote host.");
- if (did_connect)
- HTTP_NETCLOSE(s, handle);
- status = HT_NOT_LOADED;
- goto done;
- }
-#else
- unsigned long SSLerror;
-
- CTRACE((tfp,
- "HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
- url, status));
- SSL_load_error_strings();
- while ((SSLerror = ERR_get_error()) != 0) {
- CTRACE((tfp, "HTTP: SSL: %s\n", ERR_error_string(SSLerror, NULL)));
- }
- HTAlert("Unable to make secure connection to remote host.");
- if (did_connect)
- HTTP_NETCLOSE(s, handle);
- status = HT_NOT_LOADED;
- goto done;
-#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
- }
-#ifdef USE_GNUTLS_INCL
- gnutls_certificate_set_verify_flags(handle->gnutls_cred,
- GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
- GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
- ret = gnutls_certificate_verify_peers2(handle->gnutls_state, &tls_status);
- if (ret < 0 || (ret == 0 &&
- tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND)) {
- int flag_continue = 1;
- char *msg2;
-
- if (ret == 0 && tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
- msg2 = gettext("the certificate has no known issuer");
- } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
- msg2 = gettext("no issuer was found");
- } else if (tls_status & GNUTLS_CERT_SIGNER_NOT_CA) {
- msg2 = gettext("issuer is not a CA");
- } else if (tls_status & GNUTLS_CERT_REVOKED) {
- msg2 = gettext("the certificate has been revoked");
- } else {
- msg2 = gettext("the certificate is not trusted");
- }
- HTSprintf0(&msg, SSL_FORCED_PROMPT, msg2);
- CTRACE((tfp, "HTLoadHTTP: %s\n", msg));
- if (!ssl_noprompt) {
- if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
- flag_continue = 0;
- }
- } else if (ssl_noprompt == FORCE_PROMPT_NO) {
- flag_continue = 0;
- }
- FREE(msg);
- if (flag_continue == 0) {
- status = HT_NOT_LOADED;
- FREE(msg);
- goto done;
- }
- }
-#endif
-
- peer_cert = SSL_get_peer_certificate(handle);
-#if defined(USE_OPENSSL_INCL) || defined(USE_GNUTLS_FUNCS)
- X509_NAME_oneline(X509_get_subject_name(peer_cert),
- ssl_dn, (int) sizeof(ssl_dn));
-#elif defined(USE_GNUTLS_INCL)
- X509_NAME_oneline(X509_get_subject_name(peer_cert),
- ssl_dn + 1, (int) sizeof(ssl_dn) - 1);
-
- /* Iterate over DN in incompatible GnuTLS format to bring it into OpenSSL format */
- ssl_dn[0] = '/';
- ssl_dn_start = ssl_dn;
- while (*ssl_dn_start) {
- if ((*ssl_dn_start == ',') && (*(ssl_dn_start + 1) == ' ')) {
- *ssl_dn_start++ = '/';
- if (*(p = ssl_dn_start) != 0) {
- while ((p[0] = p[1]) != 0)
- ++p;
- }
- } else {
- ssl_dn_start++;
- }
- }
-#endif
-
- /*
- * X.509 DN validation taking ALL CN fields into account
- * (c) 2006 Thorsten Glaser <tg@mirbsd.de>
- */
-
- /* initialise status information */
- status_sslcertcheck = 0; /* 0 = no CN found in DN */
- ssl_dn_start = ssl_dn;
-
- /* validate all CNs found in DN */
- CTRACE((tfp, "Validating CNs in '%s'\n", ssl_dn_start));
- while ((cert_host = strstr(ssl_dn_start, "/CN=")) != NULL) {
- status_sslcertcheck = 1; /* 1 = could not verify CN */
- /* start of CommonName */
- cert_host += 4;
- /* find next part of DistinguishedName */
- if ((p = StrChr(cert_host, '/')) != NULL) {
- *p = '\0';
- ssl_dn_start = p; /* yes this points to the NUL byte */
- } else
- ssl_dn_start = NULL;
- cert_host = StripIpv6Brackets(cert_host);
-
- /* verify this CN */
- CTRACE((tfp, "Matching\n\tssl_host '%s'\n\tcert_host '%s'\n",
- ssl_host, cert_host));
- if (!strcasecomp_asterisk(ssl_host, cert_host)) {
- status_sslcertcheck = 2; /* 2 = verified peer */
- /* I think this is cool to have in the logs -TG */
- HTSprintf0(&msg,
- gettext("Verified connection to %s (cert=%s)"),
- ssl_host, cert_host);
- _HTProgress(msg);
- FREE(msg);
- /* no need to continue the verification loop */
- break;
- }
-
- /* add this CN to list of failed CNs */
- if (ssl_all_cns == NULL)
- StrAllocCopy(ssl_all_cns, "CN<");
- else
- StrAllocCat(ssl_all_cns, ":CN<");
- StrAllocCat(ssl_all_cns, cert_host);
- StrAllocCat(ssl_all_cns, ">");
- /* if we cannot retry, don't try it */
- if (ssl_dn_start == NULL)
- break;
- /* now retry next CN found in DN */
- *ssl_dn_start = '/'; /* formerly NUL byte */
- }
-
- /* check the X.509v3 Subject Alternative Name */
-#ifdef USE_GNUTLS_INCL
- if (status_sslcertcheck < 2) {
- int i;
- size_t size;
- gnutls_x509_crt_t cert;
- static char buf[2048];
-
- /* import the certificate to the x509_crt format */
- if (gnutls_x509_crt_init(&cert) == 0) {
-
- if (gnutls_x509_crt_import(cert, peer_cert,
- GNUTLS_X509_FMT_DER) < 0) {
- gnutls_x509_crt_deinit(cert);
- goto done;
- }
-
- ret = 0;
- for (i = 0; !(ret < 0); i++) {
- size = sizeof(buf);
- ret = gnutls_x509_crt_get_subject_alt_name(cert, i, buf,
- &size, NULL);
-
- if (strcasecomp_asterisk(ssl_host, buf) == 0) {
- status_sslcertcheck = 2;
- HTSprintf0(&msg,
- gettext("Verified connection to %s (subj=%s)"),
- ssl_host, buf);
- _HTProgress(msg);
- FREE(msg);
- break;
- }
-
- }
- }
- }
-#endif
-#ifdef USE_OPENSSL_INCL
- if (status_sslcertcheck < 2) {
- STACK_OF(GENERAL_NAME) * gens;
- int i, numalts;
- const GENERAL_NAME *gn;
-
- gens = (STACK_OF(GENERAL_NAME) *)
- X509_get_ext_d2i(peer_cert, NID_subject_alt_name, NULL, NULL);
-
- if (gens != NULL) {
- numalts = sk_GENERAL_NAME_num(gens);
- for (i = 0; i < numalts; ++i) {
- gn = sk_GENERAL_NAME_value(gens, i);
- if (gn->type == GEN_DNS)
- cert_host = (char *) ASN1_STRING_data(gn->d.ia5);
- else if (gn->type == GEN_IPADD) {
- /* XXX untested -TG */
- size_t j = (size_t) ASN1_STRING_length(gn->d.ia5);
-
- cert_host = (char *) malloc(j + 1);
- MemCpy(cert_host, ASN1_STRING_data(gn->d.ia5), j);
- cert_host[j] = '\0';
- } else
- continue;
- status_sslcertcheck = 1; /* got at least one */
- /* verify this SubjectAltName (see above) */
- cert_host = StripIpv6Brackets(cert_host);
- if (!(gn->type == GEN_IPADD ? strcasecomp :
- strcasecomp_asterisk) (ssl_host, cert_host)) {
- status_sslcertcheck = 2;
- HTSprintf0(&msg,
- gettext("Verified connection to %s (subj=%s)"),
- ssl_host, cert_host);
- _HTProgress(msg);
- FREE(msg);
- if (gn->type == GEN_IPADD)
- free(cert_host);
- break;
- }
- /* add to list of failed CNs */
- if (ssl_all_cns == NULL)
- StrAllocCopy(ssl_all_cns, "SAN<");
- else
- StrAllocCat(ssl_all_cns, ":SAN<");
- if (gn->type == GEN_DNS)
- StrAllocCat(ssl_all_cns, "DNS=");
- else if (gn->type == GEN_IPADD)
- StrAllocCat(ssl_all_cns, "IP=");
- StrAllocCat(ssl_all_cns, cert_host);
- StrAllocCat(ssl_all_cns, ">");
- if (gn->type == GEN_IPADD)
- free(cert_host);
- }
- sk_GENERAL_NAME_free(gens);
- }
- }
-#endif /* USE_OPENSSL_INCL */
-
- /* if an error occurred, format the appropriate message */
- if (status_sslcertcheck == 0) {
- HTSprintf0(&msg, SSL_FORCED_PROMPT,
- gettext("Can't find common name in certificate"));
- } else if (status_sslcertcheck == 1) {
- HTSprintf0(&msg,
- gettext("SSL error:host(%s)!=cert(%s)-Continue?"),
- ssl_host, ssl_all_cns);
- }
-
- /* if an error occurred, let the user decide how much he trusts */
- if (status_sslcertcheck < 2) {
- if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
- status = HT_NOT_LOADED;
- FREE(msg);
- FREE(ssl_all_cns);
- goto done;
- }
- HTSprintf0(&msg,
- gettext("UNVERIFIED connection to %s (cert=%s)"),
- ssl_host, ssl_all_cns ? ssl_all_cns : "NONE");
- _HTProgress(msg);
- FREE(msg);
- }
-
- show_cert_issuer(peer_cert);
-
- HTSprintf0(&msg,
- gettext("Secure %d-bit %s (%s) HTTP connection"),
- SSL_get_cipher_bits(handle, NULL),
- SSL_get_cipher_version(handle),
- SSL_get_cipher(handle));
- _HTProgress(msg);
- FREE(msg);
- }
-#endif /* USE_SSL */
-
- /* Ask that node for the document, omitting the host name & anchor
- */
- {
- char *p1 = (HTParse(url, "", PARSE_PATH | PARSE_PUNCTUATION));
-
-#ifdef USE_SSL
- if (do_connect) {
- METHOD = "CONNECT";
- BStrCopy0(command, "CONNECT ");
- } else
-#endif /* USE_SSL */
- if (do_post) {
- METHOD = "POST";
- BStrCopy0(command, "POST ");
- } else if (do_head) {
- METHOD = "HEAD";
- BStrCopy0(command, "HEAD ");
- } else {
- METHOD = "GET";
- BStrCopy0(command, "GET ");
- }
-
- /*
- * If we are using a proxy gateway don't copy in the first slash of
- * say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj so that just
- * gopher://.... is sent.
- */
-#ifdef USE_SSL
- if (using_proxy && !did_connect) {
- if (do_connect)
- BStrCat0(command, connect_host);
- else
- BStrCat0(command, p1 + 1);
- }
-#else
- if (using_proxy)
- BStrCat0(command, p1 + 1);
-#endif /* USE_SSL */
- else
- BStrCat0(command, p1);
- FREE(p1);
- }
- if (extensions) {
- BStrCat0(command, " ");
- BStrCat0(command, HTTP_VERSION);
- }
-
- BStrCat0(command, crlf); /* CR LF, as in rfc 977 */
-
- if (extensions) {
- int n, i;
- char *host = NULL;
-
- if ((host = HTParse(anAnchor->address, "", PARSE_HOST)) != NULL) {
- strip_userid(host);
- HTBprintf(&command, "Host: %s%c%c", host, CR, LF);
- FREE(host);
- }
-
- if (!HTPresentations)
- HTFormatInit();
- n = HTList_count(HTPresentations);
-
- first_Accept = TRUE;
- len = 0;
- for (i = 0; i < n; i++) {
- HTPresentation *pres =
- (HTPresentation *) HTList_objectAt(HTPresentations, i);
-
- if (pres->get_accept) {
- if (pres->quality < 1.0) {
- if (pres->maxbytes > 0) {
- sprintf(temp, ";q=%4.3f;mxb=%" PRI_off_t "",
- pres->quality, CAST_off_t (pres->maxbytes));
- } else {
- sprintf(temp, ";q=%4.3f", pres->quality);
- }
- } else if (pres->maxbytes > 0) {
- sprintf(temp, ";mxb=%" PRI_off_t "", CAST_off_t (pres->maxbytes));
- } else {
- temp[0] = '\0';
- }
- HTSprintf0(&linebuf, "%s%s%s",
- (first_Accept ?
- "Accept: " : ", "),
- HTAtom_name(pres->rep),
- temp);
- len += (int) strlen(linebuf);
- if (len > 252 && !first_Accept) {
- BStrCat0(command, crlf);
- HTSprintf0(&linebuf, "Accept: %s%s",
- HTAtom_name(pres->rep),
- temp);
- len = (int) strlen(linebuf);
- }
- BStrCat0(command, linebuf);
- first_Accept = FALSE;
- }
- }
- HTBprintf(&command, "%s*/*;q=0.01%c%c",
- (first_Accept ?
- "Accept: " : ", "), CR, LF);
-
- /*
- * FIXME: suppressing the "Accept-Encoding" in this case is done to
- * work around limitations of the presentation logic used for the
- * command-line "-base" option. The remote site may transmit the
- * document gzip'd, but the ensuing logic in HTSaveToFile() would see
- * the mime-type as gzip rather than text/html, and not prepend the
- * base URL. This is less efficient than accepting the compressed data
- * and uncompressing it, adding the base URL but is simpler than
- * augmenting the dump's presentation logic -TD
- */
- if (LYPrependBaseToSource && dump_output_immediately) {
- CTRACE((tfp,
- "omit Accept-Encoding to work-around interaction with -source\n"));
- } else {
- char *list = 0;
- int j, k;
-
- for (j = 1; j < encodingALL; j <<= 1) {
- if (acceptEncoding(j)) {
- for (k = 0; tbl_preferred_encoding[k].name != 0; ++k) {
- if (tbl_preferred_encoding[k].value == j) {
- if (list != 0)
- StrAllocCat(list, ", ");
- StrAllocCat(list, tbl_preferred_encoding[k].name);
- break;
- }
- }
- }
- }
-
- if (list != 0) {
- HTBprintf(&command, "Accept-Encoding: %s%c%c", list, CR, LF);
- free(list);
- }
- }
-
- if (language && *language) {
- HTBprintf(&command, "Accept-Language: %s%c%c", language, CR, LF);
- }
-
- if (pref_charset && *pref_charset) {
- BStrCat0(command, "Accept-Charset: ");
- StrAllocCopy(linebuf, pref_charset);
- if (linebuf[strlen(linebuf) - 1] == ',')
- linebuf[strlen(linebuf) - 1] = '\0';
- LYLowerCase(linebuf);
- if (strstr(linebuf, "iso-8859-1") == NULL)
- StrAllocCat(linebuf, ", iso-8859-1;q=0.01");
- if (strstr(linebuf, "us-ascii") == NULL)
- StrAllocCat(linebuf, ", us-ascii;q=0.01");
- BStrCat0(command, linebuf);
- HTBprintf(&command, "%c%c", CR, LF);
- }
-#if 0
- /*
- * Promote 300 (Multiple Choices) replies, if supported, over 406 (Not
- * Acceptable) replies. - FM
- *
- * This used to be done in versions 2.7 and 2.8*, but violates the
- * specs for transparent content negotiation and has the effect that
- * servers supporting those specs will send 300 (Multiple Choices)
- * instead of a normal response (e.g. 200 OK), since they will assume
- * that the client wants to make the choice. It is not clear whether
- * there are any servers or sites for which sending this header really
- * improves anything.
- *
- * If there ever is a need to send "Negotiate: trans" and really mean
- * it, we should send "Negotiate: trans,trans" or similar, since that
- * is semantically equivalent and some servers may ignore "Negotiate:
- * trans" as a special case when it comes from Lynx (to work around the
- * old faulty behavior). - kw
- *
- * References:
- * RFC 2295 (see also RFC 2296), and mail to lynx-dev and
- * new-httpd@apache.org from Koen Holtman, Jan 1999.
- */
- if (!do_post) {
- HTBprintf(&command, "Negotiate: trans%c%c", CR, LF);
- }
-#endif /* 0 */
-
- /*
- * When reloading give no-cache pragma to proxy server to make it
- * refresh its cache. -- Ari L. <luotonen@dxcern.cern.ch>
- *
- * Also send it as a Cache-Control header for HTTP/1.1. - FM
- */
- if (reloading) {
- HTBprintf(&command, "Pragma: no-cache%c%c", CR, LF);
- HTBprintf(&command, "Cache-Control: no-cache%c%c", CR, LF);
- }
-
- if (LYSendUserAgent || no_useragent) {
- if (non_empty(LYUserAgent)) {
- char *cp = LYSkipBlanks(LYUserAgent);
-
- /* Won't send it at all if all blank - kw */
- if (*cp != '\0')
- HTBprintf(&command, "User-Agent: %.*s%c%c",
- INIT_LINE_SIZE - 15, LYUserAgent, CR, LF);
- } else {
- HTBprintf(&command, "User-Agent: %s/%s libwww-FM/%s%c%c",
- HTAppName ? HTAppName : "unknown",
- HTAppVersion ? HTAppVersion : "0.0",
- HTLibraryVersion, CR, LF);
- }
- }
-
- if (personal_mail_address && !LYNoFromHeader) {
- HTBprintf(&command, "From: %s%c%c", personal_mail_address, CR, LF);
- }
-
- if (!(LYUserSpecifiedURL ||
- LYNoRefererHeader || LYNoRefererForThis) &&
- strcmp(HTLoadedDocumentURL(), "")) {
- const char *cp = LYRequestReferer;
-
- if (!cp)
- cp = HTLoadedDocumentURL(); /* @@@ Try both? - kw */
- BStrCat0(command, "Referer: ");
- if (isLYNXIMGMAP(cp)) {
- char *pound = findPoundSelector(cp);
- int nn = (pound ? (int) (pound - cp) : (int) strlen(cp));
-
- HTSABCat(&command, cp + LEN_LYNXIMGMAP, nn);
- } else {
- BStrCat0(command, cp);
- }
- HTBprintf(&command, "%c%c", CR, LF);
- } {
- char *abspath;
- char *docname;
- char *hostname;
- char *colon;
- int portnumber;
- char *auth, *cookie = NULL;
- BOOL secure = (BOOL) (StrNCmp(anAnchor->address, "https", 5)
- ? FALSE
- : TRUE);
-
- abspath = HTParse(arg, "", PARSE_PATH | PARSE_PUNCTUATION);
- docname = HTParse(arg, "", PARSE_PATH);
- hostname = HTParse(arg, "", PARSE_HOST);
- if (hostname &&
- NULL != (colon = HTParsePort(hostname, &portnumber))) {
- *colon = '\0'; /* Chop off port number */
- } else if (!StrNCmp(arg, "https", 5)) {
- portnumber = HTTPS_PORT;
- } else {
- portnumber = HTTP_PORT;
- }
-
- /*
- * Add Authorization, Proxy-Authorization, and/or Cookie headers,
- * if applicable.
- */
- if (using_proxy) {
- /*
- * If we are using a proxy, first determine if we should
- * include an Authorization header and/or Cookie header for the
- * ultimate target of this request. - FM & AJL
- */
- char *host2 = NULL, *path2 = NULL;
- int port2 = (StrNCmp(docname, "https", 5) ?
- HTTP_PORT : HTTPS_PORT);
-
- host2 = HTParse(docname, "", PARSE_HOST);
- path2 = HTParse(docname, "", PARSE_PATH | PARSE_PUNCTUATION);
- if ((colon = HTParsePort(host2, &port2)) != NULL) {
- /* Use non-default port number */
- *colon = '\0';
- }
-
- /*
- * This composeAuth() does file access, i.e., for the ultimate
- * target of the request. - AJL
- */
- auth_proxy = NO;
- auth = HTAA_composeAuth(host2, port2, path2, auth_proxy);
- if (auth == NULL) {
- CTRACE((tfp, "HTTP: Not sending authorization (yet).\n"));
- } else if (*auth != '\0') {
- /*
- * We have an Authorization header to be included.
- */
- HTBprintf(&command, "%s%c%c", auth, CR, LF);
- CTRACE((tfp, "HTTP: Sending authorization: %s\n", auth));
- } else {
- /*
- * The user either cancelled or made a mistake with the
- * username and password prompt.
- */
- if (!(traversal || dump_output_immediately) &&
- HTConfirm(CONFIRM_WO_PASSWORD)) {
- show_401 = TRUE;
- } else {
- if (traversal || dump_output_immediately)
- HTAlert(FAILED_NEED_PASSWD);
-#ifdef USE_SSL
- if (did_connect)
- HTTP_NETCLOSE(s, handle);
-#endif /* USE_SSL */
- BStrFree(command);
- FREE(hostname);
- FREE(docname);
- FREE(abspath);
- FREE(host2);
- FREE(path2);
- status = HT_NOT_LOADED;
- goto done;
- }
- }
- /*
- * Add 'Cookie:' header, if it's HTTP or HTTPS document being
- * proxied.
- */
- if (!StrNCmp(docname, "http", 4)) {
- cookie = LYAddCookieHeader(host2, path2, port2, secure);
- }
- FREE(host2);
- FREE(path2);
- /*
- * The next composeAuth() will be for the proxy. - AJL
- */
- auth_proxy = YES;
- } else {
- /*
- * Add cookie for a non-proxied request. - FM
- */
- cookie = LYAddCookieHeader(hostname, abspath, portnumber, secure);
- auth_proxy = NO;
- }
- /*
- * If we do have a cookie set, add it to the request buffer. - FM
- */
- if (cookie != NULL) {
- if (*cookie != '$') {
- /*
- * It's a historical cookie, so signal to the server that
- * we support modern cookies. - FM
- */
- BStrCat0(command, "Cookie2: $Version=\"1\"");
- BStrCat0(command, crlf);
- CTRACE((tfp, "HTTP: Sending Cookie2: $Version =\"1\"\n"));
- }
- if (*cookie != '\0') {
- /*
- * It's not a zero-length string, so add the header. Note
- * that any folding of long strings has been done already
- * in LYCookie.c. - FM
- */
- BStrCat0(command, "Cookie: ");
- BStrCat0(command, cookie);
- BStrCat0(command, crlf);
- CTRACE((tfp, "HTTP: Sending Cookie: %s\n", cookie));
- }
- FREE(cookie);
- }
- FREE(abspath);
-
- /*
- * If we are using a proxy, auth_proxy should be YES, and we check
- * here whether we want a Proxy-Authorization header for it. If we
- * are not using a proxy, auth_proxy should still be NO, and we
- * check here for whether we want an Authorization header. - FM &
- * AJL
- */
- if ((auth = HTAA_composeAuth(hostname,
- portnumber,
- docname,
- auth_proxy)) != NULL &&
- *auth != '\0') {
- /*
- * If auth is not NULL nor zero-length, it's an Authorization
- * or Proxy-Authorization header to be included. - FM
- */
- HTBprintf(&command, "%s%c%c", auth, CR, LF);
- CTRACE((tfp, (auth_proxy ?
- "HTTP: Sending proxy authorization: %s\n" :
- "HTTP: Sending authorization: %s\n"),
- auth));
- } else if (auth && *auth == '\0') {
- /*
- * If auth is a zero-length string, the user either cancelled
- * or goofed at the username and password prompt. - FM
- */
- if (!(traversal || dump_output_immediately) && HTConfirm(CONFIRM_WO_PASSWORD)) {
- if (auth_proxy == TRUE) {
- show_407 = TRUE;
- } else {
- show_401 = TRUE;
- }
- } else {
- if (traversal || dump_output_immediately)
- HTAlert(FAILED_NEED_PASSWD);
- BStrFree(command);
- FREE(hostname);
- FREE(docname);
- status = HT_NOT_LOADED;
- goto done;
- }
- } else {
- CTRACE((tfp, (auth_proxy ?
- "HTTP: Not sending proxy authorization (yet).\n" :
- "HTTP: Not sending authorization (yet).\n")));
- }
- FREE(hostname);
- FREE(docname);
- }
- }
-
- if (
-#ifdef USE_SSL
- !do_connect &&
-#endif /* USE_SSL */
- do_post) {
- CTRACE((tfp, "HTTP: Doing post, content-type '%s'\n",
- anAnchor->post_content_type
- ? anAnchor->post_content_type
- : "lose"));
- HTBprintf(&command, "Content-type: %s%c%c",
- anAnchor->post_content_type
- ? anAnchor->post_content_type
- : "lose",
- CR, LF);
-
- HTBprintf(&command, "Content-length: %d%c%c",
- !isBEmpty(anAnchor->post_data)
- ? BStrLen(anAnchor->post_data)
- : 0,
- CR, LF);
-
- BStrCat0(command, crlf); /* Blank line means "end" of headers */
-
- BStrCat(command, anAnchor->post_data);
- } else
- BStrCat0(command, crlf); /* Blank line means "end" of headers */
-
- if (TRACE) {
- CTRACE((tfp, "Writing:\n"));
- trace_bstring(command);
-#ifdef USE_SSL
- CTRACE((tfp, "%s",
- (anAnchor->post_data && !do_connect ? crlf : "")));
-#else
- CTRACE((tfp, "%s",
- (anAnchor->post_data ? crlf : "")));
-#endif /* USE_SSL */
- CTRACE((tfp, "----------------------------------\n"));
- }
-
- _HTProgress(gettext("Sending HTTP request."));
-
-#ifdef NOT_ASCII /* S/390 -- gil -- 0548 */
- {
- char *p2;
-
- for (p2 = BStrData(command);
- p2 < BStrData(command) + BStrLen(command);
- p2++)
- *p2 = TOASCII(*p2);
- }
-#endif /* NOT_ASCII */
- status = (int) HTTP_NETWRITE(s,
- BStrData(command),
- BStrLen(command),
- handle);
- BStrFree(command);
- FREE(linebuf);
- if (status <= 0) {
- if (status == 0) {
- CTRACE((tfp, "HTTP: Got status 0 in initial write\n"));
- /* Do nothing. */
- } else if ((SOCKET_ERRNO == ENOTCONN ||
- SOCKET_ERRNO == ECONNRESET ||
- SOCKET_ERRNO == EPIPE) &&
- !already_retrying &&
- /* Don't retry if we're posting. */ !do_post) {
- /*
- * Arrrrgh, HTTP 0/1 compatibility problem, maybe.
- */
- CTRACE((tfp,
- "HTTP: BONZO ON WRITE Trying again with HTTP0 request.\n"));
- _HTProgress(RETRYING_AS_HTTP0);
- HTTP_NETCLOSE(s, handle);
- extensions = NO;
- already_retrying = TRUE;
- goto try_again;
- } else {
- CTRACE((tfp,
- "HTTP: Hit unexpected network WRITE error; aborting connection.\n"));
- HTTP_NETCLOSE(s, handle);
- status = -1;
- HTAlert(gettext("Unexpected network write error; connection aborted."));
- goto done;
- }
- }
-
- CTRACE((tfp, "HTTP: WRITE delivered OK\n"));
- _HTProgress(gettext("HTTP request sent; waiting for response."));
-
- /* Read the first line of the response
- * -----------------------------------
- */
- {
- /* Get numeric status etc */
- BOOL end_of_file = NO;
- int buffer_length = INIT_LINE_SIZE;
-
- line_buffer = typecallocn(char, (size_t) buffer_length);
-
- if (line_buffer == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
-
- HTReadProgress(bytes_already_read = 0, (off_t) 0);
- do { /* Loop to read in the first line */
- /*
- * Extend line buffer if necessary for those crazy WAIS URLs ;-)
- */
- if (buffer_length - length < LINE_EXTEND_THRESH) {
- buffer_length = buffer_length + buffer_length;
- line_buffer =
- (char *) realloc(line_buffer, ((unsigned) buffer_length *
- sizeof(char)));
-
- if (line_buffer == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
- }
- CTRACE((tfp, "HTTP: Trying to read %d\n", buffer_length - length - 1));
- status = HTTP_NETREAD(s,
- line_buffer + length,
- (buffer_length - length - 1),
- handle);
- CTRACE((tfp, "HTTP: Read %d\n", status));
- if (status <= 0) {
- /*
- * Retry if we get nothing back too.
- * Bomb out if we get nothing twice.
- */
- if (status == HT_INTERRUPTED) {
- CTRACE((tfp, "HTTP: Interrupted initial read.\n"));
- _HTProgress(CONNECTION_INTERRUPTED);
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto clean_up;
- } else if (status < 0 &&
- (SOCKET_ERRNO == ENOTCONN ||
-#ifdef _WINDOWS /* 1997/11/09 (Sun) 16:59:58 */
- SOCKET_ERRNO == ETIMEDOUT ||
-#endif
- SOCKET_ERRNO == ECONNRESET ||
- SOCKET_ERRNO == EPIPE) &&
- !already_retrying && !do_post) {
- /*
- * Arrrrgh, HTTP 0/1 compability problem, maybe.
- */
- CTRACE((tfp,
- "HTTP: BONZO Trying again with HTTP0 request.\n"));
- HTTP_NETCLOSE(s, handle);
- FREE(line_buffer);
- FREE(line_kept_clean);
-
- extensions = NO;
- already_retrying = TRUE;
- _HTProgress(RETRYING_AS_HTTP0);
- goto try_again;
- }
-#ifdef USE_SSL
- else if ((SSLerror = ERR_get_error()) != 0) {
- CTRACE((tfp,
- "HTTP: Hit unexpected network read error; aborting connection; status %d:%s.\n",
- status, ERR_error_string(SSLerror, NULL)));
- HTAlert(gettext("Unexpected network read error; connection aborted."));
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
-#endif
- else {
- CTRACE((tfp,
- "HTTP: Hit unexpected network read error; aborting connection; status %d.\n",
- status));
- HTAlert(gettext("Unexpected network read error; connection aborted."));
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- }
-#ifdef NOT_ASCII /* S/390 -- gil -- 0564 */
- {
- char *p2;
-
- for (p2 = line_buffer + length;
- p2 < line_buffer + length + status;
- p2++)
- *p2 = FROMASCII(*p2);
- }
-#endif /* NOT_ASCII */
-
- bytes_already_read += status;
- HTReadProgress(bytes_already_read, (off_t) 0);
-
-#ifdef UCX /* UCX returns -1 on EOF */
- if (status == 0 || status == -1)
-#else
- if (status == 0)
-#endif
- {
- break;
- }
- line_buffer[length + status] = 0;
-
- if (line_buffer) {
- FREE(line_kept_clean);
- line_kept_clean = (char *) malloc((unsigned) buffer_length *
- sizeof(char));
-
- if (line_kept_clean == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
- MemCpy(line_kept_clean, line_buffer, buffer_length);
-#ifdef SH_EX /* FIX BUG by kaz@maczuka.hitachi.ibaraki.jp */
- real_length_of_line = length + status;
-#endif
- }
-
- eol = StrChr(line_buffer + length, LF);
- /* Do we *really* want to do this? */
- if (eol && eol != line_buffer && *(eol - 1) == CR)
- *(eol - 1) = ' ';
-
- length = length + status;
-
- /* Do we really want to do *this*? */
- if (eol)
- *eol = 0; /* Terminate the line */
- }
- /* All we need is the first line of the response. If it's a HTTP/1.0
- * response, then the first line will be absurdly short and therefore
- * we can safely gate the number of bytes read through this code (as
- * opposed to below) to ~1000.
- *
- * Well, let's try 100.
- */
- while (!eol && !end_of_file && bytes_already_read < 100);
- } /* Scope of loop variables */
-
- /* save total length, in case we decide later to show it all - kw */
- rawlength = length;
-
- /* We now have a terminated unfolded line. Parse it.
- * --------------------------------------------------
- */
- CTRACE((tfp, "HTTP: Rx: %s\n", line_buffer));
-
- /*
- * Kludge to work with old buggy servers and the VMS Help gateway. They
- * can't handle the third word, so we try again without it.
- */
- if (extensions && /* Old buggy server or Help gateway? */
- (0 == StrNCmp(line_buffer, "<TITLE>Bad File Request</TITLE>", 31) ||
- 0 == StrNCmp(line_buffer, "Address should begin with", 25) ||
- 0 == StrNCmp(line_buffer, "<TITLE>Help ", 12) ||
- 0 == strcmp(line_buffer,
- "Document address invalid or access not authorised"))) {
- FREE(line_buffer);
- FREE(line_kept_clean);
- extensions = NO;
- already_retrying = TRUE;
- CTRACE((tfp, "HTTP: close socket %d to retry with HTTP0\n", s));
- HTTP_NETCLOSE(s, handle);
- /* print a progress message */
- _HTProgress(RETRYING_AS_HTTP0);
- goto try_again;
- } {
- int fields;
- char server_version[VERSION_LENGTH + 1];
-
- server_version[0] = 0;
-
- fields = sscanf(line_buffer, "%20s %d",
- server_version,
- &server_status);
-
- CTRACE((tfp, "HTTP: Scanned %d fields from line_buffer\n", fields));
-
- if (http_error_file) { /* Make the status code externally available */
- FILE *error_file;
-
-#ifdef SERVER_STATUS_ONLY
- error_file = fopen(http_error_file, TXT_W);
- if (error_file) { /* Managed to open the file */
- fprintf(error_file, "error=%d\n", server_status);
- fclose(error_file);
- }
-#else
- error_file = fopen(http_error_file, TXT_A);
- if (error_file) { /* Managed to open the file */
- fprintf(error_file, " URL=%s (%s)\n", url, METHOD);
- fprintf(error_file, "STATUS=%s\n", line_buffer);
- fclose(error_file);
- }
-#endif /* SERVER_STATUS_ONLY */
- }
-
- /*
- * Rule out a non-HTTP/1.n reply as best we can.
- */
- if (fields < 2 || !server_version[0] || server_version[0] != 'H' ||
- server_version[1] != 'T' || server_version[2] != 'T' ||
- server_version[3] != 'P' || server_version[4] != '/' ||
- server_version[6] != '.') {
- /*
- * Ugh! An HTTP0 reply,
- */
- HTAtom *encoding;
-
- CTRACE((tfp, "--- Talking HTTP0.\n"));
-
- format_in = HTFileFormat(url, &encoding, NULL);
- /*
- * Treat all plain text as HTML. This sucks but its the only
- * solution without without looking at content.
- */
- if (!StrNCmp(HTAtom_name(format_in), "text/plain", 10)) {
- CTRACE((tfp, "HTTP: format_in being changed to text/HTML\n"));
- format_in = WWW_HTML;
- }
- if (!IsUnityEnc(encoding)) {
- /*
- * Change the format to that for "www/compressed".
- */
- CTRACE((tfp, "HTTP: format_in is '%s',\n", HTAtom_name(format_in)));
- StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in));
- StrAllocCopy(anAnchor->content_encoding, HTAtom_name(encoding));
- format_in = HTAtom_for("www/compressed");
- CTRACE((tfp, " Treating as '%s' with encoding '%s'\n",
- "www/compressed", HTAtom_name(encoding)));
- }
-
- start_of_data = line_kept_clean;
- } else {
- /*
- * Set up to decode full HTTP/1.n response. - FM
- */
- format_in = HTAtom_for("www/mime");
- CTRACE((tfp, "--- Talking HTTP1.\n"));
-
- /*
- * We set start_of_data to "" when !eol here because there will be
- * a put_block done below; we do *not* use the value of
- * start_of_data (as a pointer) in the computation of length (or
- * anything else) when !eol. Otherwise, set the value of length to
- * what we have beyond eol (i.e., beyond the status line). - FM
- */
- if (eol != 0) {
- start_of_data = (eol + 1);
- } else {
- start_of_data = empty;
- }
- length = (eol
- ? length - (int) (start_of_data - line_buffer)
- : 0);
-
- /*
- * Trim trailing spaces in line_buffer so that we can use it in
- * messages which include the status line. - FM
- */
- while (line_buffer[strlen(line_buffer) - 1] == ' ')
- line_buffer[strlen(line_buffer) - 1] = '\0';
-
- /*
- * Take appropriate actions based on the status. - FM
- */
- switch (server_status / 100) {
- case 1:
- /*
- * HTTP/1.1 Informational statuses.
- * 100 Continue.
- * 101 Switching Protocols.
- * > 101 is unknown.
- * We should never get these, and they have only the status
- * line and possibly other headers, so we'll deal with them by
- * showing the full header to the user as text/plain. - FM
- */
- HTAlert(gettext("Got unexpected Informational Status."));
- do_head = TRUE;
- break;
-
- case 2:
- /*
- * Good: Got MIME object! (Successful) - FM
- */
- if (do_head) {
- /*
- * If HEAD was requested, show headers (and possibly bogus
- * body) for all 2xx status codes as text/plain - KW
- */
- HTProgress(line_buffer);
- break;
- }
- switch (server_status) {
- case 204:
- /*
- * No Content.
- */
- HTAlert(line_buffer);
- HTTP_NETCLOSE(s, handle);
- HTNoDataOK = 1;
- status = HT_NO_DATA;
- goto clean_up;
-
- case 205:
- /*
- * Reset Content. The server has fulfilled the request but
- * nothing is returned and we should reset any form
- * content. We'll instruct the user to do that, and
- * restore the current document. - FM
- */
- HTAlert(gettext("Request fulfilled. Reset Content."));
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto clean_up;
-
- case 206:
- /*
- * Partial Content. We didn't send a Range so something
- * went wrong somewhere. Show the status message and
- * restore the current document. - FM
- */
- HTAlert(line_buffer);
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto clean_up;
-
- default:
- /*
- * 200 OK.
- * 201 Created.
- * 202 Accepted.
- * 203 Non-Authoritative Information.
- * > 206 is unknown.
- * All should return something to display.
- */
-#if defined(USE_SSL) && !defined(DISABLE_NEWS)
- if (do_connect) {
- CTRACE((tfp,
- "HTTP: Proxy tunnel to '%s' established.\n",
- connect_host));
- do_connect = FALSE;
- url = connect_url;
- FREE(line_buffer);
- FREE(line_kept_clean);
- if (!StrNCmp(connect_url, "snews", 5)) {
- CTRACE((tfp,
- " Will attempt handshake and snews connection.\n"));
- status = HTNewsProxyConnect(s, url, anAnchor,
- format_out, sink);
- goto done;
- }
- did_connect = TRUE;
- already_retrying = TRUE;
- eol = 0;
- length = 0;
- doing_redirect = FALSE;
- permanent_redirection = FALSE;
- target = NULL;
- CTRACE((tfp,
- " Will attempt handshake and resubmit headers.\n"));
- goto use_tunnel;
- }
-#endif /* USE_SSL */
- HTProgress(line_buffer);
- } /* case 2 switch */
- break;
-
- case 3:
- /*
- * Various forms of Redirection. - FM
- * 300 Multiple Choices.
- * 301 Moved Permanently.
- * 302 Found (temporary; we can, and do, use GET).
- * 303 See Other (temporary; always use GET).
- * 304 Not Modified.
- * 305 Use Proxy.
- * 306 Set Proxy.
- * 307 Temporary Redirect with method retained.
- * > 308 is unknown.
- */
- if (no_url_redirection || do_head || keep_mime_headers) {
- /*
- * If any of these flags are set, we do not redirect, but
- * instead show what was returned to the user as
- * text/plain. - FM
- */
- HTProgress(line_buffer);
- break;
- }
-
- if (server_status == 300) { /* Multiple Choices */
- /*
- * For client driven content negotiation. The server
- * should be sending some way for the user-agent to make a
- * selection, so we'll show the user whatever the server
- * returns. There might be a Location: header with the
- * server's preference present, but the choice should be up
- * to the user, someday based on an Alternates: header,
- * and a body always should be present with descriptions
- * and links for the choices (i.e., we use the latter, for
- * now). - FM
- */
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request
- * for interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
- }
-
- if (server_status == 304) { /* Not Modified */
- /*
- * We didn't send an "If-Modified-Since" header, so this
- * status is inappropriate. We'll deal with it by showing
- * the full header to the user as text/plain. - FM
- */
- HTAlert(gettext("Got unexpected 304 Not Modified status."));
- do_head = TRUE;
- break;
- }
-
- if (server_status == 305 ||
- server_status == 306 ||
- server_status > 307) {
- /*
- * Show user the content, if any, for 305, 306, or unknown
- * status. - FM
- */
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request
- * for interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
- }
-
- /*
- * We do not load the file, but read the headers for the
- * "Location:", check out that redirecting_url and if it's
- * acceptible (e.g., not a telnet URL when we have that
- * disabled), initiate a new fetch. If that's another
- * redirecting_url, we'll repeat the checks, and fetch
- * initiations if acceptible, until we reach the actual URL, or
- * the redirection limit set in HTAccess.c is exceeded. If the
- * status was 301 indicating that the relocation is permanent,
- * we set the permanent_redirection flag to make it permanent
- * for the current anchor tree (i.e., will persist until the
- * tree is freed or the client exits). If the redirection
- * would include POST content, we seek confirmation from an
- * interactive user, with option to use 303 for 301 (but not
- * for 307), and otherwise refuse the redirection. We also
- * don't allow permanent redirection if we keep POST content.
- * If we don't find the Location header or it's value is
- * zero-length, we display whatever the server returned, and
- * the user should RELOAD that to try again, or make a
- * selection from it if it contains links, or Left-Arrow to the
- * previous document. - FM
- */
- {
- if ((dump_output_immediately || traversal) &&
- do_post &&
- server_status != 303 &&
- server_status != 302 &&
- server_status != 301) {
- /*
- * Don't redirect POST content without approval from an
- * interactive user. - FM
- */
- HTTP_NETCLOSE(s, handle);
- status = -1;
- HTAlert(gettext("Redirection of POST content requires user approval."));
- if (traversal)
- HTProgress(line_buffer);
- goto clean_up;
- }
-
- HTProgress(line_buffer);
- if (server_status == 301) { /* Moved Permanently */
- if (do_post) {
- /*
- * Don't make the redirection permanent if we have
- * POST content. - FM
- */
- CTRACE((tfp,
- "HTTP: Have POST content. Treating 301 (Permanent) as Temporary.\n"));
- HTAlert(gettext("Have POST content. Treating Permanent Redirection as Temporary.\n"));
- } else {
- permanent_redirection = TRUE;
- }
- }
- doing_redirect = TRUE;
-
- break;
- }
-
- case 4:
- /*
- * "I think I goofed!" (Client Error) - FM
- */
- switch (server_status) {
- case 401: /* Unauthorized */
- /*
- * Authorization for origin server required. If show_401
- * is set, proceed to showing the 401 body. Otherwise, if
- * we can set up authorization based on the
- * WWW-Authenticate header, and the user provides a
- * username and password, try again. Otherwise, check
- * whether to show the 401 body or restore the current
- * document - FM
- */
- if (show_401)
- break;
- if (HTAA_shouldRetryWithAuth(start_of_data, (size_t)
- length, s, NO)) {
-
- HTTP_NETCLOSE(s, handle);
- if (dump_output_immediately && !authentication_info[0]) {
- fprintf(stderr,
- "HTTP: Access authorization required.\n");
- fprintf(stderr,
- " Use the -auth=id:pw parameter.\n");
- status = HT_NO_DATA;
- goto clean_up;
- }
-
- CTRACE((tfp, "%s %d %s\n",
- "HTTP: close socket", s,
- "to retry with Access Authorization"));
-
- _HTProgress(gettext("Retrying with access authorization information."));
- FREE(line_buffer);
- FREE(line_kept_clean);
-#ifdef USE_SSL
- if (using_proxy && !StrNCmp(url, "https://", 8)) {
- url = arg;
- do_connect = TRUE;
- did_connect = FALSE;
- }
-#endif /* USE_SSL */
- goto try_again;
- } else if (!(traversal || dump_output_immediately) &&
- HTConfirm(gettext("Show the 401 message body?"))) {
- break;
- } else {
- if (traversal || dump_output_immediately)
- HTAlert(FAILED_RETRY_WITH_AUTH);
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
-
- case 407:
- /*
- * Authorization for proxy server required. If we are not
- * in fact using a proxy, or show_407 is set, proceed to
- * showing the 407 body. Otherwise, if we can set up
- * authorization based on the Proxy-Authenticate header,
- * and the user provides a username and password, try
- * again. Otherwise, check whether to show the 401 body or
- * restore the current document. - FM & AJL
- */
- if (!using_proxy || show_407)
- break;
- if (HTAA_shouldRetryWithAuth(start_of_data, (size_t)
- length, s, YES)) {
-
- HTTP_NETCLOSE(s, handle);
- if (dump_output_immediately && !proxyauth_info[0]) {
- fprintf(stderr,
- "HTTP: Proxy authorization required.\n");
- fprintf(stderr,
- " Use the -pauth=id:pw parameter.\n");
- status = HT_NO_DATA;
- goto clean_up;
- }
-
- CTRACE((tfp, "%s %d %s\n",
- "HTTP: close socket", s,
- "to retry with Proxy Authorization"));
-
- _HTProgress(HTTP_RETRY_WITH_PROXY);
- FREE(line_buffer);
- FREE(line_kept_clean);
- goto try_again;
- } else if (!(traversal || dump_output_immediately) &&
- HTConfirm(gettext("Show the 407 message body?"))) {
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation
- * request for interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
- } else {
- if (traversal || dump_output_immediately)
- HTAlert(FAILED_RETRY_WITH_PROXY);
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
-
- case 408:
- /*
- * Request Timeout. Show the status message and restore
- * the current document. - FM
- */
- HTAlert(line_buffer);
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto clean_up;
-
- default:
- /*
- * 400 Bad Request.
- * 402 Payment Required.
- * 403 Forbidden.
- * 404 Not Found.
- * 405 Method Not Allowed.
- * 406 Not Acceptable.
- * 409 Conflict.
- * 410 Gone.
- * 411 Length Required.
- * 412 Precondition Failed.
- * 413 Request Entity Too Large.
- * 414 Request-URI Too Long.
- * 415 Unsupported Media Type.
- * 416 List Response (for content negotiation).
- * > 416 is unknown.
- * Show the status message, and display the returned text
- * if we are not doing a traversal. - FM
- */
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request
- * for interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
- } /* case 4 switch */
- break;
-
- case 5:
- /*
- * "I think YOU goofed!" (server error)
- * 500 Internal Server Error
- * 501 Not Implemented
- * 502 Bad Gateway
- * 503 Service Unavailable
- * 504 Gateway Timeout
- * 505 HTTP Version Not Supported
- * > 505 is unknown.
- * Should always include a message, which we always should
- * display. - FM
- */
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request for
- * interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
-
- default:
- /*
- * Bad or unknown server_status number. Take a chance and hope
- * there is something to display. - FM
- */
- HTAlert(gettext("Unknown status reply from server!"));
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request for
- * interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- break;
- } /* Switch on server_status/100 */
-
- } /* Full HTTP reply */
- } /* scope of fields */
-
- /*
- * The user may have pressed the 'z'ap key during the pause caused by one
- * of the HTAlerts above if the server reported an error, to skip loading
- * of the error response page. Checking here before setting up the stream
- * stack and feeding it data avoids doing unnecessary work, it also can
- * avoid unnecessarily pushing a loaded document out of the cache to make
- * room for the unwanted error page. - kw
- */
- if (HTCheckForInterrupt()) {
- HTTP_NETCLOSE(s, handle);
- if (doing_redirect) {
- /*
- * Impatient user. - FM
- */
- CTRACE((tfp, "HTTP: Interrupted followup read.\n"));
- _HTProgress(CONNECTION_INTERRUPTED);
- }
- status = HT_INTERRUPTED;
- goto clean_up;
- }
- /*
- * Set up the stream stack to handle the body of the message.
- */
- if (do_head || keep_mime_headers) {
- /*
- * It was a HEAD request, or we want the headers and source.
- */
- start_of_data = line_kept_clean;
-#ifdef SH_EX /* FIX BUG by kaz@maczuka.hitachi.ibaraki.jp */
-/* GIF file contains \0, so strlen does not return the data length */
- length = real_length_of_line;
-#else
- length = rawlength;
-#endif
- format_in = HTAtom_for("text/plain");
-
- } else if (doing_redirect) {
-
- format_in = HTAtom_for("message/x-http-redirection");
- StrAllocCopy(anAnchor->content_type, HTAtom_name(format_in));
- if (traversal) {
- format_out = WWW_DEBUG;
- if (!sink)
- sink = HTErrorStream();
- } else if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
- /*
- * Convert a download request to a presentation request for
- * interactive users. - FM
- */
- format_out = WWW_PRESENT;
- }
- }
-
- target = HTStreamStack(format_in,
- format_out,
- sink, anAnchor);
-
- if (target == NULL) {
- char *buffer = NULL;
-
- HTTP_NETCLOSE(s, handle);
- HTSprintf0(&buffer, CANNOT_CONVERT_I_TO_O,
- HTAtom_name(format_in), HTAtom_name(format_out));
- _HTProgress(buffer);
- FREE(buffer);
- status = -1;
- goto clean_up;
- }
-
- /*
- * Recycle the first chunk of data, in all cases.
- */
- (*target->isa->put_block) (target, start_of_data, length);
-
- /*
- * Go pull the bulk of the data down.
- */
- rv = HTCopy(anAnchor, s, (void *) handle, target);
-
- /*
- * If we get here with doing_redirect set, it means that we were looking
- * for a Location header. We either have got it now in redirecting_url -
- * in that case the stream should not have loaded any data. Or we didn't
- * get it, in that case the stream may have presented the message body
- * normally. - kw
- */
-
- if (rv == -1) {
- /*
- * Intentional interrupt before data were received, not an error
- */
- if (doing_redirect && traversal)
- status = -1;
- else
- status = HT_INTERRUPTED;
- HTTP_NETCLOSE(s, handle);
- goto clean_up;
- }
-
- if (rv == -2) {
- /*
- * Aw hell, a REAL error, maybe cuz it's a dumb HTTP0 server
- */
- (*target->isa->_abort) (target, NULL);
- if (doing_redirect && redirecting_url) {
- /*
- * Got a location before the error occurred? Then consider it an
- * interrupt but proceed below as normal. - kw
- */
- /* do nothing here */
- } else {
- HTTP_NETCLOSE(s, handle);
- if (!doing_redirect && !already_retrying && !do_post) {
- CTRACE((tfp, "HTTP: Trying again with HTTP0 request.\n"));
- /*
- * May as well consider it an interrupt -- right?
- */
- FREE(line_buffer);
- FREE(line_kept_clean);
- extensions = NO;
- already_retrying = TRUE;
- _HTProgress(RETRYING_AS_HTTP0);
- goto try_again;
- } else {
- status = HT_NOT_LOADED;
- goto clean_up;
- }
- }
- }
-
- /*
- * Free if complete transmission (socket was closed before return). Close
- * socket if partial transmission (was freed on abort).
- */
- if (rv != HT_INTERRUPTED && rv != -2) {
- (*target->isa->_free) (target);
- } else {
- HTTP_NETCLOSE(s, handle);
- }
-
- if (doing_redirect) {
- if (redirecting_url) {
- /*
- * Set up for checking redirecting_url in LYGetFile.c for
- * restrictions before we seek the document at that Location. - FM
- */
- CTRACE((tfp, "HTTP: Picked up location '%s'\n",
- redirecting_url));
- if (rv == HT_INTERRUPTED) {
- /*
- * Intentional interrupt after data were received, not an error
- * (probably). We take it as a user request to abandon the
- * redirection chain.
- *
- * This could reasonably be changed (by just removing this
- * block), it would make sense if there are redirecting
- * resources that "hang" after sending the headers. - kw
- */
- FREE(redirecting_url);
- CTRACE((tfp, "HTTP: Interrupted followup read.\n"));
- status = HT_INTERRUPTED;
- goto clean_up;
- }
- HTProgress(line_buffer);
- if (server_status == 305) { /* Use Proxy */
- /*
- * Make sure the proxy field ends with a slash. - FM
- */
- if (redirecting_url[strlen(redirecting_url) - 1]
- != '/')
- StrAllocCat(redirecting_url, "/");
- /*
- * Append our URL. - FM
- */
- StrAllocCat(redirecting_url, anAnchor->address);
- CTRACE((tfp, "HTTP: Proxy URL is '%s'\n",
- redirecting_url));
- }
- if (!do_post ||
- server_status == 303 ||
- server_status == 302) {
- /*
- * We don't have POST content (nor support PUT or DELETE), or
- * the status is "See Other" or "General Redirection" and we
- * can convert to GET, so go back and check out the new URL. -
- * FM
- */
- status = HT_REDIRECTING;
- goto clean_up;
- }
- /*
- * Make sure the user wants to redirect the POST content, or treat
- * as GET - FM & DK
- */
- switch (HTConfirmPostRedirect(redirecting_url,
- server_status)) {
- /*
- * User failed to confirm. Abort the fetch.
- */
- case 0:
- FREE(redirecting_url);
- status = HT_NO_DATA;
- goto clean_up;
-
- /*
- * User wants to treat as GET with no content. Go back to
- * check out the URL.
- */
- case 303:
- break;
-
- /*
- * Set the flag to retain the POST content and go back to check
- * out the URL. - FM
- */
- default:
- redirect_post_content = TRUE;
- }
-
- /* Lou's old comment: - FM */
- /* OK, now we've got the redirection URL temporarily stored
- in external variable redirecting_url, exported from HTMIME.c,
- since there's no straightforward way to do this in the library
- currently. Do the right thing. */
-
- status = HT_REDIRECTING;
-
- } else {
- status = traversal ? -1 : HT_LOADED;
- }
-
- } else {
- /*
- * If any data were received, treat as a complete transmission
- */
- status = HT_LOADED;
- }
-
- /*
- * Clean up
- */
- clean_up:
- FREE(line_buffer);
- FREE(line_kept_clean);
-
- done:
- /*
- * Clear out on exit, just in case.
- */
- reloading = FALSE;
-#ifdef USE_SSL
- FREE(connect_host);
- if (handle) {
- SSL_free(handle);
- SSL_handle = handle = NULL;
- }
-#endif /* USE_SSL */
- dump_server_status = server_status;
- return status;
-}
-
-/* Protocol descriptor
-*/
-#ifdef GLOBALDEF_IS_MACRO
-#define _HTTP_C_GLOBALDEF_1_INIT { "http", HTLoadHTTP, 0}
-GLOBALDEF(HTProtocol, HTTP, _HTTP_C_GLOBALDEF_1_INIT);
-#define _HTTP_C_GLOBALDEF_2_INIT { "https", HTLoadHTTP, 0}
-GLOBALDEF(HTProtocol, HTTPS, _HTTP_C_GLOBALDEF_2_INIT);
-#else
-GLOBALDEF HTProtocol HTTP =
-{"http", HTLoadHTTP, 0};
-GLOBALDEF HTProtocol HTTPS =
-{"https", HTLoadHTTP, 0};
-#endif /* GLOBALDEF_IS_MACRO */