This is a patch file for "aget" 0.4. This file makes numerous bug fixes and tweaks. a. Add support for HTTP redirection b. Add support for URLs w/port numbers [http://hostname:port] c. Fix support for large HTTP headers d. Fix an "errno.h" problem that caused build-time errors e. Detect problems related to HTTP Content-Length field f. Turn verbose messages off by default [-d turns them on] g. Report speed results whether or not verbose mode is enabled h. Add aliases "-o" and "-O" for output-filename switch [-l] i. Fix a bug related to URLs of the form "http://hostname/" j. Use a fixed-width percentage-completed field (looks better) k. Tweak spelling l. Fix builds using newer releases of "glibc" m. Fix builds using "gcc" 10 --- aget-0.4.old/Aget.c +++ aget-0.4/Aget.c @@ -31,14 +31,16 @@ extern int bwritten; extern pthread_t hthread; -extern int errno; +#include void get(struct request *req) { int i, ret, fd, diff_sec, nok = 0; long soffset, foffset; + char *cp; char *fmt; + char *ofname; if (req->proto == PROTO_HTTP) http_head_req(req); @@ -62,22 +64,21 @@ Log("Downloading %s (%d bytes) from site %s(%s:%d). Number of Threads: %d", req->url, req->clength, req->host, req->ip, req->port, nthreads); - if (strlen(req->lfile) != 0) { - if ((fd = open(req->lfile, O_CREAT | O_RDWR, S_IRWXU)) == -1) { - fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno)); - exit(1); - } - - } else { - if ((fd = open(req->file, O_CREAT | O_RDWR, S_IRWXU)) == -1) { - fprintf(stderr, "get: cannot open file %s for writing: %s\n", req->lfile, strerror(errno)); - exit(1); - } + ofname = strlen (req->lfile) ? req->lfile : req->file; + if (!ofname || !*ofname) ofname = "index.html"; + + if ((fd = open (ofname, O_CREAT | O_RDWR, 0644)) == -1) + { + fprintf (stderr, "aget: Can't open %s for writing: %s\n", + ofname, strerror (errno)); + exit (1); } - if ((lseek(fd, req->clength - 1, SEEK_SET)) == -1) { - fprintf(stderr, "get: couldn't lseek: %s\n", strerror(errno)); - exit(1); + if ((lseek (fd, req->clength - 1, SEEK_SET)) == -1) + { + fprintf (stderr, "aget: Can't lseek: [%s %d %ld] %s\n", + ofname, fd, (long) req->clength-1, strerror (errno)); + exit (1); } if ((write(fd, "0", 1)) == -1) { @@ -125,9 +126,13 @@ if ((diff_sec = t_finish - t_start) == 0) diff_sec = 1; /* Avoid division by zero */ - Log("Download completed, job completed in %d seconds. (%d Kb/sec)", - diff_sec, (req->clength / diff_sec) / 1024); - Log("Shutting down..."); + cp = (diff_sec == 1) ? "second" : "seconds"; + fflush (stderr); + fflush (stdout); + printf ("Download completed in %d %s (%d Kb/sec)\n" , + diff_sec, cp, (req->clength / diff_sec) / 1024); + + Log("Shutting down..."); close(fd); } --- aget-0.4.old/Defs.h +++ aget-0.4/Defs.h @@ -3,11 +3,11 @@ enum { - GETREQSIZ = 256, + GETREQSIZ = 8192, GETRECVSIZ = 8192, - HEADREQSIZ = 512, - MAXURLSIZ = 1024, - MAXHOSTSIZ = 1024, + HEADREQSIZ = 8192, + MAXURLSIZ = 2048, + MAXHOSTSIZ = 2048, MAXIPSIZ = 16, MAXBUFSIZ = 512, MAXTHREADS = 25, @@ -22,7 +22,7 @@ }; -#define PROGVERSION "EnderUNIX Aget v0.4" +#define PROGVERSION "aget unofficial release 070928" #define HEADREQ "HEAD %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n" #define GETREQ "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\nRange: bytes=%ld-\r\nConnection: close\r\n\r\n" --- aget-0.4.old/Download.c +++ aget-0.4/Download.c @@ -29,7 +29,7 @@ extern sigset_t signal_set; -extern int errno; +#include unsigned int bwritten = 0; pthread_mutex_t bwritten_mutex = PTHREAD_MUTEX_INITIALIZER; --- aget-0.4.old/Head.c +++ aget-0.4/Head.c @@ -11,6 +11,8 @@ #include #include +#include +extern char *fullurl; #include #include @@ -30,7 +32,7 @@ #include "Misc.h" -extern int errno; +#include extern int h_errno; @@ -44,7 +46,7 @@ char *tok; char *s; int clength; - + static int tries = 0; sbuf = (char *)calloc(HEADREQSIZ + strlen(req->url), sizeof(char)); rbuf = (char *)calloc(HEADREQSIZ, sizeof(char)); @@ -87,6 +89,49 @@ handleHttpRetcode(rbuf); +/* ---------------------------------------------------------------- */ + +/* This code is experimental. It's an attempt to add redirection */ +/* support to "aget". */ + + if (strstr (rbuf, "HTTP/1.1 30") != NULL) + { + if (++tries > 5) + { + fprintf (stderr, + "Error: Redirection nested too deeply\n"); + exit (1); + } + + if ((tok = strstr (rbuf, "Location:")) != NULL) + { + static char new_url [5120]; + tok += 9; + while ((*tok == ' ') || (*tok == '\t')) tok++; + + if (strncmp (tok, "http://", 7) == 0) + { + extern jmp_buf jmpbuf; + char *abc = tok; + tok += 7; + while (*tok > ' ') tok++; + *tok = '\0'; + + if (strlen (abc) < sizeof (new_url)) + { + strcpy (new_url, abc); + fullurl = new_url; + longjmp (jmpbuf, 1); + } + } + } + + fprintf (stderr, "Error: unsupported redirection\n"); + exit (1); + } + +/* ---------------------------------------------------------------- */ + tok = strtok(rbuf, "\r\n"); if ((strstr(tok, "HTTP/1.1 200")) != NULL) { while ((tok = strtok(NULL, "\r\n")) != NULL) { @@ -100,4 +145,12 @@ free(sbuf); free(rbuf); + if (!req->clength) + { + fprintf (stderr, "%s", +"Error: The remote server didn't specify Content-Length, or it was"); + fprintf (stderr, "%s", +" zero.\n\"aget\" doesn't support objects of this type.\n"); + exit (1); + } } --- aget-0.4.old/Makefile +++ aget-0.4/Makefile @@ -2,7 +2,7 @@ # http://www.enderunix.org/aget/ OBJS = main.o Aget.o Misc.o Head.o Signal.o Download.o Resume.o -CFLAGS = -g -Wall -W -pedantic +CFLAGS = -O2 -Wall -W -pedantic -D_GNU_SOURCE=1 LDFLAGS = -pthread CC = gcc STRIP = strip --- aget-0.4.old/Misc.c +++ aget-0.4/Misc.c @@ -35,12 +35,35 @@ s = url + 7; /* Jump pass http:// part */ - for (i = 0; *s != '/'; i++, s++) { + for (i = 0; *s && (*s != '/'); i++, s++) { + int pwflag = 0; + if (i > MAXHOSTSIZ) { fprintf(stderr, "Error: Cannot get hostname from URL...\n"); exit(1); } - if (*s == ':') { /* If user/pass is supplied like; http://murat:12345@x.y.com/url.html */ + + if (*s == ':') + { /* BUG FIX */ + int lcdigit; + int ncslash; + char *t; + for (t = s+1; (*t >= '0') && (*t <= '9'); t++) {} + + lcdigit = (t [-1] >= '0') && (t [-1] <= '9'); + ncslash = (*t == '/') || (*t == '\0'); + pwflag = (lcdigit && ncslash) ? 0 : 1; + + if (!pwflag) + { + req->port = atoi (s+1); + s = t; + break; + } + } + + if ((*s == ':') && pwflag) + { /* If user/pass is supplied like; http://murat:12345@x.y.com/url.html */ while(*s != '/') { req->username[j++] = *--s; i--; @@ -117,19 +140,31 @@ return (part * (total / nthreads)); } - void usage() { - fprintf(stderr, "usage: aget [options] url\n"); - fprintf(stderr, "\toptions:\n"); - fprintf(stderr, "\t\t-p port number\n"); - fprintf(stderr, "\t\t-l local file name\n"); - fprintf(stderr, "\t\t-n suggested number of threads\n"); - fprintf(stderr, "\t\t-f force using suggested number of threads\n"); - fprintf(stderr, "\t\t-h this screen\n"); - fprintf(stderr, "\t\t-v version info\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "http//www.enderunix.org/aget/\n"); + fprintf (stderr, + "%s - Accelerated HTTP downloader\n\n", PROGVERSION); + + fprintf (stderr, "Usage:\taget -options URL\n"); + fprintf (stderr, "Options:\n"); + + fprintf (stderr, + "\t-d Enable \"debug\" output\n"); + fprintf (stderr, + "\t-fn NUMBER Force indicated number of threads\n"); + fprintf (stderr, + "\t-h Display this screen\n"); + fprintf (stderr, + "\t-n NUMBER Suggest indicated number of threads\n"); + fprintf (stderr, + "\t-o NAME Set name of output file\n"); + fprintf (stderr, + "\t-p PORT Set port number\n"); + fprintf (stderr, + "\t-q Disable \"debug\" output\n"); + fprintf (stderr, + "\t-v Show version info\n"); + fprintf (stderr, "\n"); } /* reverse a given string */ @@ -156,7 +191,9 @@ { va_list ap; char *lfmt; + extern int fquiet; + if (fquiet) return; lfmt = (char *)calloc(7 + strlen(fmt), sizeof(char)); sprintf(lfmt, " %s", fmt); @@ -188,7 +225,7 @@ putchar('.'); for (i = ndot - 1; i < 100; i += 2) putchar(' '); - printf("[%d%% completed]\n", ndot); + printf("[%3d%% completed]\n", ndot); prev = ndot; } --- aget-0.4.old/Misc.h +++ aget-0.4/Misc.h @@ -24,7 +24,7 @@ void updateProgressBar(float, float); void handleHttpRetcode(char *); -time_t t_start, t_finish; +extern time_t t_start, t_finish; #endif --- aget-0.4.old/Signal.h +++ aget-0.4/Signal.h @@ -4,7 +4,7 @@ #include #include -sigset_t signal_set; +extern sigset_t signal_set; void * signal_waiter(void *arg); void sigint_handler(void); --- aget-0.4.old/main.c +++ aget-0.4/main.c @@ -1,3 +1,6 @@ +#include +jmp_buf jmpbuf; + #include #include #include @@ -14,7 +17,10 @@ #include "Resume.h" #include "main.h" -extern int errno; +#include + +time_t t_start, t_finish; +sigset_t signal_set; int main(int argc, char **argv) { @@ -44,7 +50,9 @@ exit(-1); } - while (!error && (c = getopt(argc,argv,"p:l:n:hfv")) != -1) { + while (!error && (c = getopt + (argc, argv, "n:o:O:p:l:dhfqv")) != -1) + { switch(c) { case 'p': req->port = atoi(optarg); @@ -53,14 +61,27 @@ fsuggested = 1; break; case 'l': + case 'o': + case 'O': strncpy(req->lfile, optarg, MAXBUFSIZ); break; + + case 'd': + fquiet = 0; + break; + + case 'q': + fquiet = 1; + break; + case 'n': - if ((nthreads = atoi(optarg)) > MAXTHREADS) { - Log("Error: Maximum # of threads allowed is %d\n", MAXTHREADS); - nthreads = 0; + if ((nthreads = atoi (optarg)) > MAXTHREADS) + { +Log ("Error: Maximum # of threads allowed is %d\n", MAXTHREADS); +nthreads = 0; } break; + case 'h': printf("%s\n", PROGVERSION); usage(); @@ -104,7 +125,8 @@ usage(); exit(1); } - + + setjmp (jmpbuf); parse_url(fullurl, req); /* If a log file for a previous try has been found, read it and --- aget-0.4.old/main.h +++ aget-0.4/main.h @@ -7,6 +7,7 @@ char *fullurl; int nthreads; +int fquiet = 1; int fsuggested = 0; struct request *req; /* Download jobs */