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.c89
1 files changed, 68 insertions, 21 deletions
diff --git a/mdk-stage1/url.c b/mdk-stage1/url.c
index 6187a6195..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,13 +137,7 @@ 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)) != (ssize_t)strlen(buf)) {
return FTPERR_SERVER_IO_ERROR;
@@ -401,18 +398,20 @@ char *str_ftp_error(int error)
}
-int http_download_file(char * hostname, char * remotename, int * size, char * proxyprotocol, char * proxyname, char * proxyport)
+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;
@@ -420,8 +419,15 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
http_server_name = proxyname;
http_server_port = atoi(proxyport);
} else {
- http_server_name = hostname;
- http_server_port = 80;
+ 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)",
@@ -432,6 +438,7 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock < 0) {
+ free(hostname);
return FTPERR_FAILED_CONNECT;
}
@@ -441,13 +448,15 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
if (connect(sock, (struct sockaddr *) &destPort, sizeof(destPort))) {
close(sock);
+ free(hostname);
return FTPERR_FAILED_CONNECT;
}
- buf = proxyprotocol ? asprintf_("GET %s://%s%s HTTP/0.9\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname)
- : asprintf_("GET %s HTTP/0.9\r\nHost: %s\r\n\r\n", remotename, hostname);
+ 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:
@@ -455,7 +464,7 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
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;
@@ -482,10 +491,9 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
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) {
@@ -503,10 +511,15 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
*end = '\0';
log_message("HTTP: server response '%s'", start);
- if (!strcmp(start, "404")) {
+ 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;
}
@@ -515,6 +528,34 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
}
}
+ 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
@@ -522,3 +563,9 @@ int http_download_file(char * hostname, char * remotename, int * size, char * pr
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);
+}