|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
#include "echoping.h"
|
|
|
|
|
|
|
|
#ifdef HTTP
|
|
|
|
#include "HTParse.h"
|
|
|
|
|
|
|
|
|
|
|
|
char big_recvline[MAXTOREAD];
|
|
|
|
|
|
|
|
char *
|
|
|
|
make_http_sendline(char *url, char *host, int port, int nocache)
|
|
|
|
{
|
|
|
|
short sport = (short) port;
|
|
|
|
int size = 350; /* Enough? RFC 2616, section 3.2.1 says 255 should
|
|
|
|
* be enough, although there is no hard limit. We
|
|
|
|
* reserve more because there * are the protocol
|
|
|
|
* elements, the HTTP headers, etc */
|
|
|
|
char *sendline = (char *) malloc(size);
|
|
|
|
char *hostname = (char *) malloc(size);
|
|
|
|
char *cache_directive = "";
|
|
|
|
int result;
|
|
|
|
#ifdef HTTP10
|
|
|
|
if (nocache)
|
|
|
|
cache_directive = "Pragma: no-cache\r\n"; /* RFC 1945, "Hypertext
|
|
|
|
* Transfer Protocol * --
|
|
|
|
* HTTP/1.0" */
|
|
|
|
result = snprintf(sendline, size,
|
|
|
|
"GET %s HTTP/1.0\r\nUser-Agent: Echoping/%s\r\n%s\r\n",
|
|
|
|
url, VERSION, cache_directive);
|
|
|
|
#else
|
|
|
|
if (nocache) {
|
|
|
|
if (nocache == 1)
|
|
|
|
cache_directive = "Cache-control: max-age=0\r\n"; /* Simply force a
|
|
|
|
* recheck with
|
|
|
|
* the server */
|
|
|
|
else
|
|
|
|
cache_directive = "Cache-control: no-cache\r\n"; /* RFC 2616
|
|
|
|
* "Hypertext
|
|
|
|
* Transfer Protocol
|
|
|
|
* -- HTTP/1.1" */
|
|
|
|
}
|
|
|
|
strncpy(hostname, HTParse(url, "", PARSE_HOST), size); /* See bug #1688940
|
|
|
|
* to see why we use
|
|
|
|
* * * strNcpy. */
|
|
|
|
hostname[size] = '\0'; /* Not added automatically */
|
|
|
|
if (!strcmp(hostname, ""))
|
|
|
|
snprintf(hostname, size, "%s:%d", host, sport);
|
|
|
|
result = snprintf(sendline, size,
|
|
|
|
"GET %s HTTP/1.1\r\nUser-Agent: Echoping/%s\r\nHost: %s\r\nConnection: close\r\n%s\r\n",
|
|
|
|
url, VERSION, hostname, cache_directive);
|
|
|
|
free(hostname);
|
|
|
|
#endif
|
|
|
|
if (result >= size)
|
|
|
|
err_quit("URL and/or hostname too long(s)");
|
|
|
|
return sendline;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
read_from_server(CHANNEL fs, short ssl, boolean accept_redirects)
|
|
|
|
{
|
|
|
|
int nr = 0;
|
|
|
|
int total = 0;
|
|
|
|
int reply_code;
|
|
|
|
int first_line = TRUE;
|
|
|
|
short body = FALSE;
|
|
|
|
#ifdef OPENSSL
|
|
|
|
int sslcode;
|
|
|
|
#endif
|
|
|
|
while (!body && !timeout_flag) {
|
|
|
|
if (!ssl)
|
|
|
|
nr = readline(fs.fs, big_recvline, MAXTOREAD, TRUE);
|
|
|
|
#ifdef OPENSSL
|
|
|
|
else {
|
|
|
|
nr = SSL_readline(fs.ssl, big_recvline, MAXTOREAD, TRUE);
|
|
|
|
if (nr == -1) {
|
|
|
|
sslcode = ERR_get_error();
|
|
|
|
err_ret("SSL_readline error: %s", ERR_error_string(sslcode, NULL));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef GNUTLS
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nr = TLS_readline(fs.tls, big_recvline, MAXTOREAD, TRUE);
|
|
|
|
if (nr == -1) {
|
|
|
|
err_ret("TLS_readline error: %s", gnutls_strerror(nr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* printf ("DEBUG: reading \"%s\"\n (%d chars)\n",
|
|
|
|
* big_recvline, nr);
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* HTTP replies should be separated by CR-LF. Unfortunately,
|
|
|
|
* some servers send only CR :-(
|
|
|
|
*/
|
|
|
|
body = ((nr == 2) || (nr == 1)); /* Empty line CR-LF seen */
|
|
|
|
if ((nr < 1) && (timeout_flag)) /* Probably a timeout */
|
|
|
|
return -1;
|
|
|
|
if (nr < 1)
|
|
|
|
/* SourceForge bug #109385 */
|
|
|
|
/* err_sys ("Error reading HTTP header"); */
|
|
|
|
return -1;
|
|
|
|
/*
|
|
|
|
* if ((int) big_recvline[nr-1] == 10) nr--;
|
|
|
|
*/
|
|
|
|
if (first_line) {
|
|
|
|
/* sscanf parse "HTTP/1.x 200" */
|
|
|
|
sscanf(big_recvline,"%*s %d", &reply_code);
|
|
|
|
|
|
|
|
/* 204 No Content is not an error, message body is empty by definition, see RFC 2616 */
|
|
|
|
if (reply_code == 204)
|
|
|
|
return 0; /* zero bytes is correct */
|
|
|
|
|
|
|
|
if (! (reply_code >= 200 && reply_code < 300) &&
|
|
|
|
! ((reply_code >= 300 && reply_code < 400) && accept_redirects))
|
|
|
|
/*
|
|
|
|
* Status codes beginning with 3 are not
|
|
|
|
* errors See bug #850674 and RFC 2616,
|
|
|
|
* section 10.3
|
|
|
|
*/
|
|
|
|
err_quit("HTTP error \"%s\"", big_recvline);
|
|
|
|
}
|
|
|
|
total = total + nr;
|
|
|
|
first_line = FALSE;
|
|
|
|
}
|
|
|
|
/* Read the body */
|
|
|
|
if (!ssl)
|
|
|
|
nr = readline(fs.fs, big_recvline, MAXTOREAD, FALSE);
|
|
|
|
#ifdef OPENSSL
|
|
|
|
else
|
|
|
|
nr = SSL_readline(fs.ssl, big_recvline, MAXTOREAD, FALSE);
|
|
|
|
#endif
|
|
|
|
#ifdef GNUTLS
|
|
|
|
else
|
|
|
|
nr = TLS_readline(fs.tls, big_recvline, MAXTOREAD, FALSE);
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* printf ("DEBUG: reading body \"%s\"\n (%d chars)\n", big_recvline,
|
|
|
|
* nr);
|
|
|
|
*/
|
|
|
|
if ((nr < 2) && (timeout_flag)) /* Probably a timeout */
|
|
|
|
return -1;
|
|
|
|
if (nr < 2) /* Hmm, if the body is empty, we'll get a * * * * *
|
|
|
|
* * * meaningless error message */
|
|
|
|
err_sys("Error reading HTTP body");
|
|
|
|
total = total + nr;
|
|
|
|
return total; /* How to do if we want only the body's size? */
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HTTP */
|