Revert "Move all external code to lib/external."

This reverts commit 9effec0c4e.
This commit is contained in:
Duncan Overbruck
2021-02-04 22:42:57 +01:00
parent 93410bee7f
commit 51b39002e5
44 changed files with 32 additions and 32 deletions

2063
lib/fetch/common.c Normal file

File diff suppressed because it is too large Load Diff

174
lib/fetch/common.h Normal file
View File

@ -0,0 +1,174 @@
/* $FreeBSD: rev 267133 $ */
/* $NetBSD: common.h,v 1.23 2014/01/08 20:25:34 joerg Exp $ */
/*-
* Copyright (c) 1998-2014 Dag-Erling Smorgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _COMMON_H_INCLUDED
#define _COMMON_H_INCLUDED
#define FTP_DEFAULT_PORT 21
#define HTTP_DEFAULT_PORT 80
#define HTTPS_DEFAULT_PORT 443
#define FTP_DEFAULT_PROXY_PORT 21
#define HTTP_DEFAULT_PROXY_PORT 3128
#define SOCKS5_DEFAULT_PORT 1080
#define SOCKS5_VERSION 0x05
#define SOCKS5_PASS_VERSION 0x01
#define SOCKS5_NO_AUTH 0x00
#define SOCKS5_USER_PASS 0x02
#define SOCKS5_AUTH_SUCCESS 0x00
#define SOCKS5_NO_METHOD 0xFF
#define SOCKS5_TCP_STREAM 0x01
#define SOCKS5_ATYPE_IPV4 0x01
#define SOCKS5_ATYPE_DOMAIN 0x03
#define SOCKS5_ATYPE_IPV6 0x04
#define SOCKS5_REPLY_SUCCESS 0x00
#define SOCKS5_REPLY_FAILURE 0x01
#define SOCKS5_REPLY_DENY 0x02
#define SOCKS5_REPLY_NO_NET 0x03
#define SOCKS5_REPLY_NO_HOST 0x04
#define SOCKS5_REPLY_REFUSED 0x05
#define SOCKS5_REPLY_TIMEOUT 0x06
#define SOCKS5_REPLY_CMD_NOTSUP 0x07
#define SOCKS5_REPLY_ADR_NOTSUP 0x08
#ifdef WITH_SSL
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
#if defined(__GNUC__) && __GNUC__ >= 3
#define LIBFETCH_PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#else
#define LIBFETCH_PRINTFLIKE(fmtarg, firstvararg)
#endif
#if !defined(__sun) && !defined(__hpux) && !defined(__INTERIX) && \
!defined(__digital__) && !defined(__linux) && !defined(__MINT__) && \
!defined(__sgi) && !defined(__minix) && !defined(__CYGWIN__)
#define HAVE_SA_LEN
#endif
/* Connection */
typedef struct fetchconn conn_t;
struct fetchconn {
int sd; /* socket descriptor */
char *buf; /* buffer */
size_t bufsize; /* buffer size */
size_t buflen; /* length of buffer contents */
char *next_buf; /* pending buffer, e.g. after getln */
size_t next_len; /* size of pending buffer */
int err; /* last protocol reply code */
#ifdef WITH_SSL
SSL *ssl; /* SSL handle */
SSL_CTX *ssl_ctx; /* SSL context */
X509 *ssl_cert; /* server certificate */
#endif
char *ftp_home;
struct url *cache_url;
int cache_af;
int (*cache_close)(conn_t *);
conn_t *next_cached;
};
/* Structure used for error message lists */
struct fetcherr {
const int num;
const int cat;
const char *string;
};
void fetch_seterr(struct fetcherr *, int);
void fetch_syserr(void);
void fetch_info(const char *, ...) LIBFETCH_PRINTFLIKE(1, 2);
int fetch_default_port(const char *);
int fetch_default_proxy_port(const char *);
int fetch_bind(int, int, const char *);
conn_t *fetch_cache_get(const struct url *, int);
void fetch_cache_put(conn_t *, int (*)(conn_t *));
int fetch_socks5(conn_t *, struct url *, struct url *, int);
conn_t *fetch_connect(struct url *, int, int);
conn_t *fetch_reopen(int);
#ifdef WITH_SSL
int fetch_ssl_cb_verify_crt(int, X509_STORE_CTX*);
#endif
int fetch_ssl(conn_t *, const struct url *, int);
ssize_t fetch_read(conn_t *, char *, size_t);
int fetch_getln(conn_t *);
ssize_t fetch_write(conn_t *, const void *, size_t);
int fetch_close(conn_t *);
int fetch_add_entry(struct url_list *, struct url *, const char *, int);
int fetch_netrc_auth(struct url *url);
int fetch_no_proxy_match(const char *);
int fetch_urlpath_safe(char);
#define ftp_seterr(n) fetch_seterr(ftp_errlist, n)
#define http_seterr(n) fetch_seterr(http_errlist, n)
#define netdb_seterr(n) fetch_seterr(netdb_errlist, n)
#define url_seterr(n) fetch_seterr(url_errlist, n)
fetchIO *fetchIO_unopen(void *, ssize_t (*)(void *, void *, size_t),
ssize_t (*)(void *, const void *, size_t), void (*)(void *));
/*
* I don't really like exporting http_request() and ftp_request(),
* but the HTTP and FTP code occasionally needs to cross-call
* eachother, and this saves me from adding a lot of special-case code
* to handle those cases.
*
* Note that _*_request() free purl, which is way ugly but saves us a
* whole lot of trouble.
*/
fetchIO *http_request(struct url *, const char *,
struct url_stat *, struct url *, const char *);
fetchIO *ftp_request(struct url *, const char *, const char *,
struct url_stat *, struct url *, const char *);
/*
* Check whether a particular flag is set
*/
#define CHECK_FLAG(x) (flags && strchr(flags, (x)))
#ifndef __UNCONST
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
#endif

