First step towards SSL support: wrap connections in a 'struct connection'
which contains the socket descriptor, the input buffer and (yet unused) SSL state variables. This has the neat side effect of greatly improving reentrance (though we're not *quite* there yet) and opening the door to HTTP connection caching. This commit is inspired by email conversations with and patches from Henry Whincup <henry@techiebod.com> last fall.
This commit is contained in:
parent
306d84207e
commit
e07ac3bab3
@ -198,9 +198,10 @@ _fetch_default_proxy_port(const char *scheme)
|
||||
/*
|
||||
* Establish a TCP connection to the specified port on the specified host.
|
||||
*/
|
||||
int
|
||||
conn_t *
|
||||
_fetch_connect(const char *host, int port, int af, int verbose)
|
||||
{
|
||||
conn_t *conn;
|
||||
char pbuf[10];
|
||||
struct addrinfo hints, *res, *res0;
|
||||
int sd, err;
|
||||
@ -218,7 +219,7 @@ _fetch_connect(const char *host, int port, int af, int verbose)
|
||||
hints.ai_protocol = 0;
|
||||
if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
|
||||
_netdb_seterr(err);
|
||||
return (-1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
@ -237,10 +238,23 @@ _fetch_connect(const char *host, int port, int af, int verbose)
|
||||
freeaddrinfo(res0);
|
||||
if (sd == -1) {
|
||||
_fetch_syserr();
|
||||
return (-1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (sd);
|
||||
/* allocate and fill connection structure */
|
||||
if ((conn = calloc(1, sizeof *conn)) == NULL) {
|
||||
close(sd);
|
||||
return (NULL);
|
||||
}
|
||||
if ((conn->host = strdup(host)) == NULL) {
|
||||
free(conn);
|
||||
close(sd);
|
||||
return (NULL);
|
||||
}
|
||||
conn->port = port;
|
||||
conn->af = af;
|
||||
conn->sd = sd;
|
||||
return (conn);
|
||||
}
|
||||
|
||||
|
||||
@ -250,23 +264,23 @@ _fetch_connect(const char *host, int port, int af, int verbose)
|
||||
#define MIN_BUF_SIZE 1024
|
||||
|
||||
int
|
||||
_fetch_getln(int fd, char **buf, size_t *size, size_t *len)
|
||||
_fetch_getln(conn_t *conn)
|
||||
{
|
||||
struct timeval now, timeout, wait;
|
||||
fd_set readfds;
|
||||
int r;
|
||||
char c;
|
||||
|
||||
if (*buf == NULL) {
|
||||
if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) {
|
||||
if (conn->buf == NULL) {
|
||||
if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
*size = MIN_BUF_SIZE;
|
||||
conn->bufsize = MIN_BUF_SIZE;
|
||||
}
|
||||
|
||||
**buf = '\0';
|
||||
*len = 0;
|
||||
conn->buf[0] = '\0';
|
||||
conn->buflen = 0;
|
||||
|
||||
if (fetchTimeout) {
|
||||
gettimeofday(&timeout, NULL);
|
||||
@ -276,7 +290,7 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
|
||||
|
||||
do {
|
||||
if (fetchTimeout) {
|
||||
FD_SET(fd, &readfds);
|
||||
FD_SET(conn->sd, &readfds);
|
||||
gettimeofday(&now, NULL);
|
||||
wait.tv_sec = timeout.tv_sec - now.tv_sec;
|
||||
wait.tv_usec = timeout.tv_usec - now.tv_usec;
|
||||
@ -288,17 +302,17 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
|
||||
errno = ETIMEDOUT;
|
||||
return (-1);
|
||||
}
|
||||
r = select(fd+1, &readfds, NULL, NULL, &wait);
|
||||
r = select(conn->sd + 1, &readfds, NULL, NULL, &wait);
|
||||
if (r == -1) {
|
||||
if (errno == EINTR && fetchRestartCalls)
|
||||
continue;
|
||||
/* EBADF or EINVAL: shouldn't happen */
|
||||
return (-1);
|
||||
}
|
||||
if (!FD_ISSET(fd, &readfds))
|
||||
if (!FD_ISSET(conn->sd, &readfds))
|
||||
continue;
|
||||
}
|
||||
r = read(fd, &c, 1);
|
||||
r = read(conn->sd, &c, 1);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -1) {
|
||||
@ -307,21 +321,24 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
|
||||
/* any other error is bad news */
|
||||
return (-1);
|
||||
}
|
||||
(*buf)[*len] = c;
|
||||
*len += 1;
|
||||
if (*len == *size) {
|
||||
conn->buf[conn->buflen++] = c;
|
||||
if (conn->buflen == conn->bufsize) {
|
||||
char *tmp;
|
||||
size_t tmpsize;
|
||||
|
||||
if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) {
|
||||
tmp = conn->buf;
|
||||
tmpsize = conn->bufsize * 2 + 1;
|
||||
if ((tmp = realloc(tmp, tmpsize)) == NULL) {
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
*buf = tmp;
|
||||
*size = *size * 2 + 1;
|
||||
conn->buf = tmp;
|
||||
conn->bufsize = tmpsize;
|
||||
}
|
||||
} while (c != '\n');
|
||||
|
||||
DEBUG(fprintf(stderr, "<<< %.*s", (int)*len, *buf));
|
||||
conn->buf[conn->buflen] = '\0';
|
||||
DEBUG(fprintf(stderr, "<<< %s", conn->buf));
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -331,7 +348,7 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
|
||||
* XXX currently does not enforce timeout
|
||||
*/
|
||||
int
|
||||
_fetch_putln(int fd, const char *str, size_t len)
|
||||
_fetch_putln(conn_t *conn, const char *str, size_t len)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
ssize_t wlen;
|
||||
@ -342,14 +359,29 @@ _fetch_putln(int fd, const char *str, size_t len)
|
||||
iov[1].iov_base = (char *)ENDL;
|
||||
iov[1].iov_len = sizeof ENDL;
|
||||
len += sizeof ENDL;
|
||||
wlen = writev(fd, iov, 2);
|
||||
wlen = writev(conn->sd, iov, 2);
|
||||
if (wlen < 0 || (size_t)wlen != len)
|
||||
return (-1);
|
||||
DEBUG(fprintf(stderr, ">>> %s\n", str));
|
||||
DEBUG(fprintf(stderr, ">>> %.*s\n", (int)len, str));
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close connection
|
||||
*/
|
||||
int
|
||||
_fetch_close(conn_t *conn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = close(conn->sd);
|
||||
free(conn->host);
|
||||
free(conn);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
/*** Directory-related utility functions *************************************/
|
||||
|
||||
int
|
||||
|
@ -36,6 +36,28 @@
|
||||
#define FTP_DEFAULT_PROXY_PORT 21
|
||||
#define HTTP_DEFAULT_PROXY_PORT 3128
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/* Connection */
|
||||
typedef struct fetchconn conn_t;
|
||||
struct fetchconn {
|
||||
char *host; /* host name */
|
||||
int port; /* port */
|
||||
int af; /* address family */
|
||||
int sd; /* socket descriptor */
|
||||
char *buf; /* buffer */
|
||||
size_t bufsize; /* buffer size */
|
||||
size_t buflen; /* length of buffer contents */
|
||||
int err; /* last protocol reply code */
|
||||
SSL *ssl_ctx; /* SSL context if needed */
|
||||
X509 *ssl_cert; /* server certificate */
|
||||
SSL_METHOD *ssl_meth; /* SSL method */
|
||||
};
|
||||
|
||||
/* Structure used for error message lists */
|
||||
struct fetcherr {
|
||||
const int num;
|
||||
@ -48,9 +70,10 @@ void _fetch_syserr(void);
|
||||
void _fetch_info(const char *, ...);
|
||||
int _fetch_default_port(const char *);
|
||||
int _fetch_default_proxy_port(const char *);
|
||||
int _fetch_connect(const char *, int, int, int);
|
||||
int _fetch_getln(int, char **, size_t *, size_t *);
|
||||
int _fetch_putln(int, const char *, size_t);
|
||||
conn_t *_fetch_connect(const char *, int, int, int);
|
||||
int _fetch_getln(conn_t *);
|
||||
int _fetch_putln(conn_t *, const char *, size_t);
|
||||
int _fetch_close(conn_t *);
|
||||
int _fetch_add_entry(struct url_ent **, int *, int *,
|
||||
const char *, struct url_stat *);
|
||||
|
||||
|
@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -96,12 +97,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define FTP_PROTOCOL_ERROR 999
|
||||
|
||||
static struct url cached_host;
|
||||
static int cached_socket;
|
||||
|
||||
static char *last_reply;
|
||||
static size_t lr_size;
|
||||
static size_t lr_length;
|
||||
static int last_code;
|
||||
static conn_t *cached_connection;
|
||||
|
||||
#define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
|
||||
&& isdigit(foo[2]) \
|
||||
@ -136,43 +132,42 @@ unmappedaddr(struct sockaddr_in6 *sin6)
|
||||
* Get server response
|
||||
*/
|
||||
static int
|
||||
_ftp_chkerr(int cd)
|
||||
_ftp_chkerr(conn_t *conn)
|
||||
{
|
||||
if (_fetch_getln(cd, &last_reply, &lr_size, &lr_length) == -1) {
|
||||
if (_fetch_getln(conn) == -1) {
|
||||
_fetch_syserr();
|
||||
return (-1);
|
||||
}
|
||||
if (isftpinfo(last_reply)) {
|
||||
while (lr_length && !isftpreply(last_reply)) {
|
||||
if (_fetch_getln(cd, &last_reply,
|
||||
&lr_size, &lr_length) == -1) {
|
||||
if (isftpinfo(conn->buf)) {
|
||||
while (conn->buflen && !isftpreply(conn->buf)) {
|
||||
if (_fetch_getln(conn) == -1) {
|
||||
_fetch_syserr();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (lr_length && isspace(last_reply[lr_length-1]))
|
||||
lr_length--;
|
||||
last_reply[lr_length] = 0;
|
||||
while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
|
||||
conn->buflen--;
|
||||
conn->buf[conn->buflen] = '\0';
|
||||
|
||||
if (!isftpreply(last_reply)) {
|
||||
if (!isftpreply(conn->buf)) {
|
||||
_ftp_seterr(FTP_PROTOCOL_ERROR);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
last_code = (last_reply[0] - '0') * 100
|
||||
+ (last_reply[1] - '0') * 10
|
||||
+ (last_reply[2] - '0');
|
||||
conn->err = (conn->buf[0] - '0') * 100
|
||||
+ (conn->buf[1] - '0') * 10
|
||||
+ (conn->buf[2] - '0');
|
||||
|
||||
return (last_code);
|
||||
return (conn->err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command and check reply
|
||||
*/
|
||||
static int
|
||||
_ftp_cmd(int cd, const char *fmt, ...)
|
||||
_ftp_cmd(conn_t *conn, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
size_t len;
|
||||
@ -189,7 +184,7 @@ _ftp_cmd(int cd, const char *fmt, ...)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
r = _fetch_putln(cd, msg, len);
|
||||
r = _fetch_putln(conn, msg, len);
|
||||
free(msg);
|
||||
|
||||
if (r == -1) {
|
||||
@ -197,7 +192,7 @@ _ftp_cmd(int cd, const char *fmt, ...)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (_ftp_chkerr(cd));
|
||||
return (_ftp_chkerr(conn));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -219,15 +214,15 @@ _ftp_filename(const char *file)
|
||||
* file.
|
||||
*/
|
||||
static int
|
||||
_ftp_cwd(int cd, const char *file)
|
||||
_ftp_cwd(conn_t *conn, const char *file)
|
||||
{
|
||||
char *s;
|
||||
int e;
|
||||
|
||||
if ((s = strrchr(file, '/')) == NULL || s == file) {
|
||||
e = _ftp_cmd(cd, "CWD /");
|
||||
e = _ftp_cmd(conn, "CWD /");
|
||||
} else {
|
||||
e = _ftp_cmd(cd, "CWD %.*s", s - file, file);
|
||||
e = _ftp_cmd(conn, "CWD %.*s", s - file, file);
|
||||
}
|
||||
if (e != FTP_FILE_ACTION_OK) {
|
||||
_ftp_seterr(e);
|
||||
@ -240,7 +235,7 @@ _ftp_cwd(int cd, const char *file)
|
||||
* Request and parse file stats
|
||||
*/
|
||||
static int
|
||||
_ftp_stat(int cd, const char *file, struct url_stat *us)
|
||||
_ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
|
||||
{
|
||||
char *ln;
|
||||
const char *s;
|
||||
@ -256,11 +251,11 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
|
||||
else
|
||||
++s;
|
||||
|
||||
if ((e = _ftp_cmd(cd, "SIZE %s", s)) != FTP_FILE_STATUS) {
|
||||
if ((e = _ftp_cmd(conn, "SIZE %s", s)) != FTP_FILE_STATUS) {
|
||||
_ftp_seterr(e);
|
||||
return (-1);
|
||||
}
|
||||
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
|
||||
for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
|
||||
/* nothing */ ;
|
||||
for (us->size = 0; *ln && isdigit(*ln); ln++)
|
||||
us->size = us->size * 10 + *ln - '0';
|
||||
@ -273,11 +268,11 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
|
||||
us->size = -1;
|
||||
DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
|
||||
|
||||
if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS) {
|
||||
if ((e = _ftp_cmd(conn, "MDTM %s", s)) != FTP_FILE_STATUS) {
|
||||
_ftp_seterr(e);
|
||||
return (-1);
|
||||
}
|
||||
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
|
||||
for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
|
||||
/* nothing */ ;
|
||||
switch (strspn(ln, "0123456789")) {
|
||||
case 14:
|
||||
@ -316,7 +311,7 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
|
||||
* I/O functions for FTP
|
||||
*/
|
||||
struct ftpio {
|
||||
int csd; /* Control socket descriptor */
|
||||
conn_t *conn; /* Control connection */
|
||||
int dsd; /* Data socket descriptor */
|
||||
int dir; /* Direction */
|
||||
int eof; /* EOF reached */
|
||||
@ -339,7 +334,7 @@ _ftp_readfn(void *v, char *buf, int len)
|
||||
errno = EBADF;
|
||||
return (-1);
|
||||
}
|
||||
if (io->csd == -1 || io->dsd == -1 || io->dir == O_WRONLY) {
|
||||
if (io->conn == NULL || io->dsd == -1 || io->dir == O_WRONLY) {
|
||||
errno = EBADF;
|
||||
return (-1);
|
||||
}
|
||||
@ -372,7 +367,7 @@ _ftp_writefn(void *v, const char *buf, int len)
|
||||
errno = EBADF;
|
||||
return (-1);
|
||||
}
|
||||
if (io->csd == -1 || io->dsd == -1 || io->dir == O_RDONLY) {
|
||||
if (io->conn == NULL || io->dsd == -1 || io->dir == O_RDONLY) {
|
||||
errno = EBADF;
|
||||
return (-1);
|
||||
}
|
||||
@ -415,7 +410,7 @@ _ftp_closefn(void *v)
|
||||
}
|
||||
if (io->dir == -1)
|
||||
return (0);
|
||||
if (io->csd == -1 || io->dsd == -1) {
|
||||
if (io->conn == NULL || io->dsd == -1) {
|
||||
errno = EBADF;
|
||||
return (-1);
|
||||
}
|
||||
@ -423,21 +418,21 @@ _ftp_closefn(void *v)
|
||||
io->dir = -1;
|
||||
io->dsd = -1;
|
||||
DEBUG(fprintf(stderr, "Waiting for final status\n"));
|
||||
r = _ftp_chkerr(io->csd);
|
||||
close(io->csd);
|
||||
r = _ftp_chkerr(io->conn);
|
||||
_fetch_close(io->conn);
|
||||
free(io);
|
||||
return (r == FTP_TRANSFER_COMPLETE) ? 0 : -1;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
_ftp_setup(int csd, int dsd, int mode)
|
||||
_ftp_setup(conn_t *conn, int dsd, int mode)
|
||||
{
|
||||
struct ftpio *io;
|
||||
FILE *f;
|
||||
|
||||
if ((io = malloc(sizeof *io)) == NULL)
|
||||
return (NULL);
|
||||
io->csd = dup(csd);
|
||||
io->conn = conn;
|
||||
io->dsd = dsd;
|
||||
io->dir = mode;
|
||||
io->eof = io->err = 0;
|
||||
@ -451,7 +446,7 @@ _ftp_setup(int csd, int dsd, int mode)
|
||||
* Transfer file
|
||||
*/
|
||||
static FILE *
|
||||
_ftp_transfer(int cd, const char *oper, const char *file,
|
||||
_ftp_transfer(conn_t *conn, const char *oper, const char *file,
|
||||
int mode, off_t offset, const char *flags)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
@ -475,7 +470,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
|
||||
/* find our own address, bind, and listen */
|
||||
l = sizeof sa;
|
||||
if (getsockname(cd, (struct sockaddr *)&sa, &l) == -1)
|
||||
if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1)
|
||||
goto sysouch;
|
||||
if (sa.ss_family == AF_INET6)
|
||||
unmappedaddr((struct sockaddr_in6 *)&sa);
|
||||
@ -497,14 +492,15 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
_fetch_info("setting passive mode");
|
||||
switch (sa.ss_family) {
|
||||
case AF_INET:
|
||||
if ((e = _ftp_cmd(cd, "PASV")) != FTP_PASSIVE_MODE)
|
||||
if ((e = _ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
|
||||
goto ouch;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if ((e = _ftp_cmd(cd, "EPSV")) != FTP_EPASSIVE_MODE) {
|
||||
if ((e = _ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
|
||||
if (e == -1)
|
||||
goto ouch;
|
||||
if ((e = _ftp_cmd(cd, "LPSV")) != FTP_LPASSIVE_MODE)
|
||||
if ((e = _ftp_cmd(conn, "LPSV")) !=
|
||||
FTP_LPASSIVE_MODE)
|
||||
goto ouch;
|
||||
}
|
||||
break;
|
||||
@ -517,7 +513,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
* Find address and port number. The reply to the PASV command
|
||||
* is IMHO the one and only weak point in the FTP protocol.
|
||||
*/
|
||||
ln = last_reply;
|
||||
ln = conn->buf;
|
||||
switch (e) {
|
||||
case FTP_PASSIVE_MODE:
|
||||
case FTP_LPASSIVE_MODE:
|
||||
@ -555,12 +551,12 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
|
||||
/* seek to required offset */
|
||||
if (offset)
|
||||
if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
|
||||
if (_ftp_cmd(conn, "REST %lu", (u_long)offset) != FTP_FILE_OK)
|
||||
goto sysouch;
|
||||
|
||||
/* construct sockaddr for data socket */
|
||||
l = sizeof sa;
|
||||
if (getpeername(cd, (struct sockaddr *)&sa, &l) == -1)
|
||||
if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1)
|
||||
goto sysouch;
|
||||
if (sa.ss_family == AF_INET6)
|
||||
unmappedaddr((struct sockaddr_in6 *)&sa);
|
||||
@ -597,7 +593,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
/* make the server initiate the transfer */
|
||||
if (verbose)
|
||||
_fetch_info("initiating transfer");
|
||||
e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
|
||||
e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
|
||||
if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
|
||||
goto ouch;
|
||||
|
||||
@ -641,7 +637,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
sin4 = (struct sockaddr_in *)&sa;
|
||||
a = ntohl(sin4->sin_addr.s_addr);
|
||||
p = ntohs(sin4->sin_port);
|
||||
e = _ftp_cmd(cd, "PORT %d,%d,%d,%d,%d,%d",
|
||||
e = _ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
|
||||
(a >> 24) & 0xff, (a >> 16) & 0xff,
|
||||
(a >> 8) & 0xff, a & 0xff,
|
||||
(p >> 8) & 0xff, p & 0xff);
|
||||
@ -653,14 +649,14 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
if (getnameinfo((struct sockaddr *)&sa, sa.ss_len,
|
||||
hname, sizeof(hname),
|
||||
NULL, 0, NI_NUMERICHOST) == 0) {
|
||||
e = _ftp_cmd(cd, "EPRT |%d|%s|%d|", 2, hname,
|
||||
e = _ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
|
||||
htons(sin6->sin6_port));
|
||||
if (e == -1)
|
||||
goto ouch;
|
||||
}
|
||||
if (e != FTP_OK) {
|
||||
ap = (char *)&sin6->sin6_addr;
|
||||
e = _ftp_cmd(cd,
|
||||
e = _ftp_cmd(conn,
|
||||
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
||||
6, 16,
|
||||
UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
|
||||
@ -681,13 +677,13 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
|
||||
/* seek to required offset */
|
||||
if (offset)
|
||||
if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
|
||||
if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK)
|
||||
goto sysouch;
|
||||
|
||||
/* make the server initiate the transfer */
|
||||
if (verbose)
|
||||
_fetch_info("initiating transfer");
|
||||
e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
|
||||
e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
|
||||
if (e != FTP_OPEN_DATA_CONNECTION)
|
||||
goto ouch;
|
||||
|
||||
@ -698,7 +694,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
sd = d;
|
||||
}
|
||||
|
||||
if ((df = _ftp_setup(cd, sd, mode)) == NULL)
|
||||
if ((df = _ftp_setup(conn, sd, mode)) == NULL)
|
||||
goto sysouch;
|
||||
return (df);
|
||||
|
||||
@ -720,7 +716,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
|
||||
* Authenticate
|
||||
*/
|
||||
static int
|
||||
_ftp_authenticate(int cd, struct url *url, struct url *purl)
|
||||
_ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
|
||||
{
|
||||
const char *user, *pwd, *logname;
|
||||
char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
|
||||
@ -735,11 +731,11 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
|
||||
if (!user || !*user)
|
||||
user = FTP_ANONYMOUS_USER;
|
||||
if (purl && url->port == _fetch_default_port(url->scheme))
|
||||
e = _ftp_cmd(cd, "USER %s@%s", user, url->host);
|
||||
e = _ftp_cmd(conn, "USER %s@%s", user, url->host);
|
||||
else if (purl)
|
||||
e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port);
|
||||
e = _ftp_cmd(conn, "USER %s@%s@%d", user, url->host, url->port);
|
||||
else
|
||||
e = _ftp_cmd(cd, "USER %s", user);
|
||||
e = _ftp_cmd(conn, "USER %s", user);
|
||||
|
||||
/* did the server request a password? */
|
||||
if (e == FTP_NEED_PASSWORD) {
|
||||
@ -756,7 +752,7 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
|
||||
gethostname(pbuf + len, sizeof pbuf - len);
|
||||
pwd = pbuf;
|
||||
}
|
||||
e = _ftp_cmd(cd, "PASS %s", pwd);
|
||||
e = _ftp_cmd(conn, "PASS %s", pwd);
|
||||
}
|
||||
|
||||
return (e);
|
||||
@ -765,10 +761,11 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
|
||||
/*
|
||||
* Log on to FTP server
|
||||
*/
|
||||
static int
|
||||
static conn_t *
|
||||
_ftp_connect(struct url *url, struct url *purl, const char *flags)
|
||||
{
|
||||
int cd, e, direct, verbose;
|
||||
conn_t *conn;
|
||||
int e, direct, verbose;
|
||||
#ifdef INET6
|
||||
int af = AF_UNSPEC;
|
||||
#else
|
||||
@ -788,42 +785,42 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
|
||||
/* check for proxy */
|
||||
if (purl) {
|
||||
/* XXX proxy authentication! */
|
||||
cd = _fetch_connect(purl->host, purl->port, af, verbose);
|
||||
conn = _fetch_connect(purl->host, purl->port, af, verbose);
|
||||
} else {
|
||||
/* no proxy, go straight to target */
|
||||
cd = _fetch_connect(url->host, url->port, af, verbose);
|
||||
conn = _fetch_connect(url->host, url->port, af, verbose);
|
||||
purl = NULL;
|
||||
}
|
||||
|
||||
/* check connection */
|
||||
if (cd == -1) {
|
||||
if (conn == NULL) {
|
||||
_fetch_syserr();
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* expect welcome message */
|
||||
if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY)
|
||||
if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY)
|
||||
goto fouch;
|
||||
|
||||
/* authenticate */
|
||||
if ((e = _ftp_authenticate(cd, url, purl)) != FTP_LOGGED_IN)
|
||||
if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN)
|
||||
goto fouch;
|
||||
|
||||
/* might as well select mode and type at once */
|
||||
#ifdef FTP_FORCE_STREAM_MODE
|
||||
if ((e = _ftp_cmd(cd, "MODE S")) != FTP_OK) /* default is S */
|
||||
if ((e = _ftp_cmd(conn, "MODE S")) != FTP_OK) /* default is S */
|
||||
goto fouch;
|
||||
#endif
|
||||
if ((e = _ftp_cmd(cd, "TYPE I")) != FTP_OK) /* default is A */
|
||||
if ((e = _ftp_cmd(conn, "TYPE I")) != FTP_OK) /* default is A */
|
||||
goto fouch;
|
||||
|
||||
/* done */
|
||||
return (cd);
|
||||
return (conn);
|
||||
|
||||
fouch:
|
||||
if (e != -1)
|
||||
_ftp_seterr(e);
|
||||
close(cd);
|
||||
_fetch_close(conn);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@ -831,10 +828,10 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
|
||||
* Disconnect from server
|
||||
*/
|
||||
static void
|
||||
_ftp_disconnect(int cd)
|
||||
_ftp_disconnect(conn_t *conn)
|
||||
{
|
||||
(void)_ftp_cmd(cd, "QUIT");
|
||||
close(cd);
|
||||
(void)_ftp_cmd(conn, "QUIT");
|
||||
_fetch_close(conn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -843,7 +840,7 @@ _ftp_disconnect(int cd)
|
||||
static int
|
||||
_ftp_isconnected(struct url *url)
|
||||
{
|
||||
return (cached_socket
|
||||
return (cached_connection
|
||||
&& (strcmp(url->host, cached_host.host) == 0)
|
||||
&& (strcmp(url->user, cached_host.user) == 0)
|
||||
&& (strcmp(url->pwd, cached_host.pwd) == 0)
|
||||
@ -853,12 +850,11 @@ _ftp_isconnected(struct url *url)
|
||||
/*
|
||||
* Check the cache, reconnect if no luck
|
||||
*/
|
||||
static int
|
||||
static conn_t *
|
||||
_ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
|
||||
{
|
||||
int e, cd;
|
||||
|
||||
cd = -1;
|
||||
conn_t *conn;
|
||||
int e;
|
||||
|
||||
/* set default port */
|
||||
if (!url->port)
|
||||
@ -866,19 +862,19 @@ _ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
|
||||
|
||||
/* try to use previously cached connection */
|
||||
if (_ftp_isconnected(url)) {
|
||||
e = _ftp_cmd(cached_socket, "NOOP");
|
||||
e = _ftp_cmd(cached_connection, "NOOP");
|
||||
if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
|
||||
return (cached_socket);
|
||||
return (cached_connection);
|
||||
}
|
||||
|
||||
/* connect to server */
|
||||
if ((cd = _ftp_connect(url, purl, flags)) == -1)
|
||||
return (-1);
|
||||
if (cached_socket)
|
||||
_ftp_disconnect(cached_socket);
|
||||
cached_socket = cd;
|
||||
if ((conn = _ftp_connect(url, purl, flags)) == NULL)
|
||||
return (NULL);
|
||||
if (cached_connection)
|
||||
_ftp_disconnect(cached_connection);
|
||||
cached_connection = conn;
|
||||
memcpy(&cached_host, url, sizeof *url);
|
||||
return (cd);
|
||||
return (conn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -916,7 +912,8 @@ FILE *
|
||||
_ftp_request(struct url *url, const char *op, struct url_stat *us,
|
||||
struct url *purl, const char *flags)
|
||||
{
|
||||
int cd, oflag;
|
||||
conn_t *conn;
|
||||
int oflag;
|
||||
|
||||
/* check if we should use HTTP instead */
|
||||
if (purl && strcasecmp(purl->scheme, SCHEME_HTTP) == 0) {
|
||||
@ -931,18 +928,18 @@ _ftp_request(struct url *url, const char *op, struct url_stat *us,
|
||||
}
|
||||
|
||||
/* connect to server */
|
||||
cd = _ftp_cached_connect(url, purl, flags);
|
||||
conn = _ftp_cached_connect(url, purl, flags);
|
||||
if (purl)
|
||||
fetchFreeURL(purl);
|
||||
if (cd == NULL)
|
||||
if (conn == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* change directory */
|
||||
if (_ftp_cwd(cd, url->doc) == -1)
|
||||
if (_ftp_cwd(conn, url->doc) == -1)
|
||||
return (NULL);
|
||||
|
||||
/* stat file */
|
||||
if (us && _ftp_stat(cd, url->doc, us) == -1
|
||||
if (us && _ftp_stat(conn, url->doc, us) == -1
|
||||
&& fetchLastErrCode != FETCH_PROTO
|
||||
&& fetchLastErrCode != FETCH_UNAVAIL)
|
||||
return (NULL);
|
||||
@ -956,7 +953,7 @@ _ftp_request(struct url *url, const char *op, struct url_stat *us,
|
||||
oflag = O_RDONLY;
|
||||
|
||||
/* initiate the transfer */
|
||||
return (_ftp_transfer(cd, op, url->doc, oflag, url->offset, flags));
|
||||
return (_ftp_transfer(conn, op, url->doc, oflag, url->offset, flags));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -106,7 +106,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
struct cookie
|
||||
{
|
||||
int fd;
|
||||
conn_t *conn;
|
||||
char *buf;
|
||||
size_t b_size;
|
||||
ssize_t b_len;
|
||||
@ -127,13 +127,13 @@ _http_new_chunk(struct cookie *c)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (_fetch_getln(c->fd, &c->buf, &c->b_size, &c->b_len) == -1)
|
||||
if (_fetch_getln(c->conn) == -1)
|
||||
return (-1);
|
||||
|
||||
if (c->b_len < 2 || !ishexnumber(*c->buf))
|
||||
if (c->b_len < 2 || !ishexnumber(*c->conn->buf))
|
||||
return (-1);
|
||||
|
||||
for (p = c->buf; !isspace(*p) && p < c->buf + c->b_len; ++p) {
|
||||
for (p = c->conn->buf; *p && !isspace(*p); ++p) {
|
||||
if (*p == ';')
|
||||
break;
|
||||
if (!ishexnumber(*p))
|
||||
@ -194,14 +194,16 @@ _http_fillbuf(struct cookie *c)
|
||||
c->b_size = c->chunksize;
|
||||
}
|
||||
|
||||
if ((c->b_len = read(c->fd, c->buf, c->chunksize)) == -1)
|
||||
if ((c->b_len = read(c->conn->sd, c->buf, c->chunksize)) == -1)
|
||||
return (-1);
|
||||
c->chunksize -= c->b_len;
|
||||
|
||||
if (c->chunksize == 0) {
|
||||
char endl;
|
||||
if (read(c->fd, &endl, 1) == -1 ||
|
||||
read(c->fd, &endl, 1) == -1)
|
||||
char endl[2];
|
||||
|
||||
if (read(c->conn->sd, &endl[0], 1) == -1 ||
|
||||
read(c->conn->sd, &endl[1], 1) == -1 ||
|
||||
endl[0] != '\r' || endl[1] != '\n')
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -249,7 +251,7 @@ _http_writefn(void *v, const char *buf, int len)
|
||||
{
|
||||
struct cookie *c = (struct cookie *)v;
|
||||
|
||||
return (write(c->fd, buf, len));
|
||||
return (write(c->conn->sd, buf, len));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -261,7 +263,7 @@ _http_closefn(void *v)
|
||||
struct cookie *c = (struct cookie *)v;
|
||||
int r;
|
||||
|
||||
r = close(c->fd);
|
||||
r = _fetch_close(c->conn);
|
||||
if (c->buf)
|
||||
free(c->buf);
|
||||
free(c);
|
||||
@ -272,7 +274,7 @@ _http_closefn(void *v)
|
||||
* Wrap a file descriptor up
|
||||
*/
|
||||
static FILE *
|
||||
_http_funopen(int fd)
|
||||
_http_funopen(conn_t *conn)
|
||||
{
|
||||
struct cookie *c;
|
||||
FILE *f;
|
||||
@ -281,7 +283,7 @@ _http_funopen(int fd)
|
||||
_fetch_syserr();
|
||||
return (NULL);
|
||||
}
|
||||
c->fd = fd;
|
||||
c->conn = conn;
|
||||
f = funopen(c, _http_readfn, _http_writefn, NULL, _http_closefn);
|
||||
if (f == NULL) {
|
||||
_fetch_syserr();
|
||||
@ -324,15 +326,11 @@ static struct {
|
||||
{ hdr_unknown, NULL },
|
||||
};
|
||||
|
||||
static char *reply_buf;
|
||||
static size_t reply_size;
|
||||
static size_t reply_length;
|
||||
|
||||
/*
|
||||
* Send a formatted line; optionally echo to terminal
|
||||
*/
|
||||
static int
|
||||
_http_cmd(int fd, const char *fmt, ...)
|
||||
_http_cmd(conn_t *conn, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
size_t len;
|
||||
@ -349,7 +347,7 @@ _http_cmd(int fd, const char *fmt, ...)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
r = _fetch_putln(fd, msg, len);
|
||||
r = _fetch_putln(conn, msg, len);
|
||||
free(msg);
|
||||
|
||||
if (r == -1) {
|
||||
@ -364,11 +362,11 @@ _http_cmd(int fd, const char *fmt, ...)
|
||||
* Get and parse status line
|
||||
*/
|
||||
static int
|
||||
_http_get_reply(int fd)
|
||||
_http_get_reply(conn_t *conn)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (_fetch_getln(fd, &reply_buf, &reply_size, &reply_length) == -1)
|
||||
if (_fetch_getln(conn) == -1)
|
||||
return (-1);
|
||||
/*
|
||||
* A valid status line looks like "HTTP/m.n xyz reason" where m
|
||||
@ -379,9 +377,9 @@ _http_get_reply(int fd)
|
||||
* on finding one, but if we do, insist on it being 1.0 or 1.1.
|
||||
* We don't care about the reason phrase.
|
||||
*/
|
||||
if (strncmp(reply_buf, "HTTP", 4) != 0)
|
||||
if (strncmp(conn->buf, "HTTP", 4) != 0)
|
||||
return (HTTP_PROTOCOL_ERROR);
|
||||
p = reply_buf + 4;
|
||||
p = conn->buf + 4;
|
||||
if (*p == '/') {
|
||||
if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1'))
|
||||
return (HTTP_PROTOCOL_ERROR);
|
||||
@ -390,7 +388,8 @@ _http_get_reply(int fd)
|
||||
if (*p != ' ' || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]))
|
||||
return (HTTP_PROTOCOL_ERROR);
|
||||
|
||||
return ((p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0'));
|
||||
conn->err = (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0');
|
||||
return (conn->err);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -413,17 +412,17 @@ _http_match(const char *str, const char *hdr)
|
||||
* Get the next header and return the appropriate symbolic code.
|
||||
*/
|
||||
static hdr_t
|
||||
_http_next_header(int fd, const char **p)
|
||||
_http_next_header(conn_t *conn, const char **p)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (_fetch_getln(fd, &reply_buf, &reply_size, &reply_length) == -1)
|
||||
if (_fetch_getln(conn) == -1)
|
||||
return (hdr_syserror);
|
||||
while (reply_length && isspace(reply_buf[reply_length-1]))
|
||||
reply_length--;
|
||||
reply_buf[reply_length] = 0;
|
||||
if (reply_length == 0)
|
||||
return (hdr_end);
|
||||
while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
|
||||
conn->buflen--;
|
||||
conn->buf[conn->buflen] = '\0';
|
||||
if (conn->buflen == 0)
|
||||
return (hdr_end);
|
||||
/*
|
||||
* We could check for malformed headers but we don't really care.
|
||||
* A valid header starts with a token immediately followed by a
|
||||
@ -431,7 +430,7 @@ _http_next_header(int fd, const char **p)
|
||||
* characters except "()<>@,;:\\\"{}".
|
||||
*/
|
||||
for (i = 0; hdr_names[i].num != hdr_unknown; i++)
|
||||
if ((*p = _http_match(hdr_names[i].name, reply_buf)) != NULL)
|
||||
if ((*p = _http_match(hdr_names[i].name, conn->buf)) != NULL)
|
||||
return (hdr_names[i].num);
|
||||
return (hdr_unknown);
|
||||
}
|
||||
@ -573,7 +572,7 @@ _http_base64(const char *src)
|
||||
* Encode username and password
|
||||
*/
|
||||
static int
|
||||
_http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
|
||||
_http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd)
|
||||
{
|
||||
char *upw, *auth;
|
||||
int r;
|
||||
@ -586,7 +585,7 @@ _http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
|
||||
free(upw);
|
||||
if (auth == NULL)
|
||||
return (-1);
|
||||
r = _http_cmd(fd, "%s: Basic %s", hdr, auth);
|
||||
r = _http_cmd(conn, "%s: Basic %s", hdr, auth);
|
||||
free(auth);
|
||||
return (r);
|
||||
}
|
||||
@ -595,7 +594,7 @@ _http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
|
||||
* Send an authorization header
|
||||
*/
|
||||
static int
|
||||
_http_authorize(int fd, const char *hdr, const char *p)
|
||||
_http_authorize(conn_t *conn, const char *hdr, const char *p)
|
||||
{
|
||||
/* basic authorization */
|
||||
if (strncasecmp(p, "basic:", 6) == 0) {
|
||||
@ -612,7 +611,7 @@ _http_authorize(int fd, const char *hdr, const char *p)
|
||||
user = str;
|
||||
pwd = strchr(str, ':');
|
||||
*pwd++ = '\0';
|
||||
r = _http_basic_auth(fd, hdr, user, pwd);
|
||||
r = _http_basic_auth(conn, hdr, user, pwd);
|
||||
free(str);
|
||||
return (r);
|
||||
}
|
||||
@ -627,11 +626,12 @@ _http_authorize(int fd, const char *hdr, const char *p)
|
||||
/*
|
||||
* Connect to the correct HTTP server or proxy.
|
||||
*/
|
||||
static int
|
||||
static conn_t *
|
||||
_http_connect(struct url *URL, struct url *purl, const char *flags)
|
||||
{
|
||||
conn_t *conn;
|
||||
int verbose;
|
||||
int af, fd;
|
||||
int af;
|
||||
|
||||
#ifdef INET6
|
||||
af = AF_UNSPEC;
|
||||
@ -652,13 +652,13 @@ _http_connect(struct url *URL, struct url *purl, const char *flags)
|
||||
} else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) {
|
||||
/* can't talk http to an ftp server */
|
||||
/* XXX should set an error code */
|
||||
return (-1);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if ((fd = _fetch_connect(URL->host, URL->port, af, verbose)) == -1)
|
||||
if ((conn = _fetch_connect(URL->host, URL->port, af, verbose)) == NULL)
|
||||
/* _fetch_connect() has already set an error code */
|
||||
return (-1);
|
||||
return (fd);
|
||||
return (NULL);
|
||||
return (conn);
|
||||
}
|
||||
|
||||
static struct url *
|
||||
@ -730,9 +730,10 @@ FILE *
|
||||
_http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
struct url *purl, const char *flags)
|
||||
{
|
||||
conn_t *conn;
|
||||
struct url *url, *new;
|
||||
int chunked, direct, need_auth, noredirect, verbose;
|
||||
int code, fd, i, n;
|
||||
int i, n;
|
||||
off_t offset, clength, length, size;
|
||||
time_t mtime;
|
||||
const char *p;
|
||||
@ -782,7 +783,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
}
|
||||
|
||||
/* connect to server or proxy */
|
||||
if ((fd = _http_connect(url, purl, flags)) == -1)
|
||||
if ((conn = _http_connect(url, purl, flags)) == NULL)
|
||||
goto ouch;
|
||||
|
||||
host = url->host;
|
||||
@ -798,36 +799,36 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
_fetch_info("requesting %s://%s:%d%s",
|
||||
url->scheme, host, url->port, url->doc);
|
||||
if (purl) {
|
||||
_http_cmd(fd, "%s %s://%s:%d%s HTTP/1.1",
|
||||
_http_cmd(conn, "%s %s://%s:%d%s HTTP/1.1",
|
||||
op, url->scheme, host, url->port, url->doc);
|
||||
} else {
|
||||
_http_cmd(fd, "%s %s HTTP/1.1",
|
||||
_http_cmd(conn, "%s %s HTTP/1.1",
|
||||
op, url->doc);
|
||||
}
|
||||
|
||||
/* virtual host */
|
||||
if (url->port == _fetch_default_port(url->scheme))
|
||||
_http_cmd(fd, "Host: %s", host);
|
||||
_http_cmd(conn, "Host: %s", host);
|
||||
else
|
||||
_http_cmd(fd, "Host: %s:%d", host, url->port);
|
||||
_http_cmd(conn, "Host: %s:%d", host, url->port);
|
||||
|
||||
/* proxy authorization */
|
||||
if (purl) {
|
||||
if (*purl->user || *purl->pwd)
|
||||
_http_basic_auth(fd, "Proxy-Authorization",
|
||||
_http_basic_auth(conn, "Proxy-Authorization",
|
||||
purl->user, purl->pwd);
|
||||
else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0')
|
||||
_http_authorize(fd, "Proxy-Authorization", p);
|
||||
_http_authorize(conn, "Proxy-Authorization", p);
|
||||
}
|
||||
|
||||
/* server authorization */
|
||||
if (need_auth || *url->user || *url->pwd) {
|
||||
if (*url->user || *url->pwd)
|
||||
_http_basic_auth(fd, "Authorization", url->user, url->pwd);
|
||||
_http_basic_auth(conn, "Authorization", url->user, url->pwd);
|
||||
else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0')
|
||||
_http_authorize(fd, "Authorization", p);
|
||||
_http_authorize(conn, "Authorization", p);
|
||||
else if (fetchAuthMethod && fetchAuthMethod(url) == 0) {
|
||||
_http_basic_auth(fd, "Authorization", url->user, url->pwd);
|
||||
_http_basic_auth(conn, "Authorization", url->user, url->pwd);
|
||||
} else {
|
||||
_http_seterr(HTTP_NEED_AUTH);
|
||||
goto ouch;
|
||||
@ -836,16 +837,16 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
|
||||
/* other headers */
|
||||
if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0')
|
||||
_http_cmd(fd, "User-Agent: %s", p);
|
||||
_http_cmd(conn, "User-Agent: %s", p);
|
||||
else
|
||||
_http_cmd(fd, "User-Agent: %s " _LIBFETCH_VER, _getprogname());
|
||||
_http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname());
|
||||
if (url->offset)
|
||||
_http_cmd(fd, "Range: bytes=%lld-", (long long)url->offset);
|
||||
_http_cmd(fd, "Connection: close");
|
||||
_http_cmd(fd, "");
|
||||
_http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset);
|
||||
_http_cmd(conn, "Connection: close");
|
||||
_http_cmd(conn, "");
|
||||
|
||||
/* get reply */
|
||||
switch ((code = _http_get_reply(fd))) {
|
||||
switch (_http_get_reply(conn)) {
|
||||
case HTTP_OK:
|
||||
case HTTP_PARTIAL:
|
||||
/* fine */
|
||||
@ -864,7 +865,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
* We already sent out authorization code, so there's
|
||||
* nothing more we can do.
|
||||
*/
|
||||
_http_seterr(code);
|
||||
_http_seterr(conn->err);
|
||||
goto ouch;
|
||||
}
|
||||
/* try again, but send the password this time */
|
||||
@ -876,7 +877,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
* If we're talking to a proxy, we already sent our proxy
|
||||
* authorization code, so there's nothing more we can do.
|
||||
*/
|
||||
_http_seterr(code);
|
||||
_http_seterr(conn->err);
|
||||
goto ouch;
|
||||
case HTTP_PROTOCOL_ERROR:
|
||||
/* fall through */
|
||||
@ -884,7 +885,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
_fetch_syserr();
|
||||
goto ouch;
|
||||
default:
|
||||
_http_seterr(code);
|
||||
_http_seterr(conn->err);
|
||||
if (!verbose)
|
||||
goto ouch;
|
||||
/* fall through so we can get the full error message */
|
||||
@ -892,7 +893,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
|
||||
/* get headers */
|
||||
do {
|
||||
switch ((h = _http_next_header(fd, &p))) {
|
||||
switch ((h = _http_next_header(conn, &p))) {
|
||||
case hdr_syserror:
|
||||
_fetch_syserr();
|
||||
goto ouch;
|
||||
@ -909,12 +910,12 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
_http_parse_mtime(p, &mtime);
|
||||
break;
|
||||
case hdr_location:
|
||||
if (!HTTP_REDIRECT(code))
|
||||
if (!HTTP_REDIRECT(conn->err))
|
||||
break;
|
||||
if (new)
|
||||
free(new);
|
||||
if (verbose)
|
||||
_fetch_info("%d redirect to %s", code, p);
|
||||
_fetch_info("%d redirect to %s", conn->err, p);
|
||||
if (*p == '/')
|
||||
/* absolute path */
|
||||
new = fetchMakeURL(url->scheme, url->host, url->port, p,
|
||||
@ -938,7 +939,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
chunked = (strcasecmp(p, "chunked") == 0);
|
||||
break;
|
||||
case hdr_www_authenticate:
|
||||
if (code != HTTP_NEED_AUTH)
|
||||
if (conn->err != HTTP_NEED_AUTH)
|
||||
break;
|
||||
/* if we were smarter, we'd check the method and realm */
|
||||
break;
|
||||
@ -951,21 +952,21 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
} while (h > hdr_end);
|
||||
|
||||
/* we have a hit or an error */
|
||||
if (code == HTTP_OK || code == HTTP_PARTIAL || HTTP_ERROR(code))
|
||||
if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err))
|
||||
break;
|
||||
|
||||
/* we need to provide authentication */
|
||||
if (code == HTTP_NEED_AUTH) {
|
||||
if (conn->err == HTTP_NEED_AUTH) {
|
||||
need_auth = 1;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
_fetch_close(conn);
|
||||
conn = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* all other cases: we got a redirect */
|
||||
need_auth = 0;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
_fetch_close(conn);
|
||||
conn = NULL;
|
||||
if (!new) {
|
||||
DEBUG(fprintf(stderr, "redirect with no new location\n"));
|
||||
break;
|
||||
@ -976,8 +977,8 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
} while (++i < n);
|
||||
|
||||
/* we failed, or ran out of retries */
|
||||
if (fd == -1) {
|
||||
_http_seterr(code);
|
||||
if (conn == NULL) {
|
||||
_http_seterr(conn->err);
|
||||
goto ouch;
|
||||
}
|
||||
|
||||
@ -1019,7 +1020,13 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
URL->length = clength;
|
||||
|
||||
/* wrap it up in a FILE */
|
||||
if ((f = chunked ? _http_funopen(fd) : fdopen(fd, "r")) == NULL) {
|
||||
if (chunked) {
|
||||
f = _http_funopen(conn);
|
||||
} else {
|
||||
f = fdopen(dup(conn->sd), "r");
|
||||
_fetch_close(conn);
|
||||
}
|
||||
if (f == NULL) {
|
||||
_fetch_syserr();
|
||||
goto ouch;
|
||||
}
|
||||
@ -1029,7 +1036,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
if (purl)
|
||||
fetchFreeURL(purl);
|
||||
|
||||
if (HTTP_ERROR(code)) {
|
||||
if (HTTP_ERROR(conn->err)) {
|
||||
_http_print_html(stderr, f);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
@ -1042,8 +1049,8 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
|
||||
fetchFreeURL(url);
|
||||
if (purl)
|
||||
fetchFreeURL(purl);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (conn != NULL)
|
||||
_fetch_close(conn);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user