diff options
Diffstat (limited to 'mdk-stage1/url.c')
-rw-r--r-- | mdk-stage1/url.c | 130 |
1 files changed, 100 insertions, 30 deletions
diff --git a/mdk-stage1/url.c b/mdk-stage1/url.c index 236782a50..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,6 +32,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> @@ -45,12 +46,14 @@ #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) @@ -134,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; } @@ -171,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; @@ -181,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; } @@ -312,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]; @@ -333,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); @@ -393,39 +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; + 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; - 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: @@ -433,7 +464,7 @@ 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")) { polls.fd = sock; polls.events = POLLIN; @@ -460,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) { @@ -480,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; } @@ -492,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 @@ -499,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); +} |