11
lib/fetch/errlist.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
# $NetBSD: errlist.sh,v 1.2 2008/10/06 12:58:29 joerg Exp $
printf "static struct fetcherr $1[] = {\n"
while read code type msg; do
[ "${code}" = "#" ] && continue
printf "\t{ ${code}, FETCH_${type}, \"${msg}\" },\n"
done < $3
printf "\t{ -1, FETCH_UNKNOWN, \"Unknown $2 error\" }\n"
printf "};\n"

680
lib/fetch/fetch.c Normal file
View File

@ -0,0 +1,680 @@
/* $FreeBSD: rev 252375 $ */
/* $NetBSD: fetch.c,v 1.19 2009/08/11 20:48:06 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "compat.h"
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "fetch.h"
#include "common.h"
auth_t fetchAuthMethod;
int fetchLastErrCode;
char fetchLastErrString[MAXERRSTRING];
int fetchTimeout;
int fetchConnTimeout = 300 * 1000;
int fetchConnDelay = 250;
volatile int fetchRestartCalls = 1;
int fetchDebug;
/*** Local data **************************************************************/
/*
* Error messages for parser errors
*/
#define URL_MALFORMED 1
#define URL_BAD_SCHEME 2
#define URL_BAD_PORT 3
static struct fetcherr url_errlist[] = {
{ URL_MALFORMED, FETCH_URL, "Malformed URL" },
{ URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" },
{ URL_BAD_PORT, FETCH_URL, "Invalid server port" },
{ -1, FETCH_UNKNOWN, "Unknown parser error" }
};
/*** Public API **************************************************************/
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
* Also fill out the struct url_stat.
*/
fetchIO *
fetchXGet(struct url *URL, struct url_stat *us, const char *flags)
{
if (us != NULL) {
us->size = -1;
us->atime = us->mtime = 0;
}
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchXGetFile(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchXGetFTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchXGetHTTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchXGetHTTP(URL, us, flags));
url_seterr(URL_BAD_SCHEME);
return (NULL);
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
*/
fetchIO *
fetchGet(struct url *URL, const char *flags)
{
return (fetchXGet(URL, NULL, flags));
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* write-only stream connected to the document referenced by the URL.
*/
fetchIO *
fetchPut(struct url *URL, const char *flags)
{
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchPutFile(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchPutFTP(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchPutHTTP(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchPutHTTP(URL, flags));
url_seterr(URL_BAD_SCHEME);
return (NULL);
}
/*
* Select the appropriate protocol for the URL scheme, and return the
* size of the document referenced by the URL if it exists.
*/
int
fetchStat(struct url *URL, struct url_stat *us, const char *flags)
{
if (us != NULL) {
us->size = -1;
us->atime = us->mtime = 0;
}
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchStatFile(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchStatFTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchStatHTTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchStatHTTP(URL, us, flags));
url_seterr(URL_BAD_SCHEME);
return (-1);
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* list of files in the directory pointed to by the URL.
*/
int
fetchList(struct url_list *ue, struct url *URL, const char *pattern,
const char *flags)
{
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchListFile(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchListFTP(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchListHTTP(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchListHTTP(ue, URL, pattern, flags));
url_seterr(URL_BAD_SCHEME);
return -1;
}
/*
* Attempt to parse the given URL; if successful, call fetchXGet().
*/
fetchIO *
fetchXGetURL(const char *URL, struct url_stat *us, const char *flags)
{
struct url *u;
fetchIO *f;
if ((u = fetchParseURL(URL)) == NULL)
return (NULL);
f = fetchXGet(u, us, flags);
fetchFreeURL(u);
return (f);
}
/*
* Attempt to parse the given URL; if successful, call fetchGet().
*/
fetchIO *
fetchGetURL(const char *URL, const char *flags)
{
return (fetchXGetURL(URL, NULL, flags));
}
/*
* Attempt to parse the given URL; if successful, call fetchPut().
*/
fetchIO *
fetchPutURL(const char *URL, const char *flags)
{
struct url *u;
fetchIO *f;
if ((u = fetchParseURL(URL)) == NULL)
return (NULL);
f = fetchPut(u, flags);
fetchFreeURL(u);
return (f);
}
/*
* Attempt to parse the given URL; if successful, call fetchStat().
*/
int
fetchStatURL(const char *URL, struct url_stat *us, const char *flags)
{
struct url *u;
int s;
if ((u = fetchParseURL(URL)) == NULL)
return (-1);
s = fetchStat(u, us, flags);
fetchFreeURL(u);
return (s);
}
/*
* Attempt to parse the given URL; if successful, call fetchList().
*/
int
fetchListURL(struct url_list *ue, const char *URL, const char *pattern,
const char *flags)
{
struct url *u;
int rv;
if ((u = fetchParseURL(URL)) == NULL)
return -1;
rv = fetchList(ue, u, pattern, flags);
fetchFreeURL(u);
return rv;
}
/*
* Make a URL
*/
struct url *
fetchMakeURL(const char *scheme, const char *host, int port, const char *doc,
const char *user, const char *pwd)
{
struct url *u;
if (!scheme || (!host && !doc)) {
url_seterr(URL_MALFORMED);
return (NULL);
}
if (port < 0 || port > 65535) {
url_seterr(URL_BAD_PORT);
return (NULL);
}
/* allocate struct url */
if ((u = calloc(1, sizeof(*u))) == NULL) {
fetch_syserr();
return (NULL);
}
if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
fetch_syserr();
free(u);
return (NULL);
}
#define seturl(x) snprintf(u->x, sizeof(u->x), "%s", x)
seturl(scheme);
seturl(host);
seturl(user);
seturl(pwd);
#undef seturl
u->port = port;
return (u);
}
/*
* Return value of the given hex digit.
*/
static int
fetch_hexval(char ch)
{
if (ch >= '0' && ch <= '9')
return (ch - '0');
else if (ch >= 'a' && ch <= 'f')
return (ch - 'a' + 10);
else if (ch >= 'A' && ch <= 'F')
return (ch - 'A' + 10);
return (-1);
}
/*
* Decode percent-encoded URL component from src into dst, stopping at end
* of string, or at @ or : separators. Returns a pointer to the unhandled
* part of the input string (null terminator, @, or :). No terminator is
* written to dst (it is the caller's responsibility).
*/
static const char *
fetch_pctdecode(char *dst, const char *src, size_t dlen)
{
int d1, d2;
char c;
const char *s;
for (s = src; *s != '\0' && *s != '@' && *s != ':'; s++) {
if (s[0] == '%' && (d1 = fetch_hexval(s[1])) >= 0 &&
(d2 = fetch_hexval(s[2])) >= 0 && (d1 > 0 || d2 > 0)) {
c = d1 << 4 | d2;
s += 2;
} else {
c = *s;
}
if (dlen-- > 0)
*dst++ = c;
else
return (NULL);
}
return (s);
}
int
fetch_urlpath_safe(char x)
{
if ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'Z') ||
(x >= 'a' && x <= 'z'))
return 1;
switch (x) {
case '$':
case '-':
case '_':
case '.':
case '+':
case '!':
case '*':
case '\'':
case '(':
case ')':
case ',':
/* The following are allowed in segment and path components: */
case '?':
case ':':
case '@':
case '&':
case '=':
case '/':
case ';':
/* If something is already quoted... */
case '%':
return 1;
default:
return 0;
}
}
/*
* Copy an existing URL.
*/
struct url *
fetchCopyURL(const struct url *src)
{
struct url *dst;
char *doc;
/* allocate struct url */
if ((dst = malloc(sizeof(*dst))) == NULL) {
fetch_syserr();
return (NULL);
}
if ((doc = strdup(src->doc)) == NULL) {
fetch_syserr();
free(dst);
return (NULL);
}
*dst = *src;
dst->doc = doc;
return dst;
}
/*
* Split an URL into components. URL syntax is:
* [method:/][/[user[:pwd]@]host[:port]/][document]
* This almost, but not quite, RFC1738 URL syntax.
*/
struct url *
fetchParseURL(const char *URL)
{
const char *p, *q;
struct url *u;
size_t i, count;
int pre_quoted;
/* allocate struct url */
if ((u = calloc(1, sizeof(*u))) == NULL) {
fetch_syserr();
return (NULL);
}
if (*URL == '/') {
pre_quoted = 0;
strcpy(u->scheme, SCHEME_FILE);
p = URL;
goto quote_doc;
}
if (strncmp(URL, "file:", 5) == 0) {
pre_quoted = 1;
strcpy(u->scheme, SCHEME_FILE);
URL += 5;
if (URL[0] != '/' || URL[1] != '/' || URL[2] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
p = URL;
goto quote_doc;
}
if (strncmp(URL, "http:", 5) == 0 ||
strncmp(URL, "https:", 6) == 0) {
pre_quoted = 1;
if (URL[4] == ':') {
strcpy(u->scheme, SCHEME_HTTP);
URL += 5;
} else {
strcpy(u->scheme, SCHEME_HTTPS);
URL += 6;
}
if (URL[0] != '/' || URL[1] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
goto find_user;
}
if (strncmp(URL, "ftp:", 4) == 0) {
pre_quoted = 1;
strcpy(u->scheme, SCHEME_FTP);
URL += 4;
if (URL[0] != '/' || URL[1] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
goto find_user;
}
if (strncmp(URL, "socks5:", 7) == 0) {
pre_quoted = 1;
strcpy(u->scheme, SCHEME_SOCKS5);
URL += 7;
if (URL[0] != '/' || URL[1] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
goto find_user;
}
url_seterr(URL_BAD_SCHEME);
goto ouch;
find_user:
p = strpbrk(URL, "/@");
if (p != NULL && *p == '@') {
/* username */
q = fetch_pctdecode(u->user, URL, URL_USERLEN);
if (q == NULL)
goto ouch;
/* password */
if (*q == ':') {
q = fetch_pctdecode(u->pwd, q + 1, URL_PWDLEN);
if (q == NULL)
goto ouch;
}
p++;
} else {
p = URL;
}
/* hostname */
#ifdef INET6
if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
(*++q == '\0' || *q == '/' || *q == ':')) {
if ((i = q - p - 2) > URL_HOSTLEN)
i = URL_HOSTLEN;
strncpy(u->host, ++p, i);
p = q;
} else
#endif
for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
if (i < URL_HOSTLEN)
u->host[i++] = *p;
/* port */
if (*p == ':') {
for (q = ++p; *q && (*q != '/'); q++)
if (isdigit((unsigned char)*q))
u->port = u->port * 10 + (*q - '0');
else {
/* invalid port */
url_seterr(URL_BAD_PORT);
goto ouch;
}
p = q;
}
/* document */
if (!*p)
p = "/";
quote_doc:
count = 1;
for (i = 0; p[i] != '\0'; ++i) {
if ((!pre_quoted && p[i] == '%') ||
!fetch_urlpath_safe(p[i]))
count += 3;
else
++count;
}
if ((u->doc = malloc(count)) == NULL) {
fetch_syserr();
goto ouch;
}
for (i = 0; *p != '\0'; ++p) {
if ((!pre_quoted && *p == '%') ||
!fetch_urlpath_safe(*p)) {
u->doc[i++] = '%';
if ((unsigned char)*p < 160)
u->doc[i++] = '0' + ((unsigned char)*p) / 16;
else
u->doc[i++] = 'a' - 10 + ((unsigned char)*p) / 16;
if ((unsigned char)*p % 16 < 10)
u->doc[i++] = '0' + ((unsigned char)*p) % 16;
else
u->doc[i++] = 'a' - 10 + ((unsigned char)*p) % 16;
} else
u->doc[i++] = *p;
}
u->doc[i] = '\0';
return (u);
ouch:
free(u);
return (NULL);
}
/*
* Free a URL
*/
void
fetchFreeURL(struct url *u)
{
if (!u) {
return;
}
if (u->doc) {
free(u->doc);
}
free(u);
}
static char
xdigit2digit(char digit)
{
digit = tolower((unsigned char)digit);
if (digit >= 'a' && digit <= 'f')
digit = digit - 'a' + 10;
else
digit = digit - '0';
return digit;
}
/*
* Unquote whole URL.
* Skips optional parts like query or fragment identifier.
*/
char *
fetchUnquotePath(struct url *url)
{
char *unquoted;
const char *iter;
size_t i;
if ((unquoted = malloc(strlen(url->doc) + 1)) == NULL)
return NULL;
for (i = 0, iter = url->doc; *iter != '\0'; ++iter) {
if (*iter == '#' || *iter == '?')
break;
if (iter[0] != '%' ||
!isxdigit((unsigned char)iter[1]) ||
!isxdigit((unsigned char)iter[2])) {
unquoted[i++] = *iter;
continue;
}
unquoted[i++] = xdigit2digit(iter[1]) * 16 +
xdigit2digit(iter[2]);
iter += 2;
}
unquoted[i] = '\0';
return unquoted;
}
/*
* Extract the file name component of a URL.
*/
char *
fetchUnquoteFilename(struct url *url)
{
char *unquoted, *filename;
const char *last_slash;
if ((unquoted = fetchUnquotePath(url)) == NULL)
return NULL;
if ((last_slash = strrchr(unquoted, '/')) == NULL)
return unquoted;
filename = strdup(last_slash + 1);
free(unquoted);
return filename;
}
char *
fetchStringifyURL(const struct url *url)
{
size_t total;
char *doc;
/* scheme :// user : pwd @ host :port doc */
total = strlen(url->scheme) + 3 + strlen(url->user) + 1 +
strlen(url->pwd) + 1 + strlen(url->host) + 6 + strlen(url->doc) + 1;
if ((doc = malloc(total)) == NULL)
return NULL;
if (url->port != 0)
snprintf(doc, total, "%s%s%s%s%s%s%s:%d%s",
url->scheme,
url->scheme[0] != '\0' ? "://" : "",
url->user,
url->pwd[0] != '\0' ? ":" : "",
url->pwd,
url->user[0] != '\0' || url->pwd[0] != '\0' ? "@" : "",
url->host,
(int)url->port,
url->doc);
else {
snprintf(doc, total, "%s%s%s%s%s%s%s%s",
url->scheme,
url->scheme[0] != '\0' ? "://" : "",
url->user,
url->pwd[0] != '\0' ? ":" : "",
url->pwd,
url->user[0] != '\0' || url->pwd[0] != '\0' ? "@" : "",
url->host,
url->doc);
}
return doc;
}

192
lib/fetch/fetch.h Normal file
View File

@ -0,0 +1,192 @@
/* $NetBSD: fetch.h,v 1.16 2010/01/22 13:21:09 joerg Exp $ */
/*-
* Copyright (c) 1998-2014 Dag-Erling Smorgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FETCH_H_INCLUDED
#define _FETCH_H_INCLUDED
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#define _LIBFETCH_VER "xbps/2.0"
#define URL_HOSTLEN 255
#define URL_SCHEMELEN 16
#define URL_USERLEN 256
#define URL_PWDLEN 256
typedef struct fetchIO fetchIO;
struct url {
char scheme[URL_SCHEMELEN + 1];
char user[URL_USERLEN + 1];
char pwd[URL_PWDLEN + 1];
char host[URL_HOSTLEN + 1];
int port;
char *doc;
off_t offset;
size_t length;
time_t last_modified;
};
struct url_stat {
off_t size;
time_t atime;
time_t mtime;
};
struct url_list {
size_t length;
size_t alloc_size;
struct url *urls;
};
/* Recognized schemes */
#define SCHEME_FTP "ftp"
#define SCHEME_HTTP "http"
#define SCHEME_HTTPS "https"
#define SCHEME_FILE "file"
#define SCHEME_SOCKS5 "socks5"
/* Error codes */
#define FETCH_ABORT 1
#define FETCH_AUTH 2
#define FETCH_DOWN 3
#define FETCH_EXISTS 4
#define FETCH_FULL 5
#define FETCH_INFO 6
#define FETCH_MEMORY 7
#define FETCH_MOVED 8
#define FETCH_NETWORK 9
#define FETCH_OK 10
#define FETCH_PROTO 11
#define FETCH_RESOLV 12
#define FETCH_SERVER 13
#define FETCH_TEMP 14
#define FETCH_TIMEOUT 15
#define FETCH_UNAVAIL 16
#define FETCH_UNKNOWN 17
#define FETCH_URL 18
#define FETCH_VERBOSE 19
#define FETCH_UNCHANGED 20
#if defined(__cplusplus)
extern "C" {
#endif
void fetchIO_close(fetchIO *);
ssize_t fetchIO_read(fetchIO *, void *, size_t);
ssize_t fetchIO_write(fetchIO *, const void *, size_t);
/* fetchIO-specific functions */
fetchIO *fetchXGetFile(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetFile(struct url *, const char *);
fetchIO *fetchPutFile(struct url *, const char *);
int fetchStatFile(struct url *, struct url_stat *, const char *);
int fetchListFile(struct url_list *, struct url *, const char *,
const char *);
/* HTTP-specific functions */
fetchIO *fetchXGetHTTP(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetHTTP(struct url *, const char *);
fetchIO *fetchPutHTTP(struct url *, const char *);
int fetchStatHTTP(struct url *, struct url_stat *, const char *);
int fetchListHTTP(struct url_list *, struct url *, const char *,
const char *);
/* FTP-specific functions */
fetchIO *fetchXGetFTP(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetFTP(struct url *, const char *);
fetchIO *fetchPutFTP(struct url *, const char *);
int fetchStatFTP(struct url *, struct url_stat *, const char *);
int fetchListFTP(struct url_list *, struct url *, const char *,
const char *);
/* Generic functions */
fetchIO *fetchXGetURL(const char *, struct url_stat *, const char *);
fetchIO *fetchGetURL(const char *, const char *);
fetchIO *fetchPutURL(const char *, const char *);
int fetchStatURL(const char *, struct url_stat *, const char *);
int fetchListURL(struct url_list *, const char *, const char *,
const char *);
fetchIO *fetchXGet(struct url *, struct url_stat *, const char *);
fetchIO *fetchGet(struct url *, const char *);
fetchIO *fetchPut(struct url *, const char *);
int fetchStat(struct url *, struct url_stat *, const char *);
int fetchList(struct url_list *, struct url *, const char *,
const char *);
/* URL parsing */
struct url *fetchMakeURL(const char *, const char *, int,
const char *, const char *, const char *);
struct url *fetchParseURL(const char *);
struct url *fetchCopyURL(const struct url *);
char *fetchStringifyURL(const struct url *);
void fetchFreeURL(struct url *);
/* URL listening */
void fetchInitURLList(struct url_list *);
int fetchAppendURLList(struct url_list *, const struct url_list *);
void fetchFreeURLList(struct url_list *);
char *fetchUnquotePath(struct url *);
char *fetchUnquoteFilename(struct url *);
/* Connection caching */
void fetchConnectionCacheInit(int, int);
void fetchConnectionCacheClose(void);
/* Authentication */
typedef int (*auth_t)(struct url *);
extern auth_t fetchAuthMethod;
/* Last error code */
extern int fetchLastErrCode;
#define MAXERRSTRING 256
extern char fetchLastErrString[MAXERRSTRING];
/* I/O timeout */
extern int fetchTimeout;
/* Connect timeout */
extern int fetchConnTimeout;
/* Connect attempt delay */
extern int fetchConnDelay;
/* Restart interrupted syscalls */
extern volatile int fetchRestartCalls;
/* Extra verbosity */
extern int fetchDebug;
#if defined(__cplusplus)
}
#endif
#endif

269
lib/fetch/file.c Normal file
View File

@ -0,0 +1,269 @@
/* $NetBSD: file.c,v 1.15 2009/10/15 12:36:57 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD: file.c,v 1.18 2007/12/14 10:26:58 des Exp $
*/
#include "compat.h"
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fetch.h"
#include "common.h"
static int fetch_stat_file(int, struct url_stat *);
static ssize_t
fetchFile_read(void *cookie, void *buf, size_t len)
{
return read(*(int *)cookie, buf, len);
}
static ssize_t
fetchFile_write(void *cookie, const void *buf, size_t len)
{
return write(*(int *)cookie, buf, len);
}
static void
fetchFile_close(void *cookie)
{
int fd = *(int *)cookie;
free(cookie);
close(fd);
}
fetchIO *
fetchXGetFile(struct url *u, struct url_stat *us, const char *flags)
{
char *path;
fetchIO *f;
struct url_stat local_us;
int if_modified_since, fd, *cookie;
if_modified_since = CHECK_FLAG('i');
if (if_modified_since && us == NULL)
us = &local_us;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return NULL;
}
fd = open(path, O_RDONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return NULL;
}
if (us && fetch_stat_file(fd, us) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
if (if_modified_since && u->last_modified > 0 &&
u->last_modified >= us->mtime) {
close(fd);
fetchLastErrCode = FETCH_UNCHANGED;
snprintf(fetchLastErrString, MAXERRSTRING, "Unchanged");
return NULL;
}
if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
cookie = malloc(sizeof(int));
if (cookie == NULL) {
close(fd);
fetch_syserr();
return NULL;
}
*cookie = fd;
f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
if (f == NULL) {
close(fd);
free(cookie);
}
return f;
}
fetchIO *
fetchGetFile(struct url *u, const char *flags)
{
return (fetchXGetFile(u, NULL, flags));
}
fetchIO *
fetchPutFile(struct url *u, const char *flags)
{
char *path;
fetchIO *f;
int fd, *cookie;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return NULL;
}
if (CHECK_FLAG('a'))
fd = open(path, O_WRONLY | O_APPEND);
else
fd = open(path, O_WRONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return NULL;
}
if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
cookie = malloc(sizeof(int));
if (cookie == NULL) {
close(fd);
fetch_syserr();
return NULL;
}
*cookie = fd;
f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
if (f == NULL) {
close(fd);
free(cookie);
}
return f;
}
static int
fetch_stat_file(int fd, struct url_stat *us)
{
struct stat sb;
us->size = -1;
us->atime = us->mtime = 0;
if (fstat(fd, &sb) == -1) {
fetch_syserr();
return (-1);
}
us->size = sb.st_size;
us->atime = sb.st_atime;
us->mtime = sb.st_mtime;
return (0);
}
int
fetchStatFile(struct url *u, struct url_stat *us, const char *flags)
{
char *path;
int fd, rv;
(void)flags;
if (us == NULL) {
fetch_syserr();
return -1;
}
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return -1;
}
fd = open(path, O_RDONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return -1;
}
rv = fetch_stat_file(fd, us);
close(fd);
return rv;
}
int
fetchListFile(struct url_list *ue, struct url *u, const char *pattern, const char *flags)
{
char *path;
struct dirent *de;
DIR *dir;
int ret;
(void)flags;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return -1;
}
dir = opendir(path);
free(path);
if (dir == NULL) {
fetch_syserr();
return -1;
}
ret = 0;
while ((de = readdir(dir)) != NULL) {
if (pattern && fnmatch(pattern, de->d_name, 0) != 0)
continue;
ret = fetch_add_entry(ue, u, de->d_name, 0);
if (ret)
break;
}
closedir(dir);
return ret;
}

1295
lib/fetch/ftp.c Normal file

File diff suppressed because it is too large Load Diff

48
lib/fetch/ftp.errors Normal file
View File

@ -0,0 +1,48 @@
# $NetBSD: ftp.errors,v 1.2 2008/10/06 12:58:29 joerg Exp $
# $FreeBSD: ftp.errors,v 1.6 2002/10/30 06:06:16 des Exp $
#
# This list is taken from RFC 959.
# It probably needs a going over.
#
110 OK Restart marker reply
120 TEMP Service ready in a few minutes
125 OK Data connection already open; transfer starting
150 OK File status okay; about to open data connection
200 OK Command okay
202 PROTO Command not implemented, superfluous at this site
211 INFO System status, or system help reply
212 INFO Directory status
213 INFO File status
214 INFO Help message
215 INFO Set system type
220 OK Service ready for new user
221 OK Service closing control connection
225 OK Data connection open; no transfer in progress
226 OK Requested file action successful
227 OK Entering Passive Mode
229 OK Entering Extended Passive Mode
230 OK User logged in, proceed
250 OK Requested file action okay, completed
257 OK File/directory created
331 AUTH User name okay, need password
332 AUTH Need account for login
350 OK Requested file action pending further information
421 DOWN Service not available, closing control connection
425 NETWORK Can't open data connection
426 ABORT Connection closed; transfer aborted
450 UNAVAIL File unavailable (e.g., file busy)
451 SERVER Requested action aborted: local error in processing
452 FULL Insufficient storage space in system
500 PROTO Syntax error, command unrecognized
501 PROTO Syntax error in parameters or arguments
502 PROTO Command not implemented
503 PROTO Bad sequence of commands
504 PROTO Command not implemented for that parameter
530 AUTH Not logged in
532 AUTH Need account for storing files
535 PROTO Bug in MediaHawk Video Kernel FTP server
550 UNAVAIL File unavailable (e.g., file not found, no access)
551 PROTO Requested action aborted. Page type unknown
552 FULL Exceeded storage allocation
553 EXISTS File name not allowed
999 PROTO Protocol error

1578
lib/fetch/http.c Normal file

File diff suppressed because it is too large Load Diff

46
lib/fetch/http.errors Normal file
View File

@ -0,0 +1,46 @@
# $FreeBSD$ revision 241840
#
# This list is taken from RFC 2068.
#
100 OK Continue
101 OK Switching Protocols
200 OK OK
201 OK Created
202 OK Accepted
203 INFO Non-Authoritative Information
204 OK No Content
205 OK Reset Content
206 OK Partial Content
300 MOVED Multiple Choices
301 MOVED Moved Permanently
302 MOVED Moved Temporarily
303 MOVED See Other
304 UNCHANGED Not Modified
305 INFO Use Proxy
307 MOVED Temporary Redirect
308 MOVED Permanent Redirect
400 PROTO Bad Request
401 AUTH Unauthorized
402 AUTH Payment Required
403 AUTH Forbidden
404 UNAVAIL Not Found
405 PROTO Method Not Allowed
406 PROTO Not Acceptable
407 AUTH Proxy Authentication Required
408 TIMEOUT Request Time-out
409 EXISTS Conflict
410 UNAVAIL Gone
411 PROTO Length Required
412 SERVER Precondition Failed
413 PROTO Request Entity Too Large
414 PROTO Request-URI Too Large
415 PROTO Unsupported Media Type
416 UNAVAIL Requested Range Not Satisfiable
417 SERVER Expectation Failed
500 SERVER Internal Server Error
501 PROTO Not Implemented
502 SERVER Bad Gateway
503 TEMP Service Unavailable
504 TIMEOUT Gateway Time-out
505 PROTO HTTP Version not supported
999 PROTO Protocol error