Compare commits

...

4 Commits

Author SHA1 Message Date
Archilocos 6d179c3a25
Merge f361527459 into 595c6d275e 2023-10-03 23:46:55 +01:00
Fufu Fang 595c6d275e
Remove spurious code
Remote spurious code flagged by 8451da6ac7,
which was introduced by e76b079fe6
Closes https://github.com/fangfufu/httpdirfs/issues/124
2023-10-03 23:10:24 +01:00
chrysn bd33966337 Allow leading `./` segments in links 2023-10-02 23:44:18 +01:00
liuchenghao f361527459 fix: When the network is abnormal during the file download, start to resume the transfer 2021-09-22 09:59:57 +08:00
3 changed files with 98 additions and 30 deletions

View File

@ -237,11 +237,13 @@ static void LinkTable_uninitialised_fill(LinkTable *linktbl)
}
/*
* Block until the gaps are filled
* result is an invalid variable
*/
int n = curl_multi_perform_once();
int result = 0;
int n = curl_multi_perform_once(&result);
int i = 0;
int j = 0;
while ((i = curl_multi_perform_once())) {
while ((i = curl_multi_perform_once(&result))) {
if (CONFIG.log_type & debug) {
if (j) {
erase_string(stderr, STATUS_LEN, s);
@ -406,20 +408,6 @@ static void HTML_to_LinkTable(const char *url, GumboNode *node,
* This is to prevent duplicated link, if an Apache server has the
* IconsAreLinks option.
*/
/* The following four lines of code have no effect so I've commented
them out. I'm not removing them entirely because it's possible the
original intent was to do a check of some sort here and it's an
error that this check wasn't fully implemented, in which case this
commented out code and the comment above it should serve as a
reminder to whoever originally wrote it that there's something
unfinished here that needs to be finished.
*/
/*
size_t comp_len = strnlen(link_url, MAX_FILENAME_LEN);
if (type == LINK_DIR) {
comp_len--;
}
*/
if (((type == LINK_DIR) || (type == LINK_UNINITIALISED_FILE)) &&
!linknames_equal(linktbl->links[linktbl->num - 1]->linkname,
link_url)) {
@ -958,7 +946,7 @@ TransferStruct Link_download_full(Link *link)
*/
long http_resp = 0;
do {
transfer_blocking(curl);
transfer_blocking(curl, ts.curr_size);
ret = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
if (ret) {
lprintf(error, "%s", curl_easy_strerror(ret));
@ -1077,7 +1065,7 @@ long Link_download(Link *link, char *output_buf, size_t req_size, off_t offset)
CURL *curl = Link_download_curl_setup(link, req_size, offset, &header, &ts);
transfer_blocking(curl);
transfer_blocking(curl, offset);
curl_off_t recv = Link_download_cleanup(curl, &header);
@ -1113,12 +1101,33 @@ long path_download(const char *path, char *output_buf, size_t req_size,
static void make_link_relative(const char *page_url, char *link_url)
{
/*
Some servers make the links to subdirectories absolute, but our code
expects them to be relative, so change the contents of link_url as
needed to accommodate that.
Some servers make the links to subdirectories absolute (in URI terms:
path-absolute), but our code expects them to be relative (in URI terms:
path-noscheme), so change the contents of link_url as needed to
accommodate that.
Also, some servers serve their links as `./name`. This is helpful to
them because it is the only way to express relative references when the
first new path segment of the target contains an unescaped colon (`:`),
eg in `./6:1-balun.png`. While stripping the ./ strictly speaking
reintroduces that ambiguity, it is of little practical concern in this
implementation, as full URI link targets are filtered by their number of
slashes anyway. In URI terms, this converts path-noscheme with a leading
`.` segment into path-noscheme or path-rootless without that segment.
*/
if (link_url[0] == '.' && link_url[1] == '/') {
memmove(link_url, link_url + 2, strlen(link_url) - 1);
return;
}
if (link_url[0] != '/') {
/* Already relative, nothing to do here! */
/* Already relative, nothing to do here!
(Full URIs, eg. `http://example.com/path`, pass through here
unmodified, but those are classified in different LinkTypes later
anyway).
*/
return;
}

View File

@ -10,6 +10,7 @@
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
/*
* ----------------- External variables ----------------------
@ -110,9 +111,10 @@ curl_callback_unlock(CURL *handle, curl_lock_data data, void *userptr)
* \details Adapted from:
* https://curl.haxx.se/libcurl/c/10-at-a-time.html
*/
static void
static int
curl_process_msgs(CURLMsg *curl_msg, int n_running_curl, int n_mesgs)
{
int result = 0;
(void) n_running_curl;
(void) n_mesgs;
static volatile int slept = 0;
@ -163,6 +165,7 @@ curl_process_msgs(CURLMsg *curl_msg, int n_running_curl, int n_mesgs)
lprintf(error, "%d - %s <%s>\n",
curl_msg->data.result,
curl_easy_strerror(curl_msg->data.result), url);
result = curl_msg->data.result;
}
curl_multi_remove_handle(curl_multi, curl);
/*
@ -175,13 +178,50 @@ curl_process_msgs(CURLMsg *curl_msg, int n_running_curl, int n_mesgs)
} else {
lprintf(warning, "curl_msg->msg: %d\n", curl_msg->msg);
}
return result;
}
static int http_error_result(int http_response)
{
switch(http_response)
{
case 0: //eg connection down from kick-off ~suggest retrying till some max limit
case 200: //yay we at least got to our url
case 206: //Partial Content
break;
case 416:
//cannot d/l range ~ either cos no server support
//or cos we're asking for an invalid range ~ie: we already d/ld the file
printf("HTTP416: either the d/l is already complete or the http server cannot d/l a range\n");
default:
return 0;//suggest quitting on an unhandled error
}
return 1;
}
static int curl_error_result(int curl_result)
{
switch (curl_result)
{
case CURLE_OK:
case CURLE_COULDNT_CONNECT: //no network connectivity ?
case CURLE_OPERATION_TIMEDOUT: //cos of CURLOPT_LOW_SPEED_TIME
case CURLE_COULDNT_RESOLVE_HOST: //host/DNS down ?
break; //we'll keep trying
default://see: http://curl.haxx.se/libcurl/c/libcurl-errors.html
return 0;
}
return 1;
}
/**
* \details effectively based on
* https://curl.haxx.se/libcurl/c/multi-double.html
*/
int curl_multi_perform_once(void)
int curl_multi_perform_once(int *result)
{
lprintf(network_lock_debug,
"thread %x: locking transfer_lock;\n", pthread_self());
@ -207,7 +247,12 @@ int curl_multi_perform_once(void)
int n_mesgs;
CURLMsg *curl_msg;
while ((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) {
curl_process_msgs(curl_msg, n_running_curl, n_mesgs);
int nResult = curl_process_msgs(curl_msg, n_running_curl, n_mesgs);
if (!http_error_result(n_mesgs) || !curl_error_result(nResult)) {
*result = 1;
}else{
*result = 0;
}
}
lprintf(network_lock_debug,
@ -272,7 +317,7 @@ void NetworkSystem_init(void)
crypto_lock_init();
}
void transfer_blocking(CURL *curl)
void transfer_blocking(CURL *curl, size_t start)
{
TransferStruct *ts;
CURLcode ret = curl_easy_getinfo(curl, CURLINFO_PRIVATE, &ts);
@ -293,8 +338,22 @@ void transfer_blocking(CURL *curl)
"thread %x: unlocking transfer_lock;\n", pthread_self());
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
while (ts->transferring) {
curl_multi_perform_once();
int result = 0;
bool restartDown = false;
while (ts->transferring && !restartDown) {
/*
* When the network is abnormal during the file download, start to resume the transfer
*/
if (0 != result) {
curl_multi_remove_handle(curl_multi,curl);
curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, start);
res = curl_multi_add_handle(curl_multi, curl);
if (res > 0) {
lprintf(error, "%d, %s\n", res, curl_multi_strerror(res));
}
}
curl_multi_perform_once(&result);
}
}

View File

@ -26,13 +26,13 @@ typedef enum {
extern CURLSH *CURL_SHARE;
/** \brief perform one transfer cycle */
int curl_multi_perform_once(void);
int curl_multi_perform_once(int *result);
/** \brief initialise the network module */
void NetworkSystem_init(void);
/** \brief blocking file transfer */
void transfer_blocking(CURL *curl);
void transfer_blocking(CURL *curl, size_t start);
/** \brief non blocking file transfer */
void transfer_nonblocking(CURL *curl);