Add secure libcurl transfer backend
This commit is contained in:
+7
-1
@@ -1,6 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(libprozilla VERSION 1.1.1 LANGUAGES C)
|
||||
project(libprozilla VERSION 1.2.0 LANGUAGES C)
|
||||
|
||||
include(CTest)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(CheckIncludeFile)
|
||||
@@ -8,6 +10,7 @@ include(CheckFunctionExists)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(CURL 8.17 REQUIRED)
|
||||
find_package(Intl)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
@@ -39,6 +42,9 @@ configure_file(cmake/config.h.in generated/config.h)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(po)
|
||||
add_subdirectory(docs)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
configure_package_config_file(cmake/libprozillaConfig.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/libprozillaConfig.cmake"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@PACKAGE_INIT@
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(Threads)
|
||||
find_dependency(CURL 8.17)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/libprozillaTargets.cmake")
|
||||
|
||||
+3
-2
@@ -1,8 +1,8 @@
|
||||
add_library(prozilla
|
||||
connect.c connection.c debug.c download.c ftp-retr.c ftp.c ftpparse.c
|
||||
ftpsearch.c http-retr.c http.c logfile.c main.c misc.c netrc.c ping.c url.c)
|
||||
ftpsearch.c http-retr.c http.c curl-retr.c logfile.c main.c misc.c netrc.c ping.c url.c)
|
||||
add_library(libprozilla::prozilla ALIAS prozilla)
|
||||
set_target_properties(prozilla PROPERTIES VERSION 1.0.1 SOVERSION 1)
|
||||
set_target_properties(prozilla PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1)
|
||||
target_include_directories(prozilla
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
@@ -11,6 +11,7 @@ target_include_directories(prozilla
|
||||
target_compile_definitions(prozilla PRIVATE HAVE_CONFIG_H=1 _GNU_SOURCE LOCALEDIR="${LOCALEDIR}")
|
||||
target_compile_options(prozilla PRIVATE $<$<COMPILE_LANG_AND_ID:C,GNU,Clang>:-Wall;-Wextra>)
|
||||
target_link_libraries(prozilla PUBLIC Threads::Threads)
|
||||
target_link_libraries(prozilla PRIVATE CURL::libcurl)
|
||||
if(Intl_FOUND)
|
||||
target_link_libraries(prozilla PRIVATE Intl::Intl)
|
||||
endif()
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
|
||||
+17
-10
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "prozilla.h"
|
||||
#include "connection.h"
|
||||
#include "curl-retr.h"
|
||||
#include "misc.h"
|
||||
#include "connect.h"
|
||||
#include "ftp.h"
|
||||
@@ -208,8 +209,8 @@ uerr_t connection_retr_fsize_not_known(connection_t * connection,
|
||||
|
||||
connection_show_message(connection,
|
||||
_("download for this connection completed"
|
||||
"%s : %ld received"), connection->localfile,
|
||||
connection->remote_bytes_received);
|
||||
"%s : %jd received"), connection->localfile,
|
||||
(intmax_t) connection->remote_bytes_received);
|
||||
return FILEGETOK;
|
||||
}
|
||||
|
||||
@@ -290,8 +291,8 @@ uerr_t connection_retr_fsize_known(connection_t * connection,
|
||||
|
||||
connection_show_message(connection,
|
||||
_("download for this connection completed"
|
||||
"%s : %ld received"), connection->localfile,
|
||||
connection->remote_bytes_received);
|
||||
"%s : %jd received"), connection->localfile,
|
||||
(intmax_t) connection->remote_bytes_received);
|
||||
return FILEGETOK;
|
||||
}
|
||||
|
||||
@@ -305,11 +306,13 @@ int connection_load_resume_info(connection_t * connection)
|
||||
{
|
||||
if (connection->remote_startpos - connection->orig_remote_startpos != connection->remote_bytes_received)
|
||||
{
|
||||
proz_debug("connection->remote start pos before loading %ld", connection->remote_startpos);
|
||||
proz_debug("connection->remote start pos before loading %jd",
|
||||
(intmax_t) connection->remote_startpos);
|
||||
//connection->remote_startpos +=connection->remote_bytes_received;
|
||||
connection->remote_startpos += (connection->remote_bytes_received - (connection->remote_startpos - connection->orig_remote_startpos));
|
||||
|
||||
proz_debug("connection->remote start pos after loading %ld", connection->remote_startpos);
|
||||
proz_debug("connection->remote start pos after loading %jd",
|
||||
(intmax_t) connection->remote_startpos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -455,11 +458,11 @@ void get_url_info_loop(connection_t * connection)
|
||||
switch (connection->u.proto)
|
||||
{
|
||||
case URLHTTP:
|
||||
connection->err = http_get_url_info_loop(connection);
|
||||
break;
|
||||
|
||||
case URLFTP:
|
||||
connection->err = ftp_get_url_info_loop(connection);
|
||||
case URLHTTPS:
|
||||
case URLFTPS:
|
||||
case URLSFTP:
|
||||
connection->err = curl_get_url_info(connection);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -505,6 +508,10 @@ void get_url_info_loop(connection_t * connection)
|
||||
}
|
||||
} while (connection->err == NEWLOCATION);
|
||||
|
||||
pthread_mutex_lock(&connection->access_mutex);
|
||||
connection->running = FALSE;
|
||||
pthread_mutex_unlock(&connection->access_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
#include "common.h"
|
||||
#include "prozilla.h"
|
||||
#include "connection.h"
|
||||
#include "curl-retr.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <limits.h>
|
||||
|
||||
typedef struct {
|
||||
connection_t *connection;
|
||||
CURL *curl;
|
||||
int write_failed;
|
||||
int require_partial_response;
|
||||
size_t bytes_written;
|
||||
} curl_write_context;
|
||||
|
||||
static CURLcode configure_curl(CURL *curl, connection_t *connection)
|
||||
{
|
||||
char known_hosts[PATH_MAX];
|
||||
proxy_info *proxy = NULL;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, connection->u.url);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, connection->user_agent);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L);
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,
|
||||
(long) connection->conn_timeout.tv_sec);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT,
|
||||
(long) connection->xfer_timeout.tv_sec);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,https,ftp,ftps,sftp");
|
||||
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR,
|
||||
"http,https,ftp,ftps,sftp");
|
||||
|
||||
if (connection->u.user)
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, connection->u.user);
|
||||
if (connection->u.passwd)
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, connection->u.passwd);
|
||||
|
||||
if ((connection->u.proto == URLHTTP || connection->u.proto == URLHTTPS)
|
||||
&& connection->http_proxy && connection->http_proxy->use_proxy)
|
||||
proxy = connection->http_proxy;
|
||||
else if ((connection->u.proto == URLFTP || connection->u.proto == URLFTPS)
|
||||
&& connection->ftp_proxy && connection->ftp_proxy->use_proxy
|
||||
&& connection->ftp_proxy->type == HTTPPROXY)
|
||||
proxy = connection->ftp_proxy;
|
||||
if (proxy && proxy->proxy_url.url)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_PROXY, proxy->proxy_url.url);
|
||||
if (proxy->username)
|
||||
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, proxy->username);
|
||||
if (proxy->passwd)
|
||||
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, proxy->passwd);
|
||||
}
|
||||
|
||||
if (connection->u.proto == URLSFTP)
|
||||
{
|
||||
if (snprintf(known_hosts, sizeof(known_hosts), "%s/.ssh/known_hosts",
|
||||
libprozrtinfo.home_dir) >= (int) sizeof(known_hosts)
|
||||
|| access(known_hosts, R_OK) != 0)
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, known_hosts);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static uerr_t map_curl_error(CURLcode result, long response)
|
||||
{
|
||||
if (result == CURLE_OK && response < 400)
|
||||
return HOK;
|
||||
if (response == 401 || response == 403
|
||||
|| result == CURLE_LOGIN_DENIED)
|
||||
return HAUTHFAIL;
|
||||
if (response == 404 || result == CURLE_REMOTE_FILE_NOT_FOUND)
|
||||
return HTTPNSFOD;
|
||||
if (result == CURLE_WRITE_ERROR)
|
||||
return FWRITEERR;
|
||||
return HERR;
|
||||
}
|
||||
|
||||
uerr_t curl_get_url_info(connection_t *connection)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
CURLcode result;
|
||||
curl_off_t length = -1;
|
||||
long response = 0;
|
||||
|
||||
if (!curl)
|
||||
return HERR;
|
||||
result = configure_curl(curl, connection);
|
||||
if (result == CURLE_OK)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||
result = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &length);
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (result != CURLE_OK || response >= 400)
|
||||
return map_curl_error(result, response);
|
||||
if (length < 0 || (curl_off_t) (off_t) length != length)
|
||||
connection->main_file_size = -1;
|
||||
else
|
||||
connection->main_file_size = (off_t) length;
|
||||
connection->hs.contlen = connection->main_file_size;
|
||||
connection->hs.accept_ranges = 1;
|
||||
connection->resume_support = TRUE;
|
||||
return HOK;
|
||||
}
|
||||
|
||||
static size_t curl_write(void *data, size_t size, size_t count, void *opaque)
|
||||
{
|
||||
curl_write_context *ctx = opaque;
|
||||
size_t bytes;
|
||||
long response = 0;
|
||||
|
||||
if (size != 0 && count > SIZE_MAX / size)
|
||||
return 0;
|
||||
bytes = size * count;
|
||||
if (ctx->require_partial_response)
|
||||
{
|
||||
curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
if (response != 206)
|
||||
return 0;
|
||||
}
|
||||
if (write_data_with_lock(ctx->connection, data, 1, bytes) != bytes)
|
||||
{
|
||||
ctx->write_failed = 1;
|
||||
return 0;
|
||||
}
|
||||
pthread_mutex_lock(&ctx->connection->access_mutex);
|
||||
ctx->connection->remote_bytes_received += (off_t) bytes;
|
||||
pthread_mutex_unlock(&ctx->connection->access_mutex);
|
||||
ctx->bytes_written += bytes;
|
||||
connection_calc_ratebps(ctx->connection);
|
||||
connection_throttle_bps(ctx->connection);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static uerr_t curl_get_file(connection_t *connection)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
CURLcode result;
|
||||
curl_write_context ctx = { connection, curl, 0, 0, 0 };
|
||||
char range[96];
|
||||
long response = 0;
|
||||
|
||||
if (!curl)
|
||||
return HERR;
|
||||
result = configure_curl(curl, connection);
|
||||
if (result == CURLE_OK)
|
||||
{
|
||||
if (connection->remote_endpos > connection->remote_startpos)
|
||||
{
|
||||
snprintf(range, sizeof(range), "%jd-%jd",
|
||||
(intmax_t) connection->remote_startpos,
|
||||
(intmax_t) (connection->remote_endpos - 1));
|
||||
curl_easy_setopt(curl, CURLOPT_RANGE, range);
|
||||
if (connection->u.proto == URLHTTP
|
||||
|| connection->u.proto == URLHTTPS)
|
||||
ctx.require_partial_response = 1;
|
||||
}
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ctx);
|
||||
connection_change_status(connection, DOWNLOADING);
|
||||
gettimeofday(&connection->time_begin, NULL);
|
||||
result = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
if (ctx.write_failed)
|
||||
return FWRITEERR;
|
||||
if (ctx.require_partial_response && response != 206)
|
||||
return CANTRESUME;
|
||||
if (connection->remote_endpos > connection->remote_startpos
|
||||
&& (off_t) ctx.bytes_written
|
||||
!= connection->remote_endpos - connection->remote_startpos)
|
||||
return READERR;
|
||||
if (result == CURLE_OK && response < 400)
|
||||
{
|
||||
connection_change_status(connection, COMPLETED);
|
||||
return HOK;
|
||||
}
|
||||
connection_change_status(connection, REMOTEFATAL);
|
||||
return map_curl_error(result, response);
|
||||
}
|
||||
|
||||
void *curl_loop(void *opaque)
|
||||
{
|
||||
connection_t *connection = opaque;
|
||||
boolean retry = FALSE;
|
||||
|
||||
do {
|
||||
if (retry)
|
||||
delay_ms((int) connection->retry_delay.tv_sec * 1000);
|
||||
connection->err = curl_get_file(connection);
|
||||
connection->attempts++;
|
||||
if (connection->err == HOK || connection->err == FWRITEERR
|
||||
|| connection->err == HTTPNSFOD || connection->err == HAUTHFAIL)
|
||||
return (void *) (intptr_t) connection->err;
|
||||
retry = TRUE;
|
||||
} while (connection->max_attempts == 0
|
||||
|| connection->attempts < connection->max_attempts);
|
||||
return (void *) (intptr_t) connection->err;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef CURL_RETR_H
|
||||
#define CURL_RETR_H
|
||||
|
||||
#include "prozilla.h"
|
||||
|
||||
uerr_t curl_get_url_info(connection_t *connection);
|
||||
void *curl_loop(void *connection);
|
||||
|
||||
#endif
|
||||
+7
-16
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "download.h"
|
||||
#include "curl-retr.h"
|
||||
#include "ftp-retr.h"
|
||||
#include "http-retr.h"
|
||||
#include "logfile.h"
|
||||
@@ -305,25 +306,14 @@ void proz_download_start_downloads(download_t * download,
|
||||
switch (download->pconnections[i]->u.proto)
|
||||
{
|
||||
case URLHTTP:
|
||||
/* http_loop(&download->connections[i]); */
|
||||
if (pthread_create(&download->threads[i], NULL,
|
||||
(void *)&http_loop,
|
||||
(void *)(download->pconnections[i])) != 0)
|
||||
|
||||
proz_die(_("Error: Not enough system resources"));
|
||||
|
||||
break;
|
||||
|
||||
case URLFTP:
|
||||
|
||||
/* ftp_loop(&download->connections[i]); */
|
||||
|
||||
|
||||
case URLHTTPS:
|
||||
case URLFTPS:
|
||||
case URLSFTP:
|
||||
if (pthread_create(&download->threads[i], NULL,
|
||||
(void *)&ftp_loop,
|
||||
curl_loop,
|
||||
(void *)(download->pconnections[i])) != 0)
|
||||
proz_die(_("Error: Not enough system resources"));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -884,7 +874,8 @@ off_t proz_download_get_total_remote_bytes_got(download_t * download)
|
||||
|
||||
for (i = 0; i < download->num_connections; i++)
|
||||
{
|
||||
proz_debug("DOWNLOAD_TOTAL_BYTES_RECV=%lld for connection %d", total_bytes_recv, i);
|
||||
proz_debug("DOWNLOAD_TOTAL_BYTES_RECV=%jd for connection %d",
|
||||
(intmax_t) total_bytes_recv, i);
|
||||
total_bytes_recv +=
|
||||
proz_connection_get_total_remote_bytes_got(download->
|
||||
pconnections[i]);
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ uerr_t proz_ftp_get_file(connection_t * connection)
|
||||
|
||||
user = user ? user : libprozrtinfo.ftp_default_user;
|
||||
passwd = passwd ? passwd : libprozrtinfo.ftp_default_passwd;
|
||||
proz_debug(_("Logging in as user %s with password %s."), user, passwd);
|
||||
proz_debug(_("Logging in as user %s."), user);
|
||||
|
||||
connection_change_status(connection, LOGGININ);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "debug.h"
|
||||
#include "ftpparse.h"
|
||||
#include "ftp.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/* #define UNIMPLEMENTED_CMD(a) ((a == 500) || (a == 502) || (a == 504)) */
|
||||
|
||||
@@ -188,14 +189,17 @@ uerr_t ftp_get_line(connection_t * connection, char *line)
|
||||
|
||||
connection->szBuffer = &ch;
|
||||
|
||||
while ((iBuffLen < BUFFER_SIZE)
|
||||
while ((iBuffLen < BUFFER_SIZE - 1)
|
||||
&& ((ret = ftp_check_msg(connection, 1)) > 0))
|
||||
{
|
||||
/* Now get the full string. */
|
||||
iLen = ftp_read_msg(connection, 1);
|
||||
|
||||
if (iLen != 1)
|
||||
return FTPERR;
|
||||
{
|
||||
connection->szBuffer = NULL;
|
||||
return FTPERR;
|
||||
}
|
||||
|
||||
iBuffLen += iLen;
|
||||
*szptr = ch;
|
||||
@@ -207,13 +211,14 @@ uerr_t ftp_get_line(connection_t * connection, char *line)
|
||||
|
||||
/* Check for error returned in ftp_check_msg(). */
|
||||
if (ret == -1)
|
||||
return FTPERR;
|
||||
{
|
||||
connection->szBuffer = NULL;
|
||||
return FTPERR;
|
||||
}
|
||||
|
||||
/* if zero bytes were found that means the server has closed the connection*/
|
||||
if (ret == 0)
|
||||
*(szptr) = '\0';
|
||||
else
|
||||
*(szptr + 1) = '\0';
|
||||
*szptr = '\0';
|
||||
connection->szBuffer = NULL;
|
||||
|
||||
proz_debug(_("Received: %s"), line);
|
||||
|
||||
@@ -393,7 +398,7 @@ uerr_t ftp_rest(connection_t * connection, off_t bytes)
|
||||
{
|
||||
uerr_t err;
|
||||
|
||||
err = ftp_send_msg(connection, "REST %lld\r\n", bytes);
|
||||
err = ftp_send_msg(connection, "REST %jd\r\n", (intmax_t) bytes);
|
||||
if (err != FTPOK)
|
||||
return err;
|
||||
|
||||
@@ -445,7 +450,6 @@ uerr_t ftp_pwd(connection_t * connection, char *dir)
|
||||
{
|
||||
uerr_t err;
|
||||
char *r, *l;
|
||||
char szBuffer[FTP_BUFFER_SIZE];
|
||||
|
||||
err = ftp_send_msg(connection, "PWD\r\n");
|
||||
if (err != FTPOK)
|
||||
@@ -477,7 +481,7 @@ uerr_t ftp_pwd(connection_t * connection, char *dir)
|
||||
if ((r = strchr(connection->serv_ret_lines->line, ' ')) != NULL)
|
||||
{
|
||||
*r = '\0';
|
||||
strcpy(dir, szBuffer);
|
||||
strcpy(dir, r + 1);
|
||||
*r = ' ';
|
||||
}
|
||||
}
|
||||
@@ -491,6 +495,8 @@ uerr_t ftp_pwd(connection_t * connection, char *dir)
|
||||
uerr_t ftp_size(connection_t * connection, const char *file, off_t *size)
|
||||
{
|
||||
uerr_t err;
|
||||
char *end;
|
||||
intmax_t parsed_size;
|
||||
|
||||
*size = -1;
|
||||
|
||||
@@ -505,7 +511,12 @@ uerr_t ftp_size(connection_t * connection, const char *file, off_t *size)
|
||||
/* Now lets figure out what happened. */
|
||||
if (connection->serv_ret_lines->line[0] == '2')
|
||||
{
|
||||
sscanf(connection->serv_ret_lines->line + 3, "%lld", size);
|
||||
errno = 0;
|
||||
parsed_size = strtoimax(connection->serv_ret_lines->line + 3, &end, 10);
|
||||
if (errno != 0 || end == connection->serv_ret_lines->line + 3
|
||||
|| parsed_size < 0 || (intmax_t) (off_t) parsed_size != parsed_size)
|
||||
return FTPSIZEFAIL;
|
||||
*size = (off_t) parsed_size;
|
||||
return FTPOK;
|
||||
}
|
||||
else if (connection->serv_ret_lines->line[0] == '5') /* An error occured. */
|
||||
@@ -902,21 +913,7 @@ uerr_t proz_ftp_get_url_info(connection_t * connection)
|
||||
user = user ? user : libprozrtinfo.ftp_default_user;
|
||||
passwd = passwd ? passwd : libprozrtinfo.ftp_default_passwd;
|
||||
|
||||
if (strcmp(user, "anonymous") == 0)
|
||||
connection_show_message(connection,
|
||||
_("Logging in as user %s with password %s"),
|
||||
user, passwd);
|
||||
else
|
||||
{
|
||||
int pwd_len = strlen(passwd);
|
||||
char *tmp_pwd = (char *)kmalloc(pwd_len + 1);
|
||||
memset(tmp_pwd, 'x', pwd_len);
|
||||
tmp_pwd[pwd_len] = 0;
|
||||
connection_show_message(connection,
|
||||
_("Logging in as user %s with password %s"),
|
||||
user, tmp_pwd);
|
||||
kfree(tmp_pwd);
|
||||
}
|
||||
connection_show_message(connection, _("Logging in as user %s"), user);
|
||||
|
||||
init_response(connection);
|
||||
err = ftp_login(connection, user, passwd);
|
||||
|
||||
+7
-8
@@ -121,9 +121,9 @@ urlinfo *prepare_lycos_url(ftps_request_t * request, char *ftps_loc,
|
||||
(char *)kmalloc(lycos_url_len + strlen(request->file_name) + 300);
|
||||
|
||||
sprintf(lycos_url_buf,
|
||||
"%s?form=advanced&query=%s&doit=Search&type=Exact+search&hits=%d&matches=&hitsprmatch=&limdom=&limpath=&limsize1=%zd&limsize2=%zd&f1=Host&f2=Path&f3=Size&f4=-&f5=-&f6=-&header=none&sort=none&trlen=20",
|
||||
"%s?form=advanced&query=%s&doit=Search&type=Exact+search&hits=%d&matches=&hitsprmatch=&limdom=&limpath=&limsize1=%jd&limsize2=%jd&f1=Host&f2=Path&f3=Size&f4=-&f5=-&f6=-&header=none&sort=none&trlen=20",
|
||||
ftps_loc, request->file_name, num_req_mirrors,
|
||||
request->file_size, request->file_size);
|
||||
(intmax_t) request->file_size, (intmax_t) request->file_size);
|
||||
|
||||
/* Debugging purposes */
|
||||
/*sprintf(lycos_url_buf,"localhost/search.html"); */
|
||||
@@ -161,9 +161,9 @@ urlinfo *prepare_filesearching_url(ftps_request_t * request, char *ftps_loc,
|
||||
(char *)kmalloc(filesearching_url_len + strlen(request->file_name) + 300);
|
||||
|
||||
sprintf(filesearching_url_buf,
|
||||
"%s?q=%s&l=en&t=f&e=on&m=%d&o=n&s=on&s1=%zd&s2=%zd&d=&p=&p2=&x=10&y=14",
|
||||
"%s?q=%s&l=en&t=f&e=on&m=%d&o=n&s=on&s1=%jd&s2=%jd&d=&p=&p2=&x=10&y=14",
|
||||
ftps_loc, request->file_name, num_req_mirrors,
|
||||
request->file_size, request->file_size);
|
||||
(intmax_t) request->file_size, (intmax_t) request->file_size);
|
||||
|
||||
/* Debugging purposes */
|
||||
/* sprintf(filesearching_url_buf,"localhost/fs.html"); */
|
||||
@@ -287,7 +287,7 @@ uerr_t parse_lycos_html_mirror_list(ftps_request_t * request, char *p)
|
||||
strncpy(p1, i + 5, j - i - 5);
|
||||
|
||||
p1[j - i - 5 + 1] = 0;
|
||||
proz_debug("\nstring len= %ld", strlen(p1));
|
||||
proz_debug("\nstring len= %zu", strlen(p1));
|
||||
|
||||
p2 = p1;
|
||||
|
||||
@@ -464,7 +464,7 @@ uerr_t parse_filesearching_html_mirror_list(ftps_request_t * request, char *p)
|
||||
p1 = kmalloc((j - i - 16) + 100);
|
||||
strncpy(p1, i + 16, j - i - 16);
|
||||
|
||||
proz_debug("\nstring len= %ld", strlen(p1));
|
||||
proz_debug("\nstring len= %zu", strlen(p1));
|
||||
proz_debug("\nstring value= %s", p1);
|
||||
|
||||
p1[j - i - 16 + 1] = 0;
|
||||
@@ -640,8 +640,7 @@ uerr_t get_mirror_info(connection_t * connection, char **ret_buf)
|
||||
{
|
||||
/* Construct the necessary header. */
|
||||
www_auth = get_basic_auth_str(user, passwd, "Authorization");
|
||||
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
|
||||
proz_debug(_("Authentification string=%s"), www_auth);
|
||||
proz_debug(_("Authenticating as user %s"), user);
|
||||
}
|
||||
else
|
||||
www_auth = 0;
|
||||
|
||||
+9
-7
@@ -28,6 +28,7 @@
|
||||
#include "debug.h"
|
||||
#include "http.h"
|
||||
#include "http-retr.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Will download a portion of/or the full file from the connection->url.
|
||||
*/
|
||||
@@ -117,8 +118,7 @@ uerr_t proz_http_get_file(connection_t * connection)
|
||||
{
|
||||
/* Construct the necessary header. */
|
||||
www_auth = get_basic_auth_str(user, passwd, "Authorization");
|
||||
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
|
||||
proz_debug(_("Authentification string=%s"), www_auth);
|
||||
proz_debug(_("Authenticating as user %s"), user);
|
||||
}
|
||||
else
|
||||
www_auth = 0;
|
||||
@@ -147,8 +147,10 @@ uerr_t proz_http_get_file(connection_t * connection)
|
||||
if (connection->hs.accept_ranges == 1)
|
||||
{
|
||||
range = (char *)alloca(18 + 64);
|
||||
sprintf(range, "Range: bytes=%lld-\r\n", connection->remote_startpos);
|
||||
proz_debug("Range = %lld Range = %s", connection->remote_startpos, range);
|
||||
snprintf(range, 18 + 64, "Range: bytes=%jd-\r\n",
|
||||
(intmax_t) connection->remote_startpos);
|
||||
proz_debug("Range = %jd Range = %s",
|
||||
(intmax_t) connection->remote_startpos, range);
|
||||
}
|
||||
|
||||
if (connection->u.referer)
|
||||
@@ -423,8 +425,7 @@ uerr_t ftp_get_file_from_http_proxy(connection_t * connection)
|
||||
{
|
||||
/* Construct the necessary header. */
|
||||
www_auth = get_basic_auth_str(user, passwd, "Authorization");
|
||||
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
|
||||
proz_debug(_("Authentification string=%s"), www_auth);
|
||||
proz_debug(_("Authenticating as user %s"), user);
|
||||
}
|
||||
else
|
||||
www_auth = 0;
|
||||
@@ -442,7 +443,8 @@ uerr_t ftp_get_file_from_http_proxy(connection_t * connection)
|
||||
if (connection->hs.accept_ranges == 1)
|
||||
{
|
||||
range = (char *)alloca(18 + 64);
|
||||
sprintf(range, "Range: bytes=%lld-\r\n", connection->remote_startpos);
|
||||
snprintf(range, 18 + 64, "Range: bytes=%jd-\r\n",
|
||||
(intmax_t) connection->remote_startpos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-6
@@ -261,7 +261,7 @@ off_t hgetlen(const char *hdr)
|
||||
for (len = 0; isdigit(*hdr); hdr++)
|
||||
len = 10 * len + (*hdr - '0');
|
||||
|
||||
proz_debug("contenlen %s contentlen %lld", *hdr, len);
|
||||
proz_debug("content length %jd", (intmax_t) len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ off_t hgetrange(const char *hdr)
|
||||
for (len = 0; isdigit(*hdr); hdr++)
|
||||
len = 10 * len + (*hdr - '0');
|
||||
|
||||
proz_debug("range %s range %lld", *hdr, len);
|
||||
proz_debug("range %jd", (intmax_t) len);
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -614,8 +614,7 @@ uerr_t proz_http_get_url_info(connection_t * connection)
|
||||
{
|
||||
/* Construct the necessary header. */
|
||||
www_auth = get_basic_auth_str(user, passwd, "Authorization");
|
||||
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
|
||||
proz_debug(_("Authentification string=%s"), www_auth);
|
||||
proz_debug(_("Authenticating as user %s"), user);
|
||||
}
|
||||
else
|
||||
www_auth = 0;
|
||||
@@ -829,8 +828,7 @@ uerr_t ftp_get_url_info_from_http_proxy(connection_t * connection)
|
||||
{
|
||||
/* Construct the necessary header. */
|
||||
www_auth = get_basic_auth_str(user, passwd, "Authorization");
|
||||
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
|
||||
proz_debug(_("Authentification string=%s"), www_auth);
|
||||
proz_debug(_("Authenticating as user %s"), user);
|
||||
}
|
||||
else
|
||||
www_auth = 0;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "misc.h"
|
||||
//#include "getopt.h"
|
||||
#include "debug.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +49,9 @@ int proz_init(int argc, char **argv)
|
||||
{
|
||||
// int c;
|
||||
|
||||
if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
|
||||
return 0;
|
||||
|
||||
/* Gettext stuff */
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
@@ -125,6 +129,7 @@ void proz_shutdown(void)
|
||||
kfree(libprozrtinfo.dl_dir);
|
||||
kfree(libprozrtinfo.output_dir);
|
||||
kfree(libprozrtinfo.log_dir);
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
+7
-4
@@ -45,7 +45,7 @@ void *kmalloc(size_t size)
|
||||
ret = malloc(size);
|
||||
|
||||
if (ret == NULL)
|
||||
proz_die(_("Failed to malloc() %lu bytes."), size);
|
||||
proz_die(_("Failed to malloc() %zu bytes."), size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ void *krealloc(void *ptr, size_t new_size)
|
||||
ret = realloc(ptr, new_size);
|
||||
|
||||
if (!ret)
|
||||
proz_die(_("Failed to realloc() %lu bytes."), new_size);
|
||||
proz_die(_("Failed to realloc() %zu bytes."), new_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -507,6 +507,11 @@ void cleanup_socks(void *cdata)
|
||||
cleanup_ftpsocks(connection);
|
||||
break;
|
||||
|
||||
case URLHTTPS:
|
||||
case URLFTPS:
|
||||
case URLSFTP:
|
||||
break;
|
||||
|
||||
default:
|
||||
proz_die(_("Error: unsupported protocol"));
|
||||
}
|
||||
@@ -564,5 +569,3 @@ void cleanup_httpsocks(connection_t * connection)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+7
-1
@@ -81,7 +81,10 @@ typedef enum {
|
||||
FILEISDIR,
|
||||
MIRINFOK, MIRPARSEOK, MIRPARSEFAIL, FILEGETOK,
|
||||
/*Related to file joining */
|
||||
JOININPROGRESS, JOINDONE, JOINERR
|
||||
JOININPROGRESS, JOINDONE, JOINERR,
|
||||
|
||||
/* Secure protocols are appended to preserve the historical ABI values. */
|
||||
URLHTTPS, URLFTPS, URLSFTP
|
||||
} uerr_t;
|
||||
|
||||
|
||||
@@ -91,6 +94,9 @@ typedef enum {
|
||||
|
||||
#define DEFAULT_FTP_PORT 21
|
||||
#define DEFAULT_HTTP_PORT 80
|
||||
#define DEFAULT_HTTPS_PORT 443
|
||||
#define DEFAULT_FTPS_PORT 990
|
||||
#define DEFAULT_SFTP_PORT 22
|
||||
|
||||
/* This is used when no password is found or specified. */
|
||||
#define DEFAULT_FTP_USER "anonymous"
|
||||
|
||||
@@ -83,7 +83,10 @@ char *protostrings[] = {
|
||||
/* Similar to former, but for supported protocols: */
|
||||
proto_t sup_protos[] = {
|
||||
{ "http://", URLHTTP, DEFAULT_HTTP_PORT },
|
||||
{ "ftp://", URLFTP, DEFAULT_FTP_PORT }
|
||||
{ "ftp://", URLFTP, DEFAULT_FTP_PORT },
|
||||
{ "https://", URLHTTPS, DEFAULT_HTTPS_PORT },
|
||||
{ "ftps://", URLFTPS, DEFAULT_FTPS_PORT },
|
||||
{ "sftp://", URLSFTP, DEFAULT_SFTP_PORT }
|
||||
/* { "file://", URLFILE, DEFAULT_FTP_PORT } */
|
||||
};
|
||||
|
||||
@@ -637,7 +640,8 @@ char *str_url(const urlinfo * u, int hide)
|
||||
else
|
||||
passwd = encode_string(u->passwd);
|
||||
}
|
||||
if (u->proto == URLFTP && *dir == '/')
|
||||
if ((u->proto == URLFTP || u->proto == URLFTPS || u->proto == URLSFTP)
|
||||
&& *dir == '/')
|
||||
{
|
||||
char *tmp = (char *)kmalloc(strlen(dir) + 3);
|
||||
/*sprintf (tmp, "%%2F%s", dir + 1); */
|
||||
@@ -797,12 +801,12 @@ uerr_t proz_parse_url(const char *url, urlinfo * u, int strict)
|
||||
/* Some delimiter troubles... */
|
||||
if (url[i] == '/' && url[i - 1] != ':')
|
||||
++i;
|
||||
if (type == URLHTTP)
|
||||
if (type == URLHTTP || type == URLHTTPS)
|
||||
while (url[i] && url[i] == '/')
|
||||
++i;
|
||||
u->path = (char *)kmalloc(strlen(url + i) + 8);
|
||||
strcpy(u->path, url + i);
|
||||
if (type == URLFTP)
|
||||
if (type == URLFTP || type == URLFTPS || type == URLSFTP)
|
||||
{
|
||||
u->ftp_type = process_ftp_type(u->path);
|
||||
/* #### We don't handle type `d' correctly yet. */
|
||||
@@ -825,14 +829,15 @@ uerr_t proz_parse_url(const char *url, urlinfo * u, int strict)
|
||||
/* Simplify the directory. */
|
||||
path_simplify(u->dir);
|
||||
/* Remove the leading `/' in HTTP. */
|
||||
if (type == URLHTTP && *u->dir == '/')
|
||||
if ((type == URLHTTP || type == URLHTTPS) && *u->dir == '/')
|
||||
strcpy(u->dir, u->dir + 1);
|
||||
/* Strip trailing `/'. */
|
||||
l = strlen(u->dir);
|
||||
if (l > 1 && u->dir[l - 1] == '/')
|
||||
u->dir[l - 1] = '\0';
|
||||
/* Re-create the path: */
|
||||
abs_ftp = (u->proto == URLFTP && *u->dir == '/');
|
||||
abs_ftp = ((u->proto == URLFTP || u->proto == URLFTPS
|
||||
|| u->proto == URLSFTP) && *u->dir == '/');
|
||||
/* sprintf (u->path, "%s%s%s%s", abs_ftp ? "%2F": "/",
|
||||
abs_ftp ? (u->dir + 1) : u->dir, *u->dir ? "/" : "", u->file); */
|
||||
strcpy(u->path, abs_ftp ? "%2F" : "/");
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
add_executable(url_parse_test url_parse_test.c)
|
||||
target_link_libraries(url_parse_test PRIVATE prozilla)
|
||||
add_test(NAME url_parse COMMAND url_parse_test)
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <prozilla.h>
|
||||
#include <url.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int check(const char *text, uerr_t protocol, unsigned short port)
|
||||
{
|
||||
urlinfo url;
|
||||
uerr_t result = proz_parse_url(text, &url, 0);
|
||||
|
||||
if (result != URLOK || url.proto != protocol || url.port != port)
|
||||
{
|
||||
fprintf(stderr, "failed to parse %s (result=%d protocol=%d port=%u)\n",
|
||||
text, result, url.proto, url.port);
|
||||
return 1;
|
||||
}
|
||||
proz_free_url(&url, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return check("http://example.invalid/file", URLHTTP, 80)
|
||||
|| check("https://example.invalid/file", URLHTTPS, 443)
|
||||
|| check("ftp://example.invalid/file", URLFTP, 21)
|
||||
|| check("ftps://example.invalid/file", URLFTPS, 990)
|
||||
|| check("sftp://example.invalid/file", URLSFTP, 22);
|
||||
}
|
||||
Reference in New Issue
Block a user