mirror of
https://github.com/libretro/RetroArch
synced 2025-04-16 17:43:02 +00:00
webdav: fixes for reauth and parallelism (#17132)
This commit is contained in:
parent
8ee6561a26
commit
a26f6f6b45
@ -59,7 +59,6 @@ typedef struct
|
||||
char *cnonce;
|
||||
bool qop_auth;
|
||||
unsigned nc;
|
||||
char *digest_auth_header;
|
||||
} webdav_state_t;
|
||||
|
||||
static webdav_state_t webdav_driver_st = {0};
|
||||
@ -120,10 +119,6 @@ static void webdav_cleanup_digest(void)
|
||||
|
||||
webdav_st->qop_auth = false;
|
||||
webdav_st->nc = 1;
|
||||
|
||||
if (webdav_st->digest_auth_header)
|
||||
free(webdav_st->digest_auth_header);
|
||||
webdav_st->digest_auth_header = NULL;
|
||||
}
|
||||
|
||||
static char *webdav_create_ha1_hash(char *user, char *realm, char *pass)
|
||||
@ -267,6 +262,7 @@ static bool webdav_create_digest_auth(char *digest)
|
||||
return false;
|
||||
|
||||
webdav_st->cnonce = "1a2b3c4f";
|
||||
webdav_st->basic = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -438,13 +434,10 @@ static char *webdav_get_auth_header(const char *method, const char *url)
|
||||
{
|
||||
if (!webdav_st->basic_auth_header)
|
||||
webdav_st->basic_auth_header = webdav_create_basic_auth();
|
||||
return webdav_st->basic_auth_header;
|
||||
return strdup(webdav_st->basic_auth_header);
|
||||
}
|
||||
|
||||
if (webdav_st->digest_auth_header)
|
||||
free(webdav_st->digest_auth_header);
|
||||
webdav_st->digest_auth_header = webdav_create_digest_auth_header(method, url);
|
||||
return webdav_st->digest_auth_header;
|
||||
return webdav_create_digest_auth_header(method, url);
|
||||
}
|
||||
|
||||
static void webdav_log_http_failure(const char *path, http_transfer_data_t *data)
|
||||
@ -454,8 +447,33 @@ static void webdav_log_http_failure(const char *path, http_transfer_data_t *data
|
||||
for (i = 0; data->headers && i < data->headers->size; i++)
|
||||
RARCH_WARN("%s\n", data->headers->elems[i].data);
|
||||
if (data->data)
|
||||
{
|
||||
data->data[data->len] = 0;
|
||||
RARCH_WARN("%s\n", data->data);
|
||||
}
|
||||
}
|
||||
|
||||
static bool webdav_needs_reauth(http_transfer_data_t *data)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!data || data->status != 401 || !data->headers)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < data->headers->size; i++)
|
||||
{
|
||||
if (!string_starts_with(data->headers->elems[i].data, "WWW-Authenticate: Digest "))
|
||||
continue;
|
||||
|
||||
RARCH_DBG("[webdav] found WWW-Authenticate: Digest header\n");
|
||||
if (webdav_create_digest_auth(data->headers->elems[i].data))
|
||||
return true;
|
||||
else
|
||||
RARCH_WARN("[webdav] failure creating WWW-Authenticate: Digest header\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void webdav_stat_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||
{
|
||||
@ -470,27 +488,13 @@ static void webdav_stat_cb(retro_task_t *task, void *task_data, void *user_data,
|
||||
if (!data)
|
||||
RARCH_WARN("[webdav] did not get data for stat, is the server down?\n");
|
||||
|
||||
if (data && data->status == 401 && data->headers && webdav_st->basic == true)
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
size_t i;
|
||||
webdav_st->basic = false;
|
||||
for (i = 0; i < data->headers->size; i++)
|
||||
{
|
||||
if (!string_starts_with(data->headers->elems[i].data, "WWW-Authenticate: Digest "))
|
||||
continue;
|
||||
|
||||
RARCH_DBG("[webdav] found WWW-Authenticate: Digest header\n");
|
||||
if (webdav_create_digest_auth(data->headers->elems[i].data))
|
||||
{
|
||||
task_push_webdav_stat(webdav_st->url, true,
|
||||
webdav_get_auth_header("OPTIONS", webdav_st->url),
|
||||
webdav_stat_cb, webdav_cb_st);
|
||||
char *auth_header = webdav_get_auth_header("OPTIONS", webdav_st->url);
|
||||
task_push_webdav_stat(webdav_st->url, true, auth_header, webdav_stat_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
return;
|
||||
}
|
||||
else
|
||||
RARCH_WARN("[webdav] failure creating WWW-Authenticate: Digest header\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!success && data)
|
||||
webdav_log_http_failure(webdav_st->url, data);
|
||||
@ -505,7 +509,7 @@ static bool webdav_sync_begin(cloud_sync_complete_handler_t cb, void *user_data)
|
||||
const char *url = settings->arrays.webdav_url;
|
||||
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||
size_t len = 0;
|
||||
const char *auth_header;
|
||||
char *auth_header;
|
||||
|
||||
if (string_is_empty(url))
|
||||
return false;
|
||||
@ -531,6 +535,7 @@ static bool webdav_sync_begin(cloud_sync_complete_handler_t cb, void *user_data)
|
||||
webdav_cb_st->cb = cb;
|
||||
webdav_cb_st->user_data = user_data;
|
||||
task_push_webdav_stat(webdav_st->url, true, auth_header, webdav_stat_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -569,7 +574,23 @@ static void webdav_read_cb(retro_task_t *task, void *task_data, void *user_data,
|
||||
if (!success && data)
|
||||
webdav_log_http_failure(webdav_cb_st->path, data);
|
||||
|
||||
/* TODO: it's possible we get a 401 here and need to redo the auth check with this request */
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||
char url[PATH_MAX_LENGTH];
|
||||
char url_encoded[PATH_MAX_LENGTH];
|
||||
char *auth_header;
|
||||
|
||||
fill_pathname_join_special(url, webdav_st->url, webdav_cb_st->path, sizeof(url));
|
||||
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||
|
||||
RARCH_DBG("[webdav] GET %s\n", url_encoded);
|
||||
auth_header = webdav_get_auth_header("GET", url_encoded);
|
||||
task_push_http_transfer_with_headers(url_encoded, true, NULL, auth_header, webdav_read_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
return;
|
||||
}
|
||||
|
||||
if (success && data->data && webdav_cb_st)
|
||||
{
|
||||
/* TODO: it would be better if writing to the file happened during the network reads */
|
||||
@ -596,6 +617,7 @@ static bool webdav_read(const char *path, const char *file, cloud_sync_complete_
|
||||
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t*)calloc(1, sizeof(webdav_cb_state_t));
|
||||
char url[PATH_MAX_LENGTH];
|
||||
char url_encoded[PATH_MAX_LENGTH];
|
||||
char *auth_header;
|
||||
|
||||
fill_pathname_join_special(url, webdav_st->url, path, sizeof(url));
|
||||
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||
@ -605,9 +627,10 @@ static bool webdav_read(const char *path, const char *file, cloud_sync_complete_
|
||||
strlcpy(webdav_cb_st->path, path, sizeof(webdav_cb_st->path));
|
||||
strlcpy(webdav_cb_st->file, file, sizeof(webdav_cb_st->file));
|
||||
|
||||
task_push_http_transfer_with_headers(url_encoded, true, NULL,
|
||||
webdav_get_auth_header("GET", url_encoded),
|
||||
webdav_read_cb, webdav_cb_st);
|
||||
RARCH_DBG("[webdav] GET %s\n", url_encoded);
|
||||
auth_header = webdav_get_auth_header("GET", url_encoded);
|
||||
task_push_http_transfer_with_headers(url_encoded, true, NULL, auth_header, webdav_read_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -615,11 +638,20 @@ static void webdav_mkdir_cb(retro_task_t *task, void *task_data, void *user_data
|
||||
{
|
||||
webdav_mkdir_state_t *webdav_mkdir_st = (webdav_mkdir_state_t *)user_data;
|
||||
http_transfer_data_t *data = (http_transfer_data_t*)task_data;
|
||||
char *auth_header;
|
||||
|
||||
if (!webdav_mkdir_st)
|
||||
return;
|
||||
|
||||
/* TODO: it's possible we get a 401 here and need to redo the auth check with this request */
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
RARCH_DBG("[webdav] MKCOL %s\n", webdav_mkdir_st->url);
|
||||
auth_header = webdav_get_auth_header("MKCOL", webdav_mkdir_st->url);
|
||||
task_push_webdav_mkdir(webdav_mkdir_st->url, true, auth_header, webdav_mkdir_cb, webdav_mkdir_st);
|
||||
free(auth_header);
|
||||
return;
|
||||
}
|
||||
|
||||
/* HTTP 405 on MKCOL means it's already there */
|
||||
if (!data || data->status < 200 || (data->status >= 400 && data->status != 405))
|
||||
{
|
||||
@ -638,9 +670,9 @@ static void webdav_mkdir_cb(retro_task_t *task, void *task_data, void *user_data
|
||||
{
|
||||
*webdav_mkdir_st->last_slash = '\0';
|
||||
RARCH_DBG("[webdav] MKCOL %s\n", webdav_mkdir_st->url);
|
||||
task_push_webdav_mkdir(webdav_mkdir_st->url, true,
|
||||
webdav_get_auth_header("MKCOL", webdav_mkdir_st->url),
|
||||
webdav_mkdir_cb, webdav_mkdir_st);
|
||||
auth_header = webdav_get_auth_header("MKCOL", webdav_mkdir_st->url);
|
||||
task_push_webdav_mkdir(webdav_mkdir_st->url, true, auth_header, webdav_mkdir_cb, webdav_mkdir_st);
|
||||
free(auth_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -668,6 +700,7 @@ static void webdav_ensure_dir(const char *dir, webdav_mkdir_cb_t cb, webdav_cb_s
|
||||
webdav_mkdir_cb(NULL, &data, webdav_mkdir_st, NULL);
|
||||
}
|
||||
|
||||
static void webdav_do_update(bool success, webdav_cb_state_t *webdav_cb_st);
|
||||
static void webdav_update_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||
{
|
||||
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||
@ -679,7 +712,12 @@ static void webdav_update_cb(retro_task_t *task, void *task_data, void *user_dat
|
||||
else if (!data)
|
||||
RARCH_WARN("[webdav] could not upload %s\n", webdav_cb_st ? webdav_cb_st->path : "<unknown>");
|
||||
|
||||
/* TODO: it's possible we get a 401 here and need to redo the auth check with this request */
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
webdav_do_update(true, webdav_cb_st);
|
||||
return;
|
||||
}
|
||||
|
||||
if (webdav_cb_st)
|
||||
{
|
||||
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, webdav_cb_st->rfile);
|
||||
@ -696,6 +734,7 @@ static void webdav_do_update(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||
char url[PATH_MAX_LENGTH];
|
||||
void *buf;
|
||||
int64_t len;
|
||||
char *auth_header;
|
||||
|
||||
if (!webdav_cb_st)
|
||||
return;
|
||||
@ -717,9 +756,9 @@ static void webdav_do_update(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||
|
||||
RARCH_DBG("[webdav] PUT %s\n", url_encoded);
|
||||
task_push_webdav_put(url_encoded, buf, len, true,
|
||||
webdav_get_auth_header("PUT", url_encoded),
|
||||
webdav_update_cb, webdav_cb_st);
|
||||
auth_header = webdav_get_auth_header("PUT", url_encoded);
|
||||
task_push_webdav_put(url_encoded, buf, len, true, auth_header, webdav_update_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
@ -758,7 +797,23 @@ static void webdav_delete_cb(retro_task_t *task, void *task_data, void *user_dat
|
||||
else if (!data)
|
||||
RARCH_WARN("[webdav] could not delete %s\n", webdav_cb_st ? webdav_cb_st->path : "<unknown>");
|
||||
|
||||
/* TODO: it's possible we get a 401 here and need to redo the auth check with this request */
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||
char url[PATH_MAX_LENGTH];
|
||||
char url_encoded[PATH_MAX_LENGTH];
|
||||
char *auth_header;
|
||||
|
||||
fill_pathname_join_special(url, webdav_st->url, webdav_cb_st->path, sizeof(url));
|
||||
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||
|
||||
RARCH_DBG("[webdav] DELETE %s\n", url_encoded);
|
||||
auth_header = webdav_get_auth_header("DELETE", url_encoded);
|
||||
task_push_webdav_delete(url_encoded, true, auth_header, webdav_delete_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
return;
|
||||
}
|
||||
|
||||
if (webdav_cb_st)
|
||||
{
|
||||
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, NULL);
|
||||
@ -768,6 +823,7 @@ static void webdav_delete_cb(retro_task_t *task, void *task_data, void *user_dat
|
||||
RARCH_WARN("[webdav] missing cb data in delete?\n");
|
||||
}
|
||||
|
||||
static void webdav_do_backup(bool success, webdav_cb_state_t *webdav_cb_st);
|
||||
static void webdav_backup_cb(retro_task_t *task, void *task_data, void *user_data, const char *err)
|
||||
{
|
||||
webdav_cb_state_t *webdav_cb_st = (webdav_cb_state_t *)user_data;
|
||||
@ -779,7 +835,12 @@ static void webdav_backup_cb(retro_task_t *task, void *task_data, void *user_dat
|
||||
else if (!data)
|
||||
RARCH_WARN("[webdav] could not backup %s\n", webdav_cb_st ? webdav_cb_st->path : "<unknown>");
|
||||
|
||||
/* TODO: it's possible we get a 401 here and need to redo the auth check with this request */
|
||||
if (webdav_needs_reauth(data))
|
||||
{
|
||||
webdav_do_backup(true, webdav_cb_st);
|
||||
return;
|
||||
}
|
||||
|
||||
if (webdav_cb_st)
|
||||
{
|
||||
webdav_cb_st->cb(webdav_cb_st->user_data, webdav_cb_st->path, success, NULL);
|
||||
@ -799,6 +860,7 @@ static void webdav_do_backup(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||
size_t len;
|
||||
struct tm tm_;
|
||||
time_t cur_time = time(NULL);
|
||||
char *auth_header;
|
||||
|
||||
if (!webdav_cb_st)
|
||||
return;
|
||||
@ -821,9 +883,9 @@ static void webdav_do_backup(bool success, webdav_cb_state_t *webdav_cb_st)
|
||||
net_http_urlencode_full(dest_encoded, dest, sizeof(dest_encoded));
|
||||
|
||||
RARCH_DBG("[webdav] MOVE %s -> %s\n", url_encoded, dest_encoded);
|
||||
task_push_webdav_move(url_encoded, dest_encoded, true,
|
||||
webdav_get_auth_header("MOVE", url_encoded),
|
||||
webdav_backup_cb, webdav_cb_st);
|
||||
auth_header = webdav_get_auth_header("MOVE", url_encoded);
|
||||
task_push_webdav_move(url_encoded, dest_encoded, true, auth_header, webdav_backup_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
}
|
||||
|
||||
static bool webdav_delete(const char *path, cloud_sync_complete_handler_t cb, void *user_data)
|
||||
@ -845,14 +907,15 @@ static bool webdav_delete(const char *path, cloud_sync_complete_handler_t cb, vo
|
||||
webdav_state_t *webdav_st = webdav_state_get_ptr();
|
||||
char url_encoded[PATH_MAX_LENGTH];
|
||||
char url[PATH_MAX_LENGTH];
|
||||
char *auth_header;
|
||||
|
||||
fill_pathname_join_special(url, webdav_st->url, path, sizeof(url));
|
||||
net_http_urlencode_full(url_encoded, url, sizeof(url_encoded));
|
||||
|
||||
RARCH_DBG("[webdav] DELETE %s\n", url_encoded);
|
||||
task_push_webdav_delete(url_encoded, true,
|
||||
webdav_get_auth_header("DELETE", url_encoded),
|
||||
webdav_delete_cb, webdav_cb_st);
|
||||
auth_header = webdav_get_auth_header("DELETE", url_encoded);
|
||||
task_push_webdav_delete(url_encoded, true, auth_header, webdav_delete_cb, webdav_cb_st);
|
||||
free(auth_header);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ void cloud_sync_find_driver(
|
||||
cloud_sync_drivers[i];
|
||||
else
|
||||
{
|
||||
if (verbosity_enabled)
|
||||
if (verbosity_enabled && settings->arrays.cloud_sync_driver[0])
|
||||
{
|
||||
unsigned d;
|
||||
RARCH_ERR("Couldn't find any %s named \"%s\"\n", prefix,
|
||||
@ -80,10 +80,11 @@ void cloud_sync_find_driver(
|
||||
for (d = 0; cloud_sync_drivers[d]; d++)
|
||||
RARCH_LOG_OUTPUT("\t%s\n", cloud_sync_drivers[d]->ident);
|
||||
|
||||
RARCH_WARN("Going to default to first %s...\n", prefix);
|
||||
RARCH_WARN("Going to default to null...\n");
|
||||
}
|
||||
|
||||
cloud_sync_st->driver = (const cloud_sync_driver_t*)cloud_sync_drivers[0];
|
||||
i = (int)driver_find_index("cloud_sync_driver", "null");
|
||||
cloud_sync_st->driver = (const cloud_sync_driver_t*)cloud_sync_drivers[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +279,7 @@ static void *task_push_http_transfer_generic(
|
||||
return NULL;
|
||||
|
||||
method = net_http_connection_method(conn);
|
||||
if (method && (method[0] == 'P' || method[0] == 'p'))
|
||||
if (!string_is_equal(method, "GET"))
|
||||
{
|
||||
/* POST requests usually mutate the server, so assume multiple calls are
|
||||
* intended, even if they're duplicated. Additionally, they may differ
|
||||
|
Loading…
x
Reference in New Issue
Block a user