Index: fetch.c =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/fetch.c,v retrieving revision 1.234 diff -u -p -r1.234 fetch.c --- fetch.c 1 Aug 2021 15:29:30 -0000 1.234 +++ fetch.c 11 Sep 2022 16:36:47 -0000 @@ -106,12 +106,12 @@ __dead static void timeouthttp(int); static int auth_url(const char *, char **, const struct authinfo *); static void base64_encode(const unsigned char *, size_t, unsigned char *); #endif -static int go_fetch(const char *); +static int go_fetch(const char *, struct urlinfo *); static int fetch_ftp(const char *); -static int fetch_url(const char *, const char *, char *, char *); +static int fetch_url(const char *, const char *, char *, char *, struct urlinfo *); static const char *match_token(const char **, const char *); static int parse_url(const char *, const char *, struct urlinfo *, - struct authinfo *); + struct authinfo *, struct urlinfo *); static void url_decode(char *); static void freeauthinfo(struct authinfo *); static void freeurlinfo(struct urlinfo *); @@ -435,7 +435,7 @@ url_decode(char *url) static int parse_url(const char *url, const char *desc, struct urlinfo *ui, - struct authinfo *auth) + struct authinfo *auth, struct urlinfo *rui) { const char *origurl, *tport; char *cp, *ep, *thost; @@ -469,6 +469,26 @@ parse_url(const char *url, const char *d ui->portnum = HTTPS_PORT; tport = httpsport; #endif + } else if (rui != NULL) { + copyurlinfo(ui, rui); + switch(ui->utype) { + case HTTP_URL_T: + tport = httpport; + break; + case FTP_URL_T: + tport = ftpport; + break; + case FILE_URL_T: + tport = ""; + break; +#ifdef WITH_SSL + case HTTPS_URL_T: + tport = httpsport; + break; +#endif + default: + break; + } } else { warnx("Invalid %s `%s'", desc, url); cleanup_parse_url: @@ -541,7 +561,8 @@ parse_url(const char *url, const char *d #endif /* INET6 */ if ((cp = strchr(thost, ':')) != NULL) *cp++ = '\0'; - ui->host = thost; + if (*thost != '\0') + ui->host = thost; /* look for [:port] */ if (cp != NULL) { @@ -718,7 +739,7 @@ handle_proxy(const char *url, const char } initurlinfo(&pui); - if (parse_url(penv, "proxy URL", &pui, pauth) == -1) + if (parse_url(penv, "proxy URL", &pui, pauth, NULL) == -1) return -1; if ((!IS_HTTP_TYPE(pui.utype) && pui.utype != FTP_URL_T) || @@ -990,7 +1011,7 @@ parse_posinfo(const char **cp, struct po static void do_auth(int hcode, const char *url, const char *penv, struct authinfo *wauth, struct authinfo *pauth, char **auth, const char *message, - volatile int *rval) + volatile int *rval, struct urlinfo *ui) { struct authinfo aauth; char *response; @@ -1025,7 +1046,8 @@ do_auth(int hcode, const char *url, cons if (auth_url(*auth, &response, &aauth) == 0) { *rval = fetch_url(url, penv, hcode == 401 ? pauth->auth : response, - hcode == 401 ? response: wauth->auth); + hcode == 401 ? response : wauth->auth, + ui); memset(response, 0, strlen(response)); FREEPTR(response); } @@ -1036,7 +1058,7 @@ static int negotiate_connection(FETCH *fin, const char *url, const char *penv, struct posinfo *pi, time_t *mtime, struct authinfo *wauth, struct authinfo *pauth, volatile int *rval, volatile int *ischunked, - char **auth) + char **auth, struct urlinfo *ui) { int len, hcode, rv; char buf[FTPBUFLEN], *ep; @@ -1156,18 +1178,18 @@ negotiate_connection(FETCH *fin, const c fprintf(ttyout, "Redirected via %s\n", location); *rval = fetch_url(url, location, - pauth->auth, wauth->auth); + pauth->auth, wauth->auth, ui); } else { if (verbose) fprintf(ttyout, "Redirected to %s\n", location); - *rval = go_fetch(location); + *rval = go_fetch(location, ui); } goto cleanup_fetch_url; #ifndef NO_AUTH case 401: case 407: - do_auth(hcode, url, penv, wauth, pauth, auth, message, rval); + do_auth(hcode, url, penv, wauth, pauth, auth, message, rval, ui); goto cleanup_fetch_url; #endif default: @@ -1261,7 +1283,7 @@ connectmethod(FETCH *fin, const char *ur break; #ifndef NO_AUTH case 407: - do_auth(hcode, url, penv, wauth, pauth, auth, message, rval); + do_auth(hcode, url, penv, wauth, pauth, auth, message, rval, ui); goto cleanup_fetch_url; #endif default: @@ -1299,7 +1321,7 @@ out: * is still open (e.g, ftp xfer with trailing /) */ static int -fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth) +fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth, struct urlinfo *rui) { sigfunc volatile oldint; sigfunc volatile oldpipe; @@ -1352,7 +1374,7 @@ fetch_url(const char *url, const char *p if (sigsetjmp(httpabort, 1)) goto cleanup_fetch_url; - if (parse_url(url, "URL", &ui, &wauth) == -1) + if (parse_url(url, "URL", &ui, &wauth, rui) == -1) goto cleanup_fetch_url; copyurlinfo(&oui, &ui); @@ -1535,7 +1557,7 @@ fetch_url(const char *url, const char *p switch (negotiate_connection(fin, url, penv, &pi, &mtime, &wauth, &pauth, &rval, &ischunked, - __UNVOLATILE(&auth))) { + __UNVOLATILE(&auth), &ui)) { case C_OK: break; case C_CLEANUP: @@ -1862,7 +1884,7 @@ fetch_ftp(const char *url) initauthinfo(&auth, NULL); if (STRNEQUAL(url, FTP_URL)) { - if ((parse_url(url, "URL", &ui, &auth) == -1) || + if ((parse_url(url, "URL", &ui, &auth, NULL) == -1) || (auth.user != NULL && *auth.user == '\0') || EMPTYSTRING(ui.host)) { warnx("Invalid URL `%s'", url); @@ -2179,7 +2201,7 @@ fetch_ftp(const char *url) * is still open (e.g, ftp xfer with trailing /) */ static int -go_fetch(const char *url) +go_fetch(const char *url, struct urlinfo *rui) { char *proxyenv; char *p; @@ -2228,7 +2250,7 @@ go_fetch(const char *url) || STRNEQUAL(url, HTTPS_URL) #endif || STRNEQUAL(url, FILE_URL)) - return (fetch_url(url, NULL, NULL, NULL)); + return (fetch_url(url, NULL, NULL, NULL, rui)); /* * If it contains "://" but does not begin with ftp:// @@ -2243,13 +2265,26 @@ go_fetch(const char *url) errx(1, "Unsupported URL scheme `%.*s'", (int)(p - url), url); /* + * Refer to previous urlinfo if provided. This makes relative + * redirects work. + */ + if (rui != NULL) { + if ((rui->utype == HTTP_URL_T) +#ifdef WITH_SSL + || (rui->utype == HTTPS_URL_T) +#endif + || (rui->utype == FILE_URL_T)) + return (fetch_url(url, NULL, NULL, NULL, rui)); + } + + /* * Try FTP URL-style and host:file arguments next. * If ftpproxy is set with an FTP URL, use fetch_url() * Otherwise, use fetch_ftp(). */ proxyenv = getoptionvalue("ftp_proxy"); if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL)) - return (fetch_url(url, NULL, NULL, NULL)); + return (fetch_url(url, NULL, NULL, NULL, rui)); return (fetch_ftp(url)); } @@ -2292,7 +2327,7 @@ auto_fetch(int argc, char *argv[]) redirect_loop = 0; if (!anonftp) anonftp = 2; /* Handle "automatic" transfers. */ - rval = go_fetch(argv[argpos]); + rval = go_fetch(argv[argpos], NULL); if (outfile != NULL && strcmp(outfile, "-") != 0 && outfile[0] != '|') { FREEPTR(outfile);