summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
diff options
context:
space:
mode:
authoravsm <avsm@openbsd.org>2009-05-31 09:16:50 +0000
committeravsm <avsm@openbsd.org>2009-05-31 09:16:50 +0000
commit71d8b9891a55151b80e6b37e0fd1a8e75fa529d1 (patch)
treec255d1b19a357b3e9230c4aba23ed40fc48a798e /gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
parentindent (diff)
downloadwireguard-openbsd-71d8b9891a55151b80e6b37e0fd1a8e75fa529d1.tar.xz
wireguard-openbsd-71d8b9891a55151b80e6b37e0fd1a8e75fa529d1.zip
Update to lynx-2.8.6.rel5, with our local patches maintained where relevant.
tests from miod@ sthen@ jmc@ jsing@ two additional fixes from miod: - fix uninitialized stack variable use, leading to occasional crash. - modify the socklen_t test to include <sys/types.h>, fixes gcc2 build failures
Diffstat (limited to 'gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c')
-rw-r--r--gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c3426
1 files changed, 1790 insertions, 1636 deletions
diff --git a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
index fd3e11f76ac..e1a5bf538ad 100644
--- a/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
+++ b/gnu/usr.bin/lynx/WWW/Library/Implementation/HTTP.c
@@ -1,10 +1,10 @@
/* 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.
-*/
+ * ==========================
+ * 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>
@@ -39,40 +39,37 @@
#include <LYGlobalDefs.h>
#include <GridText.h>
#include <LYStrings.h>
+#include <LYrcFile.h>
#include <LYLeaks.h>
-struct _HTStream
-{
- HTStreamClass * isa;
+struct _HTStream {
+ HTStreamClass *isa;
};
-extern char * HTAppName; /* Application name: please supply */
-extern char * HTAppVersion; /* Application version: please supply */
-
-PUBLIC BOOL reloading = FALSE; /* Reloading => send no-cache pragma to proxy */
-PUBLIC char * redirecting_url = NULL; /* Location: value. */
-PUBLIC BOOL permanent_redirection = FALSE; /* Got 301 status? */
-PUBLIC BOOL redirect_post_content = FALSE; /* Don't convert to GET? */
+BOOL 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
-PUBLIC SSL_CTX * ssl_ctx = NULL; /* SSL ctx */
-PUBLIC SSL * SSL_handle = NULL;
-PUBLIC int ssl_okay;
+SSL_CTX *ssl_ctx = NULL; /* SSL ctx */
+SSL *SSL_handle = NULL;
+static int ssl_okay;
-PRIVATE void free_ssl_ctx NOARGS
+static void free_ssl_ctx(void)
{
if (ssl_ctx != NULL)
SSL_CTX_free(ssl_ctx);
}
-PRIVATE int HTSSLCallback(int preverify_ok, X509_STORE_CTX *x509_ctx)
+static int HTSSLCallback(int preverify_ok, X509_STORE_CTX * x509_ctx GCC_UNUSED)
{
char *msg = NULL;
int result = 1;
if (!(preverify_ok || ssl_okay || ssl_noprompt)) {
#ifdef USE_X509_SUPPORT
- HTSprintf0(&msg, "SSL error:%s-Continue?",
+ HTSprintf0(&msg, SSL_FORCED_PROMPT,
X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509_ctx)));
if (HTForcedPrompt(ssl_noprompt, msg, YES))
ssl_okay = 1;
@@ -85,11 +82,15 @@ PRIVATE int HTSSLCallback(int preverify_ok, X509_STORE_CTX *x509_ctx)
return result;
}
-PUBLIC SSL * HTGetSSLHandle NOARGS
+SSL *HTGetSSLHandle(void)
{
+#ifdef USE_GNUTLS_INCL
+ static char *certfile = NULL;
+#endif
+
if (ssl_ctx == NULL) {
/*
- * First time only.
+ * First time only.
*/
#if SSLEAY_VERSION_NUMBER < 0x0800
ssl_ctx = SSL_CTX_new();
@@ -101,42 +102,54 @@ PUBLIC SSL * HTGetSSLHandle NOARGS
SSL_CTX_set_default_verify_paths(ssl_ctx);
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, HTSSLCallback);
#endif /* SSLEAY_VERSION_NUMBER < 0x0800 */
+#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));
+ }
+#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));
+ return (SSL_new(ssl_ctx));
}
-PUBLIC void HTSSLInitPRNG NOARGS
+void HTSSLInitPRNG(void)
{
#if SSLEAY_VERSION_NUMBER >= 0x00905100
if (RAND_status() == 0) {
char rand_file[256];
time_t t;
int pid;
- long l,seed;
+ long l, seed;
t = time(NULL);
pid = getpid();
RAND_file_name(rand_file, 256);
- CTRACE((tfp,"HTTP: Seeding PRNG\n"));
- if(rand_file != NULL) {
+ CTRACE((tfp, "HTTP: Seeding PRNG\n"));
+ if (rand_file != NULL) {
/* Seed as much as 1024 bytes from RAND_file_name */
RAND_load_file(rand_file, 1024);
}
/* Seed in time (mod_ssl does this) */
- RAND_seed((unsigned char *)&t, sizeof(time_t));
+ RAND_seed((unsigned char *) &t, sizeof(time_t));
/* Seed in pid (mod_ssl does this) */
- RAND_seed((unsigned char *)&pid, sizeof(pid));
+ RAND_seed((unsigned char *) &pid, sizeof(pid));
/* Initialize system's random number generator */
- RAND_bytes((unsigned char *)&seed, sizeof(long));
-#if !defined(__OpenBSD__)
+ RAND_bytes((unsigned char *) &seed, sizeof(long));
+
+#if !defined(__OpenBSD__)
lynx_srand(seed);
#endif
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, sizeof(long));
+ RAND_seed((unsigned char *) &l, sizeof(long));
}
if (rand_file != NULL) {
/* Write a rand_file */
@@ -160,31 +173,30 @@ PUBLIC void HTSSLInitPRNG NOARGS
#define HTTP_NETCLOSE(a, b) (void)NETCLOSE(a)
#endif /* USE_SSL */
-#ifdef _WINDOWS /* 1997/11/06 (Thu) 13:00:08 */
+#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;
+ int fd;
+ char *buf;
+ int len;
} recv_data_t;
-PUBLIC int ws_read_per_sec = 0;
-PRIVATE int ws_errno = 0;
-
-PRIVATE DWORD g_total_times = 0;
-PRIVATE DWORD g_total_bytes = 0;
+int ws_read_per_sec = 0;
+static int ws_errno = 0;
+static DWORD g_total_times = 0;
+static DWORD g_total_bytes = 0;
-PUBLIC char * str_speed(void)
+char *str_speed(void)
{
static char buff[32];
if (ws_read_per_sec > 1000)
sprintf(buff, "%d.%03dkB", ws_read_per_sec / 1000,
- (ws_read_per_sec % 1000) );
+ (ws_read_per_sec % 1000));
else
sprintf(buff, "%3d", ws_read_per_sec);
@@ -194,27 +206,30 @@ PUBLIC char * str_speed(void)
/* The same like read, but takes care of EINTR and uses select to
timeout the stale connections. */
-PRIVATE int ws_read(int fd, char *buf, int len)
+static int ws_read(int fd, char *buf, int len)
{
- int res;
- int retry = 3;
+ int res;
+ int retry = 3;
- do {
+ do {
res = recv(fd, buf, len, 0);
if (WSAEWOULDBLOCK == WSAGetLastError()) {
- Sleep(100);
- if (retry-- > 0)
- continue;
+ Sleep(100);
+ if (retry-- > 0)
+ continue;
}
- } while (res == SOCKET_ERROR && SOCKET_ERRNO == EINTR);
+ } while (res == SOCKET_ERROR && SOCKET_ERRNO == EINTR);
- return res;
+ return res;
}
-PRIVATE void _thread_func (void *p)
+#define DWORD_ERR ((DWORD)-1)
+
+static DWORD __stdcall _thread_func(void *p)
{
- int i, val, ret;
- recv_data_t *q = (recv_data_t *)p;
+ DWORD result;
+ int i, val;
+ recv_data_t *q = (recv_data_t *) p;
i = 0;
i++;
@@ -224,36 +239,38 @@ PRIVATE void _thread_func (void *p)
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
- ret = -1;
+ result = DWORD_ERR;
} else {
- ret = val;
+ result = val;
}
- ExitThread((DWORD)ret);
+ return result;
}
/* The same like read, but takes care of EINTR and uses select to
timeout the stale connections. */
-PUBLIC int ws_netread(int fd, char *buf, int len)
+int ws_netread(int fd, char *buf, int len)
{
int i;
char buff[256];
- /* 1998/03/30 (Mon) 09:01:21 */
+ /* 1998/03/30 (Mon) 09:01:21 */
HANDLE hThread;
DWORD dwThreadID;
DWORD exitcode = 0;
- DWORD ret_val = -1, val, process_time, now_TickCount, save_TickCount;
+ DWORD ret_val = DWORD_ERR;
+ DWORD val, process_time, now_TickCount, save_TickCount;
static recv_data_t para;
extern int win32_check_interrupt(void); /* LYUtil.c */
- extern int lynx_timeout; /* LYMain.c */
+ extern int lynx_timeout; /* LYMain.c */
extern CRITICAL_SECTION critSec_READ; /* LYMain.c */
#define TICK 5
@@ -268,9 +285,9 @@ PUBLIC int ws_netread(int fd, char *buf, int len)
ws_read_per_sec = 0;
save_TickCount = GetTickCount();
- hThread = CreateThread((void *)NULL, STACK_SIZE,
- (LPTHREAD_START_ROUTINE)_thread_func,
- (void *)&para, 0UL, &dwThreadID);
+ hThread = CreateThread(NULL, STACK_SIZE,
+ _thread_func,
+ (void *) &para, 0UL, &dwThreadID);
if (hThread == 0) {
HTInfoMsg("CreateThread Failed (read)");
@@ -279,20 +296,20 @@ PUBLIC int ws_netread(int fd, char *buf, int len)
i = 0;
while (1) {
- val = WaitForSingleObject(hThread, 1000/TICK);
+ val = WaitForSingleObject(hThread, 1000 / TICK);
i++;
if (val == WAIT_FAILED) {
HTInfoMsg("Wait Failed");
- ret_val = -1;
+ ret_val = DWORD_ERR;
break;
} else if (val == WAIT_TIMEOUT) {
i++;
- if (i/TICK > (AlertSecs + 2)) {
+ if (i / TICK > (AlertSecs + 2)) {
sprintf(buff, "Read Waiting (%2d.%01d) for %d Bytes",
- i/TICK, (i%TICK) * 10 / TICK, len);
+ i / TICK, (i % TICK) * 10 / TICK, len);
SetConsoleTitle(buff);
}
- if (win32_check_interrupt() || ((i/TICK) > lynx_timeout)) {
+ if (win32_check_interrupt() || ((i / TICK) > lynx_timeout)) {
if (CloseHandle(hThread) == FALSE) {
HTInfoMsg("Thread terminate Failed");
}
@@ -302,42 +319,51 @@ PUBLIC int ws_netread(int fd, char *buf, int len)
}
} else if (val == WAIT_OBJECT_0) {
if (GetExitCodeThread(hThread, &exitcode) == FALSE) {
- exitcode = -1;
+ exitcode = DWORD_ERR;
}
if (CloseHandle(hThread) == FALSE) {
HTInfoMsg("Thread terminate Failed");
}
now_TickCount = GetTickCount();
- if (now_TickCount > save_TickCount)
+ 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;
- g_total_bytes += exitcode;
- if (g_total_bytes > 2000000) {
- ws_read_per_sec = g_total_bytes / (g_total_times/1000);
+ /*
+ * 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 = g_total_bytes * 1000 / g_total_times;
+ ws_read_per_sec *= 1000;
+ ws_read_per_sec /= g_total_times;
}
+
ret_val = exitcode;
break;
}
- } /* end while(1) */
+ } /* end while(1) */
- read_exit:
+ read_exit:
LeaveCriticalSection(&critSec_READ);
return ret_val;
}
-#endif
+#endif /* _WINDOWS */
/*
* Strip any username from the given string so we retain only the host.
- * If the
*/
-PRIVATE void strip_userid ARGS1(
- char *, host)
+static void strip_userid(char *host)
{
char *p1 = host;
char *p2 = strchr(host, '@');
@@ -348,7 +374,7 @@ PRIVATE void strip_userid ARGS1(
if ((fake = HTParse(host, "", PARSE_HOST)) != NULL) {
char *msg = NULL;
- CTRACE((tfp, "FIXME:%s\n", fake));
+ CTRACE((tfp, "parsed:%s\n", fake));
HTSprintf0(&msg, gettext("Address contains a username: %s"), host);
HTAlert(msg);
FREE(msg);
@@ -359,722 +385,864 @@ PRIVATE void strip_userid ARGS1(
}
}
+/*
+ * 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 = (program != 0);
+ }
+ return result;
+}
+
/* 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.
-**
-*/
-PRIVATE int HTLoadHTTP ARGS4 (
- CONST char *, arg,
- HTParentAnchor *, anAnchor,
- HTFormat, format_out,
- HTStream*, sink)
+ * ==============================
+ *
+ * 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)
{
- 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 */
- int 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 ? */
- char *METHOD;
-
- BOOL had_header; /* Have we had at least one header? */
- char *line_buffer;
- char *line_kept_clean;
- int real_length_of_line;
- 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;
- BOOL doing_redirect, already_retrying = FALSE;
- int len = 0;
+ static char *empty = "";
+ 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 */
+ int 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;
+
+ BOOL had_header; /* Have we had at least one header? */
+ char *line_buffer;
+ char *line_kept_clean;
+ int real_length_of_line = 0;
+ 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;
+ BOOL doing_redirect, already_retrying = FALSE;
+ int len = 0;
#ifdef USE_SSL
- 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 */
- char ssl_dn[256];
- char *cert_host;
- char *ssl_host;
- char *p;
- char *msg = NULL;
+ 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 */
+ 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;
+
+#ifdef USE_GNUTLS_INCL
+ int ret;
+ unsigned tls_status;
+#endif
+
#if SSLEAY_VERSION_NUMBER >= 0x0900
- BOOL try_tls = TRUE;
+ BOOL try_tls = TRUE;
#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
- SSL_handle = NULL;
+ SSL_handle = NULL;
#else
- void * handle = NULL;
+ 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;
- }
+ 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)) {
- if ((connect_url = strstr((url+7), "https://"))) {
- do_connect = TRUE;
- connect_host = HTParse(connect_url, "https", PARSE_HOST);
- if (!strchr(connect_host, ':')) {
- 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 (!strchr(connect_host, ':')) {
- 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));
- }
- }
+ if (using_proxy && !strncmp(url, "http://", 7)) {
+ if ((connect_url = strstr((url + 7), "https://"))) {
+ do_connect = TRUE;
+ connect_host = HTParse(connect_url, "https", PARSE_HOST);
+ if (!strchr(connect_host, ':')) {
+ 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 (!strchr(connect_host, ':')) {
+ 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;
- had_header = NO;
- length = 0;
- doing_redirect = FALSE;
- permanent_redirection = FALSE;
- redirect_post_content = FALSE;
- target = NULL;
- line_buffer = NULL;
- line_kept_clean = NULL;
+ 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;
+ had_header = NO;
+ 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);
+ 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;
+ 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);
+ 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) {
+ 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));
+ 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));
+ 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;
- }
-
-/* *sob* All this needs to be converted to handle binary strings
- * if we're going to be able to handle binary form uploads...
- * This is a nice long function as well. *sigh* -RJP
- */
-
+ 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);
+ 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);
#if SSLEAY_VERSION_NUMBER >= 0x0900
- if (!try_tls)
- handle->options|=SSL_OP_NO_TLSv1;
+ if (!try_tls)
+ handle->options |= SSL_OP_NO_TLSv1;
#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
- HTSSLInitPRNG();
- status = SSL_connect(handle);
+ HTSSLInitPRNG();
+ status = SSL_connect(handle);
- if (status <= 0) {
+ 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 {
- 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;
- }
+ if (try_tls) {
+ _HTProgress(gettext("Retrying connection without TLS."));
+ try_tls = FALSE;
+ if (did_connect)
+ HTTP_NETCLOSE(s, handle);
+ goto try_again;
+ } 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;
+ }
#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;
+ 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 */
- }
-
- X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(handle)),
- ssl_dn, sizeof(ssl_dn));
- if ((cert_host = strstr(ssl_dn, "/CN=")) == NULL) {
- HTSprintf0(&msg,
- gettext("SSL error:Can't find common name in certificate-Continue?"));
- if (! HTForcedPrompt(ssl_noprompt, msg, YES)) {
- status = HT_NOT_LOADED;
- FREE(msg);
- goto done;
- }
- } else {
- cert_host += 4;
- if ((p = strchr(cert_host, '/')) != NULL)
- *p = '\0';
- if ((p = strchr(cert_host, ':')) != NULL)
- *p = '\0';
- ssl_host = HTParse(url, "", PARSE_HOST);
- if ((p = strchr(ssl_host, ':')) != NULL)
- *p = '\0';
- if (strcasecomp(ssl_host, cert_host)) {
- HTSprintf0(&msg,
- gettext("SSL error:host(%s)!=cert(%s)-Continue?"),
- ssl_host,
- cert_host);
- if (! HTForcedPrompt(ssl_noprompt, msg, YES)) {
- status = HT_NOT_LOADED;
- FREE(msg);
- goto done;
- }
- }
- }
-
- 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);
- }
+ }
+#ifdef USE_GNUTLS_INCL
+ ret = gnutls_certificate_verify_peers2(handle->gnutls_state, &tls_status);
+ if ((ret < 0) || tls_status) {
+ int flag_continue = 1;
+ char *msg2;
+
+ 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_SIGNER_NOT_FOUND) {
+ msg2 = gettext("the certificate has no known issuer");
+ } 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
+
+ X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(handle)),
+#ifndef USE_GNUTLS_INCL
+ ssl_dn, sizeof(ssl_dn));
+#else
+ ssl_dn + 1, 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;
+ ssl_all_cns = NULL;
+ /* get host we're connecting to */
+ ssl_host = HTParse(url, "", PARSE_HOST);
+ /* strip port number */
+ if ((p = strchr(ssl_host, ':')) != NULL)
+ *p = '\0';
+ /* validate all CNs found in DN */
+ 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;
+ /* strip port number */
+ if ((p = strchr(cert_host, ':')) != NULL)
+ *p = '\0';
+ /* verify this CN */
+ if (!strcasecomp_asterisk(ssl_host, cert_host)) {
+ status_sslcertcheck = 2; /* 2 = verified peer */
+ /* I think this is cool to have in the logs --mirabilos */
+ 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, cert_host);
+ } else {
+ StrAllocCat(ssl_all_cns, ":");
+ StrAllocCat(ssl_all_cns, cert_host);
+ }
+ /* 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 */
+ }
+
+ /* 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("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));
+ /* 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
+ 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 (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.
- */
+ /*
+ * 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);
- }
+ 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);
+ 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=%ld",
- pres->quality, pres->maxbytes);
- } else {
- sprintf(temp, ";q=%4.3f", pres->quality);
- }
- } else if (pres->maxbytes > 0) {
- sprintf(temp, ";mxb=%ld", pres->maxbytes);
- } else {
- temp[0] = '\0';
- }
- HTSprintf0(&linebuf, "%s%s%s",
- (first_Accept ?
- "Accept: " : ", "),
- HTAtom_name(pres->rep),
- temp);
- len += strlen(linebuf);
- if (len > 252 && !first_Accept) {
- BStrCat0(command, crlf);
- HTSprintf0(&linebuf, "Accept: %s%s",
- HTAtom_name(pres->rep),
- temp);
- len = strlen(linebuf);
- }
- BStrCat0(command, linebuf);
- first_Accept = FALSE;
- }
- }
- HTBprintf(&command, "%s*/*;q=0.01%c%c",
- (first_Accept ?
- "Accept: " : ", "), CR, LF);
- first_Accept = FALSE;
- len = 0;
-
- /*
- * 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;
-#if defined(USE_ZLIB) || defined(GZIP_PATH)
- StrAllocCopy(list, "gzip");
-#endif
-#if defined(USE_ZLIB) || defined(COMPRESS_PATH)
- if (list != 0)
- StrAllocCat(list, ", ");
- StrAllocCat(list, "compress");
-#endif
- 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);
- }
+ 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=%ld",
+ pres->quality, pres->maxbytes);
+ } else {
+ sprintf(temp, ";q=%4.3f", pres->quality);
+ }
+ } else if (pres->maxbytes > 0) {
+ sprintf(temp, ";mxb=%ld", pres->maxbytes);
+ } else {
+ temp[0] = '\0';
+ }
+ HTSprintf0(&linebuf, "%s%s%s",
+ (first_Accept ?
+ "Accept: " : ", "),
+ HTAtom_name(pres->rep),
+ temp);
+ len += strlen(linebuf);
+ if (len > 252 && !first_Accept) {
+ BStrCat0(command, crlf);
+ HTSprintf0(&linebuf, "Accept: %s%s",
+ HTAtom_name(pres->rep),
+ temp);
+ len = strlen(linebuf);
+ }
+ BStrCat0(command, linebuf);
+ first_Accept = FALSE;
+ }
+ }
+ HTBprintf(&command, "%s*/*;q=0.01%c%c",
+ (first_Accept ?
+ "Accept: " : ", "), CR, LF);
+ first_Accept = FALSE;
+ len = 0;
+
+ /*
+ * 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);
- }
+ /*
+ * 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 (LYUserAgent && *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(), "")) {
- char *cp = LYRequestReferer;
- if (!cp) cp = HTLoadedDocumentURL(); /* @@@ Try both? - kw */
- BStrCat0(command, "Referer: ");
- if (isLYNXIMGMAP(cp)) {
- char *cp1 = trimPoundSelector(cp);
- BStrCat0(command, cp + LEN_LYNXIMGMAP);
- restorePoundSelector(cp1);
- } 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 = strchr(hostname, ':'))) {
- *(colon++) = '\0'; /* Chop off port number */
- portnumber = atoi(colon);
- } else if (!strncmp(arg, "https", 5)) {
- portnumber = HTTPS_PORT;
- } else {
- portnumber = HTTP_PORT;
+ /*
+ * 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);
}
- /*
- ** Add Authorization, Proxy-Authorization,
- ** and/or Cookie headers, if applicable.
- */
- if (using_proxy) {
+ if (LYUserAgent && *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 = strchr(hostname, ':'))) {
+ *(colon++) = '\0'; /* Chop off port number */
+ portnumber = atoi(colon);
+ } else if (!strncmp(arg, "https", 5)) {
+ portnumber = HTTPS_PORT;
+ } else {
+ portnumber = HTTP_PORT;
+ }
+
/*
- ** 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 (host2) {
- if ((colon = strchr(host2, ':')) != NULL) {
- /* Use non-default port number */
- *colon = '\0';
- colon++;
- port2 = atoi(colon);
+ * 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 (host2) {
+ if ((colon = strchr(host2, ':')) != NULL) {
+ /* Use non-default port number */
+ *colon = '\0';
+ colon++;
+ port2 = atoi(colon);
+ }
+ }
+ /*
+ * This composeAuth() does file access, i.e., for the ultimate
+ * target of the request. - AJL
+ */
+ auth_proxy = NO;
+ if ((auth = HTAA_composeAuth(host2, port2, path2,
+ auth_proxy)) != NULL &&
+ *auth != '\0') {
+ /*
+ * If auth is not NULL nor zero-length, it's an
+ * Authorization header to be included. - FM
+ */
+ HTBprintf(&command, "%s%c%c", auth, CR, LF);
+ CTRACE((tfp, "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)) {
+ 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;
+ }
+ } else {
+ CTRACE((tfp, "HTTP: Not sending authorization (yet).\n"));
+ }
+ /*
+ * 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;
}
/*
- ** This composeAuth() does file access, i.e., for
- ** the ultimate target of the request. - AJL
- */
- auth_proxy = NO;
- if ((auth = HTAA_composeAuth(host2, port2, path2,
+ * 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 header to be included. - FM
- */
+ * 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, "HTTP: Sending authorization: %s\n", auth));
+ 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)) {
- show_401 = TRUE;
+ * 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);
-#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;
}
} else {
- CTRACE((tfp, "HTTP: Not sending authorization (yet).\n"));
+ CTRACE((tfp, (auth_proxy ?
+ "HTTP: Not sending proxy authorization (yet).\n" :
+ "HTTP: Not sending authorization (yet).\n")));
}
- /*
- ** 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(hostname);
+ FREE(docname);
}
- 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);
- }
- auth_proxy = NO;
- }
+ auth_proxy = NO;
+ }
if (
#ifdef USE_SSL
- !do_connect &&
+ !do_connect &&
#endif /* USE_SSL */
- do_post) {
+ do_post) {
CTRACE((tfp, "HTTP: Doing post, content-type '%s'\n",
- anAnchor->post_content_type
- ? anAnchor->post_content_type
- : "lose"));
+ 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",
+ 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,
+ ? BStrLen(anAnchor->post_data)
+ : 0,
CR, LF);
BStrCat0(command, crlf); /* Blank line means "end" of headers */
BStrCat(command, anAnchor->post_data);
- }
- else
+ } else
BStrCat0(command, crlf); /* Blank line means "end" of headers */
if (TRACE) {
@@ -1082,702 +1250,748 @@ use_tunnel:
trace_bstring(command);
#ifdef USE_SSL
CTRACE((tfp, "%s",
- (anAnchor->post_data && !do_connect ? crlf : "")));
+ (anAnchor->post_data && !do_connect ? crlf : "")));
#else
CTRACE((tfp, "%s",
- (anAnchor->post_data ? crlf : "")));
+ (anAnchor->post_data ? crlf : "")));
#endif /* USE_SSL */
CTRACE((tfp, "----------------------------------\n"));
}
- _HTProgress (gettext("Sending HTTP request."));
+ _HTProgress(gettext("Sending HTTP request."));
-#ifdef NOT_ASCII /* S/390 -- gil -- 0548 */
- { char *p;
+#ifdef NOT_ASCII /* S/390 -- gil -- 0548 */
+ {
+ char *p2;
- for ( p = BStrData(command); p < BStrData(command) + BStrLen(command); p++ )
- *p = TOASCII(*p);
- }
+ for (p2 = BStrData(command);
+ p2 < BStrData(command) + BStrLen(command);
+ p2++)
+ *p2 = TOASCII(*p2);
+ }
#endif /* NOT_ASCII */
- status = 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) {
+ status = 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);
+ * 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, buffer_length);
- if (line_buffer == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
-
- HTReadProgress (bytes_already_read = 0, 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, (buffer_length * sizeof(char)));
- if (line_buffer == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
+ } 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: 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) {
+ }
+
+ 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, buffer_length);
+
+ if (line_buffer == NULL)
+ outofmem(__FILE__, "HTLoadHTTP");
+
+ HTReadProgress(bytes_already_read = 0, 0);
+ do { /* Loop to read in the first line */
/*
- * Retry if we get nothing back too.
- * Bomb out if we get nothing twice.
+ * Extend line buffer if necessary for those crazy WAIS URLs ;-)
*/
- 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);
+ if (buffer_length - length < LINE_EXTEND_THRESH) {
+ buffer_length = buffer_length + buffer_length;
+ line_buffer =
+ (char *) realloc(line_buffer, (buffer_length * sizeof(char)));
- extensions = NO;
- already_retrying = TRUE;
- _HTProgress (RETRYING_AS_HTTP0);
- goto try_again;
- } 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;
+ 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);
-#ifdef NOT_ASCII /* S/390 -- gil -- 0564 */
- { char *p;
+ extensions = NO;
+ already_retrying = TRUE;
+ _HTProgress(RETRYING_AS_HTTP0);
+ goto try_again;
+ } 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 ( p = line_buffer + length; p < line_buffer + length + status; p++ )
- *p = FROMASCII(*p);
- }
+ 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, 0);
+ bytes_already_read += status;
+ HTReadProgress(bytes_already_read, 0);
-#ifdef UCX /* UCX returns -1 on EOF */
- if (status == 0 || status == -1)
+#ifdef UCX /* UCX returns -1 on EOF */
+ if (status == 0 || status == -1)
#else
- if (status == 0)
+ if (status == 0)
#endif
- {
- end_of_file = YES;
- break;
- }
- line_buffer[length+status] = 0;
-
- if (line_buffer) {
- FREE(line_kept_clean);
- line_kept_clean = (char *)malloc(buffer_length * sizeof(char));
- if (line_kept_clean == NULL)
- outofmem(__FILE__, "HTLoadHTTP");
- memcpy(line_kept_clean, line_buffer, buffer_length);
- real_length_of_line = length + status;
+ {
+ end_of_file = YES;
+ break;
+ }
+ line_buffer[length + status] = 0;
+
+ if (line_buffer) {
+ FREE(line_kept_clean);
+ line_kept_clean = (char *) malloc(buffer_length * sizeof(char));
+
+ if (line_kept_clean == NULL)
+ outofmem(__FILE__, "HTLoadHTTP");
+ memcpy(line_kept_clean, line_buffer, buffer_length);
+ real_length_of_line = length + status;
+ }
+
+ 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 */
- eol = strchr(line_buffer + length, LF);
- /* Do we *really* want to do this? */
- if (eol && eol != line_buffer && *(eol-1) == CR)
- *(eol-1) = ' ';
+ /* save total length, in case we decide later to show it all - kw */
+ rawlength = length;
- length = length + status;
+ /* 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;
- /* 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);
- }
+ 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);
- }
+ 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,
+ * Rule out a non-HTTP/1.n reply as best we can.
*/
- HTAtom * encoding;
+ 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"));
+ 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)) {
+ format_in = HTFileFormat(url, &encoding, NULL);
/*
- ** 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",
+ * 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
- */
- start_of_data = eol ? eol + 1 : "";
- length = eol ? length - (start_of_data - line_buffer) : 0;
+ 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"));
- /*
- ** 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';
+ /*
+ * 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
+ */
+ start_of_data = eol ? eol + 1 : empty;
+ length = eol ? length - (start_of_data - line_buffer) : 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;
+ * 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';
- case 2:
/*
- ** Good: Got MIME object! (Successful) - FM
- */
- if (do_head) {
+ * Take appropriate actions based on the status. - FM
+ */
+ switch (server_status / 100) {
+ case 1:
/*
- * If HEAD was requested, show headers (and possibly
- * bogus body) for all 2xx status codes as text/plain - KW
+ * 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
*/
- HTProgress(line_buffer);
+ HTAlert(gettext("Got unexpected Informational Status."));
+ do_head = TRUE;
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:
+ case 2:
/*
- * 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
+ * Good: Got MIME object! (Successful) - FM
*/
- HTAlert(gettext("Request fulfilled. Reset Content."));
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto clean_up;
+ 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 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;
+ 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;
- default:
- /*
- * 200 OK.
- * 201 Created.
- * 202 Accepted.
- * 203 Non-Authoritative Information.
- * > 206 is unknown.
- * All should return something to display.
- */
+ 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",
+ 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)) {
+ 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;
+ bytes_already_read = 0;
+ had_header = NO;
+ length = 0;
+ doing_redirect = FALSE;
+ permanent_redirection = FALSE;
+ target = NULL;
CTRACE((tfp,
- " Will attempt handshake and snews connection.\n"));
- status = HTNewsProxyConnect(s, url, anAnchor,
- format_out, sink);
- goto done;
+ " Will attempt handshake and resubmit headers.\n"));
+ goto use_tunnel;
}
- did_connect = TRUE;
- already_retrying = TRUE;
- eol = 0;
- bytes_already_read = 0;
- had_header = NO;
- 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);
+ HTProgress(line_buffer);
+ } /* case 2 switch */
break;
- }
- if (server_status == 300) { /* Multiple Choices */
+ case 3:
/*
- * 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
+ * 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.
*/
- HTAlert(line_buffer);
- if (traversal) {
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
- }
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
+ if (no_url_redirection || do_head || keep_mime_headers) {
/*
- * Convert a download request to
- * a presentation request for
- * interactive users. - FM
+ * If any of these flags are set, we do not redirect, but
+ * instead show what was returned to the user as
+ * text/plain. - FM
*/
- format_out = WWW_PRESENT;
+ HTProgress(line_buffer);
+ break;
}
- 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 == 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 == 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 (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 (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
+
+ if (server_status == 305 ||
+ server_status == 306 ||
+ server_status > 307) {
/*
- * Convert a download request to
- * a presentation request for
- * interactive users. - FM
+ * Show user the content, if any, for 305, 306, or unknown
+ * status. - FM
*/
- format_out = WWW_PRESENT;
+ 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;
}
- 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 orgin 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
+ * 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 (show_401)
- break;
- if (HTAA_shouldRetryWithAuth(start_of_data, 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;
+ {
+ 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;
}
- 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;
+ 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;
+ }
}
-#endif /* USE_SSL */
- goto try_again;
- } else if (!(traversal || dump_output_immediately) &&
- HTConfirm(gettext("Show the 401 message body?"))) {
+ doing_redirect = TRUE;
+
break;
- } else {
- if (traversal || dump_output_immediately)
- HTAlert(FAILED_RETRY_WITH_AUTH);
- HTTP_NETCLOSE(s, handle);
- status = -1;
- goto clean_up;
}
- case 407:
+ case 4:
/*
- * 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
+ * "I think I goofed!" (Client Error) - FM
*/
- if (!using_proxy || show_407)
- break;
- if (HTAA_shouldRetryWithAuth(start_of_data, length, s, YES)) {
+ switch (server_status) {
+ case 401: /* Unauthorized */
+ /*
+ * Authorization for orgin 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, length, s, NO)) {
- 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;
+ 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;
}
- CTRACE((tfp, "%s %d %s\n",
+ 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, 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?"))) {
+ _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 done;
+
+ 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
+ * 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 4 switch */
+ break;
- case 408:
+ case 5:
/*
- * Request Timeout. Show the status message
- * and restore the current document. - FM
+ * "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);
- HTTP_NETCLOSE(s, handle);
- status = HT_NO_DATA;
- goto done;
+ 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:
+ 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
+ * 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);
@@ -1787,354 +2001,294 @@ use_tunnel:
if (!dump_output_immediately &&
format_out == HTAtom_for("www/download")) {
/*
- * Convert a download request to
- * a presentation request for
- * interactive users. - FM
+ * Convert a download request to a presentation request for
+ * interactive users. - FM
*/
format_out = WWW_PRESENT;
}
break;
- } /* case 4 switch */
- break;
+ } /* Switch on server_status/100 */
+
+ } /* Full HTTP reply */
+ } /* scope of fields */
- case 5:
+ /*
+ * 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) {
/*
- ** "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")) {
+ * 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
+ */
+/* (*target->isa->_abort)(target, NULL); *//* already done in HTCopy */
+ 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"));
/*
- * Convert a download request to
- * a presentation request for
- * interactive users. - FM
+ * May as well consider it an interrupt -- right?
*/
- format_out = WWW_PRESENT;
+ 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;
}
- break;
+ }
+ }
+
+ /*
+ * 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);
+ }
- default:
+ if (doing_redirect) {
+ if (redirecting_url) {
/*
- ** 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;
+ * 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;
}
- if (!dump_output_immediately &&
- format_out == HTAtom_for("www/download")) {
+ HTProgress(line_buffer);
+ if (server_status == 305) { /* Use Proxy */
/*
- * Convert a download request to
- * a presentation request for
- * interactive users. - FM
+ * Make sure the proxy field ends with a slash. - FM
*/
- format_out = WWW_PRESENT;
+ 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));
}
- 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 || 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
- */
- /* (*target->isa->_abort)(target, NULL); */ /* already done in HTCopy */
- 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:
- doing_redirect = FALSE;
- 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.
- */
- do_head = FALSE;
- do_post = FALSE;
- reloading = FALSE;
+ 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:
+ doing_redirect = FALSE;
+ 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.
+ */
+ do_head = FALSE;
+ do_post = FALSE;
+ reloading = FALSE;
#ifdef USE_SSL
- do_connect = FALSE;
- did_connect = FALSE;
- FREE(connect_host);
- if (handle) {
- SSL_free(handle);
- SSL_handle = handle = NULL;
- }
+ do_connect = FALSE;
+ did_connect = FALSE;
+ FREE(connect_host);
+ if (handle) {
+ SSL_free(handle);
+ SSL_handle = handle = NULL;
+ }
#endif /* USE_SSL */
- return 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);
+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);
+GLOBALDEF(HTProtocol, HTTPS, _HTTP_C_GLOBALDEF_2_INIT);
#else
-GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0 };
-GLOBALDEF PUBLIC HTProtocol HTTPS = { "https", HTLoadHTTP, 0 };
+GLOBALDEF HTProtocol HTTP =
+{"http", HTLoadHTTP, 0};
+GLOBALDEF HTProtocol HTTPS =
+{"https", HTLoadHTTP, 0};
#endif /* GLOBALDEF_IS_MACRO */