diff options
Diffstat (limited to 'mdk-stage1/url.c')
| -rw-r--r-- | mdk-stage1/url.c | 176 |
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); +} |
