summaryrefslogtreecommitdiffstats
path: root/mdk-stage1/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdk-stage1/url.c')
-rw-r--r--mdk-stage1/url.c176
1 files changed, 114 insertions, 62 deletions
diff --git a/mdk-stage1/url.c b/mdk-stage1/url.c
index 0f919812b..14f1e25d6 100644
--- a/mdk-stage1/url.c
+++ b/mdk-stage1/url.c
@@ -1,7 +1,7 @@
/*
- * Guillaume Cottenceau (gc@mandrakesoft.com)
+ * Guillaume Cottenceau (gc)
*
- * Copyright 2000 MandrakeSoft
+ * Copyright 2000 Mandriva
*
* This software may be freely redistributed under the terms of the GNU
* public license.
@@ -32,33 +32,36 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <sys/poll.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
-#include "log.h"
#include "dns.h"
+#include "log.h"
#include "tools.h"
+#include "utils.h"
#include "url.h"
#define TIMEOUT_SECS 60
#define BUFFER_SIZE 4096
+#define HTTP_MAX_RECURSION 5
static int ftp_check_response(int sock, char ** str)
{
static char buf[BUFFER_SIZE + 1];
int bufLength = 0;
- fd_set emptySet, readSet;
+ struct pollfd polls;
char * chptr, * start;
- struct timeval timeout;
int bytesRead, rc = 0;
int doesContinue = 1;
char errorCode[4];
@@ -66,21 +69,10 @@ static int ftp_check_response(int sock, char ** str)
errorCode[0] = '\0';
do {
- FD_ZERO(&emptySet);
- FD_ZERO(&readSet);
- FD_SET(sock, &readSet);
-
- timeout.tv_sec = TIMEOUT_SECS;
- timeout.tv_usec = 0;
-
- rc = select(sock + 1, &readSet, &emptySet, &emptySet, &timeout);
- if (rc < 1) {
- if (rc==0)
- return FTPERR_BAD_SERVER_RESPONSE;
- else
- rc = FTPERR_UNKNOWN;
- } else
- rc = 0;
+ polls.fd = sock;
+ polls.events = POLLIN;
+ if (poll(&polls, 1, TIMEOUT_SECS*1000) != 1)
+ return FTPERR_BAD_SERVER_RESPONSE;
bytesRead = read(sock, buf + bufLength, sizeof(buf) - bufLength - 1);
@@ -125,7 +117,7 @@ static int ftp_check_response(int sock, char ** str)
} else {
bufLength = 0;
}
- } while (doesContinue && !rc);
+ } while (doesContinue);
if (*errorCode == '4' || *errorCode == '5') {
if (!strncmp(errorCode, "550", 3)) {
@@ -145,15 +137,9 @@ static int ftp_command(int sock, char * command, char * param)
char buf[500];
int rc;
- strcpy(buf, command);
- if (param) {
- strcat(buf, " ");
- strcat(buf, param);
- }
-
- strcat(buf, "\r\n");
+ snprintf(buf, sizeof(buf), "%s%s%s\r\n", command, param ? " " : "", param ? param : "");
- if (write(sock, buf, strlen(buf)) != strlen(buf)) {
+ if (write(sock, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
return FTPERR_SERVER_IO_ERROR;
}
@@ -163,17 +149,15 @@ static int ftp_command(int sock, char * command, char * param)
return 0;
}
-static int get_host_address(const char * host, struct in_addr * address)
+static int get_host_address(char * host, struct in_addr * address)
{
if (isdigit(host[0])) {
if (!inet_aton(host, address)) {
return FTPERR_BAD_HOST_ADDR;
}
} else {
- if (mygethostbyname((char *) host, address)) {
- errno = h_errno;
+ if (mygethostbyname(host, address))
return FTPERR_BAD_HOSTNAME;
- }
}
return 0;
@@ -184,7 +168,6 @@ int ftp_open_connection(char * host, char * name, char * password, char * proxy)
int sock;
struct in_addr serverAddress;
struct sockaddr_in destPort;
- char * buf;
int rc;
int port = 21;
@@ -194,9 +177,7 @@ int ftp_open_connection(char * host, char * name, char * password, char * proxy)
}
if (strcmp(proxy, "")) {
- buf = alloca(strlen(name) + strlen(host) + 5);
- sprintf(buf, "%s@%s", name, host);
- name = buf;
+ name = asprintf_("%s@%s", name, host);
host = proxy;
}
@@ -325,7 +306,7 @@ int ftp_data_command(int sock, char * command, char * param)
}
-static int ftp_get_filesize(int sock, char * remotename)
+int ftp_get_filesize(int sock, char * remotename)
{
int size = 0;
char buf[2000];
@@ -346,14 +327,14 @@ static int ftp_get_filesize(int sock, char * remotename)
return -1;
}
- fd = ftp_data_command(sock, "LIST", NULL);
+ fd = ftp_data_command(sock, "LIST", file);
if (fd <= 0) {
close(sock);
return -1;
}
ptr = buf;
- while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf))) != 0)
+ while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf) - 1)) != 0)
ptr += tot;
*ptr = '\0';
close(fd);
@@ -394,7 +375,6 @@ int ftp_start_download(int sock, char * remotename, int * size)
log_message("FTP: could not get filesize (trying to continue)");
*size = 0;
}
-
return ftp_data_command(sock, "RETR", remotename);
}
@@ -407,40 +387,76 @@ int ftp_end_data_command(int sock)
return 0;
}
-
-int http_download_file(char * hostname, char * remotename, int * size)
+
+char *str_ftp_error(int error)
+{
+ return error == FTPERR_PASSIVE_ERROR ? "error with passive connection" :
+ error == FTPERR_FAILED_CONNECT ? "couldn't connect to server" :
+ error == FTPERR_FILE_NOT_FOUND ? "file not found" :
+ error == FTPERR_BAD_SERVER_RESPONSE ? "bad server response (server too busy?)" :
+ NULL;
+}
+
+
+static int _http_download_file(char * hostport, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport, int recursion)
{
char * buf;
- struct timeval timeout;
+ char * hostname = strdup(hostport);
char headers[4096];
char * nextChar = headers;
- int checkedCode;
+ int statusCode;
struct in_addr serverAddress;
+ struct pollfd polls;
int sock;
int rc;
struct sockaddr_in destPort;
- fd_set readSet;
- char * header_content_length = "Content-Length: ";
+ const char * header_content_length = "Content-Length: ";
+ const char * header_location = "Location: http://";
+ char * http_server_name;
+ int http_server_port;
+
+ if (proxyprotocol) {
+ http_server_name = proxyname;
+ http_server_port = atoi(proxyport);
+ } else {
+ char *port = strchr(hostname, ':');
+ if (port) {
+ *port = '\0';
+ http_server_name = hostname;
+ http_server_port = atoi(++port);
+ } else {
+ http_server_name = hostname;
+ http_server_port = 80;
+ }
+ }
+
+ log_message("HTTP: connecting to server %s:%i (%s)",
+ http_server_name, http_server_port,
+ proxyprotocol ? "proxy" : "no proxy");
- if ((rc = get_host_address(hostname, &serverAddress))) return rc;
+ if ((rc = get_host_address(http_server_name, &serverAddress))) return rc;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock < 0) {
+ free(hostname);
return FTPERR_FAILED_CONNECT;
}
destPort.sin_family = AF_INET;
- destPort.sin_port = htons(80);
+ destPort.sin_port = htons(http_server_port);
destPort.sin_addr = serverAddress;
if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
close(sock);
+ free(hostname);
return FTPERR_FAILED_CONNECT;
}
- buf = alloca(strlen(remotename) + 20);
- sprintf(buf, "GET %s HTTP/0.9\r\n\r\n", remotename);
+ buf = proxyprotocol ? asprintf_("GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname)
+ : asprintf_("GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", remotename, hostname);
+
write(sock, buf, strlen(buf));
+ free(hostname);
/* This is fun; read the response a character at a time until we:
@@ -448,15 +464,12 @@ int http_download_file(char * hostname, char * remotename, int * size)
2) Get a \r\n\r\n, which means we're done */
*nextChar = '\0';
- checkedCode = 0;
+ statusCode = 0;
while (!strstr(headers, "\r\n\r\n")) {
- FD_ZERO(&readSet);
- FD_SET(sock, &readSet);
+ polls.fd = sock;
+ polls.events = POLLIN;
+ rc = poll(&polls, 1, TIMEOUT_SECS*1000);
- timeout.tv_sec = TIMEOUT_SECS;
- timeout.tv_usec = 0;
-
- rc = select(sock + 1, &readSet, NULL, NULL, &timeout);
if (rc == 0) {
close(sock);
return FTPERR_SERVER_TIMEOUT;
@@ -478,10 +491,9 @@ int http_download_file(char * hostname, char * remotename, int * size)
return FTPERR_SERVER_IO_ERROR;
}
- if (!checkedCode && strstr(headers, "\r\n")) {
+ if (!statusCode && strstr(headers, "\r\n")) {
char * start, * end;
- checkedCode = 1;
start = headers;
while (!isspace(*start) && *start) start++;
if (!*start) {
@@ -498,10 +510,16 @@ int http_download_file(char * hostname, char * remotename, int * size)
}
*end = '\0';
- if (!strcmp(start, "404")) {
+ log_message("HTTP: server response '%s'", start);
+ if (streq(start, "404")) {
close(sock);
return FTPERR_FILE_NOT_FOUND;
- } else if (strcmp(start, "200")) {
+ } else if (streq(start, "302")) {
+ log_message("HTTP: found, but document has moved");
+ statusCode = 302;
+ } else if (streq(start, "200")) {
+ statusCode = 200;
+ } else {
close(sock);
return FTPERR_BAD_SERVER_RESPONSE;
}
@@ -510,6 +528,34 @@ int http_download_file(char * hostname, char * remotename, int * size)
}
}
+ if (statusCode == 302) {
+ if (recursion >= HTTP_MAX_RECURSION) {
+ log_message("HTTP: too many levels of recursion, aborting");
+ close(sock);
+ return FTPERR_UNKNOWN;
+ }
+ if ((buf = strstr(headers, header_location))) {
+ char * found_host;
+ char *found_file;
+ found_host = buf + strlen(header_location);
+ if ((found_file = index(found_host, '/'))) {
+ if ((buf = index(found_file, '\r'))) {
+ buf[0] = '\0';
+ remotename = strdup(found_file);
+ found_file[0] = '\0';
+ hostname = strdup(found_host);
+ log_message("HTTP: redirected to new host \"%s\" and file \"%s\"", hostname, remotename);
+ }
+ }
+
+ }
+ /*
+ * don't fail if new URL can't be parsed,
+ * asking the same URL may work if the DNS server are doing round-robin
+ */
+ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1);
+ }
+
if ((buf = strstr(headers, header_content_length)))
*size = charstar_to_int(buf + strlen(header_content_length));
else
@@ -517,3 +563,9 @@ int http_download_file(char * hostname, char * remotename, int * size)
return sock;
}
+
+
+int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport)
+{
+ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, 0);
+}