mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-29 12:19:03 +03:00
CSync & Propagator: Support a direct download URL
This is for server file backends that support sending a direct URL.
This commit is contained in:
parent
4d4ae9374b
commit
4d4eab8b1c
17 changed files with 168 additions and 30 deletions
|
@ -442,6 +442,8 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||||
trav.rename_path = cur->destpath;
|
trav.rename_path = cur->destpath;
|
||||||
trav.etag = cur->etag;
|
trav.etag = cur->etag;
|
||||||
trav.file_id = cur->file_id;
|
trav.file_id = cur->file_id;
|
||||||
|
trav.directDownloadUrl = cur->directDownloadUrl;
|
||||||
|
trav.directDownloadCookies = cur->directDownloadCookies;
|
||||||
trav.inode = cur->inode;
|
trav.inode = cur->inode;
|
||||||
|
|
||||||
trav.error_status = cur->error_status;
|
trav.error_status = cur->error_status;
|
||||||
|
@ -464,7 +466,7 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
|
||||||
|
|
||||||
rc = (*visitor)(&trav, twctx->userdata);
|
rc = (*visitor)(&trav, twctx->userdata);
|
||||||
cur->instruction = trav.instruction;
|
cur->instruction = trav.instruction;
|
||||||
if (trav.etag != cur->etag) {
|
if (trav.etag != cur->etag) { // FIXME It would be nice to have this documented
|
||||||
SAFE_FREE(cur->etag);
|
SAFE_FREE(cur->etag);
|
||||||
cur->etag = c_strdup(trav.etag);
|
cur->etag = c_strdup(trav.etag);
|
||||||
}
|
}
|
||||||
|
@ -912,6 +914,8 @@ int csync_abort_requested(CSYNC *ctx)
|
||||||
void csync_file_stat_free(csync_file_stat_t *st)
|
void csync_file_stat_free(csync_file_stat_t *st)
|
||||||
{
|
{
|
||||||
if (st) {
|
if (st) {
|
||||||
|
SAFE_FREE(st->directDownloadUrl);
|
||||||
|
SAFE_FREE(st->directDownloadCookies);
|
||||||
SAFE_FREE(st->etag);
|
SAFE_FREE(st->etag);
|
||||||
SAFE_FREE(st->destpath);
|
SAFE_FREE(st->destpath);
|
||||||
SAFE_FREE(st);
|
SAFE_FREE(st);
|
||||||
|
|
|
@ -189,6 +189,8 @@ struct csync_tree_walk_file_s {
|
||||||
const char *rename_path;
|
const char *rename_path;
|
||||||
const char *etag;
|
const char *etag;
|
||||||
const char *file_id;
|
const char *file_id;
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
struct {
|
struct {
|
||||||
int64_t size;
|
int64_t size;
|
||||||
time_t modtime;
|
time_t modtime;
|
||||||
|
|
|
@ -515,6 +515,8 @@ static void results(void *userdata,
|
||||||
const char *resourcetype = NULL;
|
const char *resourcetype = NULL;
|
||||||
const char *md5sum = NULL;
|
const char *md5sum = NULL;
|
||||||
const char *file_id = NULL;
|
const char *file_id = NULL;
|
||||||
|
const char *directDownloadUrl = NULL;
|
||||||
|
const char *directDownloadCookies = NULL;
|
||||||
const ne_status *status = NULL;
|
const ne_status *status = NULL;
|
||||||
char *path = ne_path_unescape( uri->path );
|
char *path = ne_path_unescape( uri->path );
|
||||||
|
|
||||||
|
@ -540,6 +542,8 @@ static void results(void *userdata,
|
||||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||||
file_id = ne_propset_value( set, &ls_props[4] );
|
file_id = ne_propset_value( set, &ls_props[4] );
|
||||||
|
directDownloadUrl = ne_propset_value( set, &ls_props[5] );
|
||||||
|
directDownloadCookies = ne_propset_value( set, &ls_props[6] );
|
||||||
|
|
||||||
newres->type = resr_normal;
|
newres->type = resr_normal;
|
||||||
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
if( clength == NULL && resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||||
|
@ -563,6 +567,13 @@ static void results(void *userdata,
|
||||||
|
|
||||||
csync_vio_set_file_id(newres->file_id, file_id);
|
csync_vio_set_file_id(newres->file_id, file_id);
|
||||||
|
|
||||||
|
if (directDownloadUrl) {
|
||||||
|
newres->directDownloadUrl = c_strdup(directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (directDownloadCookies) {
|
||||||
|
newres->directDownloadCookies = c_strdup(directDownloadCookies);
|
||||||
|
}
|
||||||
|
|
||||||
/* prepend the new resource to the result list */
|
/* prepend the new resource to the result list */
|
||||||
newres->next = fetchCtx->list;
|
newres->next = fetchCtx->list;
|
||||||
fetchCtx->list = newres;
|
fetchCtx->list = newres;
|
||||||
|
|
|
@ -125,6 +125,8 @@ static const ne_propname ls_props[] = {
|
||||||
{ "DAV:", "resourcetype" },
|
{ "DAV:", "resourcetype" },
|
||||||
{ "DAV:", "getetag"},
|
{ "DAV:", "getetag"},
|
||||||
{ "http://owncloud.org/ns", "id"},
|
{ "http://owncloud.org/ns", "id"},
|
||||||
|
{ "http://owncloud.org/ns", "directDownloadUrl"},
|
||||||
|
{ "http://owncloud.org/ns", "directDownloadCookies"},
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +142,10 @@ typedef struct resource {
|
||||||
time_t modtime;
|
time_t modtime;
|
||||||
char* md5;
|
char* md5;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1];
|
char file_id[FILE_ID_BUF_SIZE+1];
|
||||||
|
// Those two are optional from the server. We can use those URL to download the file directly
|
||||||
|
// without going through the ownCloud instance.
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
|
|
||||||
struct resource *next;
|
struct resource *next;
|
||||||
} resource;
|
} resource;
|
||||||
|
|
|
@ -99,6 +99,8 @@ static void propfind_results_recursive(void *userdata,
|
||||||
{
|
{
|
||||||
struct resource *newres = 0;
|
struct resource *newres = 0;
|
||||||
const char *clength, *modtime, *file_id = NULL;
|
const char *clength, *modtime, *file_id = NULL;
|
||||||
|
const char *directDownloadUrl = NULL;
|
||||||
|
const char *directDownloadCookies = NULL;
|
||||||
const char *resourcetype = NULL;
|
const char *resourcetype = NULL;
|
||||||
const char *md5sum = NULL;
|
const char *md5sum = NULL;
|
||||||
const ne_status *status = NULL;
|
const ne_status *status = NULL;
|
||||||
|
@ -109,6 +111,7 @@ static void propfind_results_recursive(void *userdata,
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
csync_owncloud_ctx_t *ctx = (csync_owncloud_ctx_t*) userdata;
|
||||||
|
|
||||||
|
|
||||||
(void) status;
|
(void) status;
|
||||||
|
|
||||||
if (!ctx->propfind_recursive_cache) {
|
if (!ctx->propfind_recursive_cache) {
|
||||||
|
@ -127,6 +130,8 @@ static void propfind_results_recursive(void *userdata,
|
||||||
resourcetype = ne_propset_value( set, &ls_props[2] );
|
resourcetype = ne_propset_value( set, &ls_props[2] );
|
||||||
md5sum = ne_propset_value( set, &ls_props[3] );
|
md5sum = ne_propset_value( set, &ls_props[3] );
|
||||||
file_id = ne_propset_value( set, &ls_props[4] );
|
file_id = ne_propset_value( set, &ls_props[4] );
|
||||||
|
directDownloadUrl = ne_propset_value( set, &ls_props[5] );
|
||||||
|
directDownloadCookies = ne_propset_value( set, &ls_props[6] );
|
||||||
|
|
||||||
newres->type = resr_normal;
|
newres->type = resr_normal;
|
||||||
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
if( resourcetype && strncmp( resourcetype, "<DAV:collection>", 16 ) == 0) {
|
||||||
|
@ -157,6 +162,13 @@ static void propfind_results_recursive(void *userdata,
|
||||||
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
|
DEBUG_WEBDAV("propfind_results_recursive %s [%s] %s", newres->uri, newres->type == resr_collection ? "collection" : "file", newres->md5);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (directDownloadUrl) {
|
||||||
|
newres->directDownloadUrl = c_strdup(directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (directDownloadCookies) {
|
||||||
|
newres->directDownloadCookies = c_strdup(directDownloadCookies);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create new item in rb tree */
|
/* Create new item in rb tree */
|
||||||
if (newres->type == resr_collection) {
|
if (newres->type == resr_collection) {
|
||||||
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
|
DEBUG_WEBDAV("propfind_results_recursive %s is a folder", newres->uri);
|
||||||
|
|
|
@ -312,6 +312,15 @@ void resourceToFileStat(csync_vio_file_stat_t *lfs, struct resource *res )
|
||||||
}
|
}
|
||||||
|
|
||||||
csync_vio_file_stat_set_file_id(lfs, res->file_id);
|
csync_vio_file_stat_set_file_id(lfs, res->file_id);
|
||||||
|
|
||||||
|
if (res->directDownloadUrl) {
|
||||||
|
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL;
|
||||||
|
lfs->directDownloadUrl = c_strdup(res->directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (res->directDownloadCookies) {
|
||||||
|
lfs->fields |= CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES;
|
||||||
|
lfs->directDownloadCookies = c_strdup(res->directDownloadCookies);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* WebDAV does not deliver permissions. Set a default here. */
|
/* WebDAV does not deliver permissions. Set a default here. */
|
||||||
|
@ -346,6 +355,12 @@ struct resource* resource_dup(struct resource* o) {
|
||||||
if( o->md5 ) {
|
if( o->md5 ) {
|
||||||
r->md5 = c_strdup(o->md5);
|
r->md5 = c_strdup(o->md5);
|
||||||
}
|
}
|
||||||
|
if (o->directDownloadUrl) {
|
||||||
|
r->directDownloadUrl = c_strdup(o->directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (o->directDownloadCookies) {
|
||||||
|
r->directDownloadCookies = c_strdup(o->directDownloadCookies);
|
||||||
|
}
|
||||||
r->next = o->next;
|
r->next = o->next;
|
||||||
csync_vio_set_file_id(r->file_id, o->file_id);
|
csync_vio_set_file_id(r->file_id, o->file_id);
|
||||||
|
|
||||||
|
@ -360,6 +375,8 @@ void resource_free(struct resource* o) {
|
||||||
SAFE_FREE(old->uri);
|
SAFE_FREE(old->uri);
|
||||||
SAFE_FREE(old->name);
|
SAFE_FREE(old->name);
|
||||||
SAFE_FREE(old->md5);
|
SAFE_FREE(old->md5);
|
||||||
|
SAFE_FREE(old->directDownloadUrl);
|
||||||
|
SAFE_FREE(old->directDownloadCookies);
|
||||||
SAFE_FREE(old);
|
SAFE_FREE(old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,6 +398,8 @@ void free_fetchCtx( struct listdir_context *ctx )
|
||||||
SAFE_FREE(res->name);
|
SAFE_FREE(res->name);
|
||||||
SAFE_FREE(res->md5);
|
SAFE_FREE(res->md5);
|
||||||
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
|
memset( res->file_id, 0, FILE_ID_BUF_SIZE+1 );
|
||||||
|
SAFE_FREE(res->directDownloadUrl);
|
||||||
|
SAFE_FREE(res->directDownloadCookies);
|
||||||
|
|
||||||
newres = res->next;
|
newres = res->next;
|
||||||
SAFE_FREE(res);
|
SAFE_FREE(res);
|
||||||
|
|
|
@ -177,6 +177,9 @@ struct csync_file_stat_s {
|
||||||
char *destpath; /* for renames */
|
char *destpath; /* for renames */
|
||||||
const char *etag;
|
const char *etag;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
char file_id[FILE_ID_BUF_SIZE+1]; /* the ownCloud file id is fixed width of 21 byte. */
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
|
|
||||||
CSYNC_STATUS error_status;
|
CSYNC_STATUS error_status;
|
||||||
|
|
||||||
enum csync_instructions_e instruction; /* u32 */
|
enum csync_instructions_e instruction; /* u32 */
|
||||||
|
|
|
@ -369,6 +369,15 @@ out:
|
||||||
st->etag = c_strdup(fs->etag);
|
st->etag = c_strdup(fs->etag);
|
||||||
}
|
}
|
||||||
csync_vio_set_file_id(st->file_id, fs->file_id);
|
csync_vio_set_file_id(st->file_id, fs->file_id);
|
||||||
|
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL) {
|
||||||
|
SAFE_FREE(st->directDownloadUrl);
|
||||||
|
st->directDownloadUrl = c_strdup(fs->directDownloadUrl);
|
||||||
|
}
|
||||||
|
if (fs->fields & CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES) {
|
||||||
|
SAFE_FREE(st->directDownloadCookies);
|
||||||
|
st->directDownloadCookies = c_strdup(fs->directDownloadCookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fastout: /* target if the file information is read from database into st */
|
fastout: /* target if the file information is read from database into st */
|
||||||
st->phash = h;
|
st->phash = h;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "csync_private.h"
|
#include "csync_private.h"
|
||||||
#include "csync_util.h"
|
#include "csync_util.h"
|
||||||
|
@ -107,6 +108,7 @@ int csync_vio_stat(CSYNC *ctx, const char *uri, csync_vio_file_stat_t *buf) {
|
||||||
switch(ctx->replica) {
|
switch(ctx->replica) {
|
||||||
case REMOTE_REPLICA:
|
case REMOTE_REPLICA:
|
||||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
|
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "ERROR: Cannot call remote stat, not implemented");
|
||||||
|
assert(ctx->replica != REMOTE_REPLICA);
|
||||||
break;
|
break;
|
||||||
case LOCAL_REPLICA:
|
case LOCAL_REPLICA:
|
||||||
rc = csync_vio_local_stat(uri, buf);
|
rc = csync_vio_local_stat(uri, buf);
|
||||||
|
|
|
@ -36,6 +36,8 @@ void csync_vio_file_stat_destroy(csync_vio_file_stat_t *file_stat) {
|
||||||
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
if (file_stat->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||||
SAFE_FREE(file_stat->etag);
|
SAFE_FREE(file_stat->etag);
|
||||||
}
|
}
|
||||||
|
SAFE_FREE(file_stat->directDownloadUrl);
|
||||||
|
SAFE_FREE(file_stat->directDownloadCookies);
|
||||||
SAFE_FREE(file_stat->name);
|
SAFE_FREE(file_stat->name);
|
||||||
SAFE_FREE(file_stat);
|
SAFE_FREE(file_stat);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,9 @@ enum csync_vio_file_stat_fields_e {
|
||||||
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
// CSYNC_VIO_FILE_STAT_FIELDS_UID = 1 << 15,
|
||||||
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
// CSYNC_VIO_FILE_STAT_FIELDS_GID = 1 << 16,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
|
CSYNC_VIO_FILE_STAT_FIELDS_ETAG = 1 << 17,
|
||||||
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18
|
CSYNC_VIO_FILE_STAT_FIELDS_FILE_ID = 1 << 18,
|
||||||
|
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADURL = 1 << 19,
|
||||||
|
CSYNC_VIO_FILE_STAT_FIELDS_DIRECTDOWNLOADCOOKIES = 1 << 20
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +83,8 @@ struct csync_vio_file_stat_s {
|
||||||
char *name;
|
char *name;
|
||||||
char *etag;
|
char *etag;
|
||||||
char file_id[FILE_ID_BUF_SIZE+1];
|
char file_id[FILE_ID_BUF_SIZE+1];
|
||||||
|
char *directDownloadUrl;
|
||||||
|
char *directDownloadCookies;
|
||||||
|
|
||||||
time_t atime;
|
time_t atime;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
|
|
|
@ -83,7 +83,12 @@ protected:
|
||||||
QNetworkRequest req(request);
|
QNetworkRequest req(request);
|
||||||
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash);
|
||||||
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
//qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
|
||||||
req.setRawHeader(QByteArray("Cookie"), _cred->_token.toLocal8Bit());
|
|
||||||
|
// Append token cookie
|
||||||
|
QList<QNetworkCookie> cookies = request.header(QNetworkRequest::CookieHeader).value<QList<QNetworkCookie> >();
|
||||||
|
cookies.append(QNetworkCookie::parseCookies(_cred->_token.toUtf8()));
|
||||||
|
req.setHeader(QNetworkRequest::CookieHeader, QVariant::fromValue(cookies));
|
||||||
|
|
||||||
return MirallAccessManager::createRequest(op, req, outgoingData);
|
return MirallAccessManager::createRequest(op, req, outgoingData);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
@ -112,7 +117,7 @@ void TokenCredentials::syncContextPreInit (CSYNC* ctx)
|
||||||
|
|
||||||
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
|
void TokenCredentials::syncContextPreStart (CSYNC* ctx)
|
||||||
{
|
{
|
||||||
csync_set_module_property(ctx, "session_key", _token.toLocal8Bit().data());
|
csync_set_module_property(ctx, "session_key", _token.toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TokenCredentials::changed(AbstractCredentials* credentials) const
|
bool TokenCredentials::changed(AbstractCredentials* credentials) const
|
||||||
|
|
|
@ -494,6 +494,10 @@ void PropagateDownloadFileLegacy::start()
|
||||||
_propagator->_journal->commit("download file start");
|
_propagator->_journal->commit("download file start");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_item._directDownloadUrl.isEmpty()) {
|
||||||
|
qDebug() << Q_FUNC_INFO << "Direct download URL" << _item._directDownloadUrl << "not supported with legacy propagator, will go via ownCloud server";
|
||||||
|
}
|
||||||
|
|
||||||
/* actually do the request */
|
/* actually do the request */
|
||||||
int retry = 0;
|
int retry = 0;
|
||||||
|
|
||||||
|
|
|
@ -358,13 +358,38 @@ void PropagateUploadFileQNAM::abort()
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// DOES NOT take owncership of the device.
|
||||||
|
GETFileJob::GETFileJob(Account* account, const QString& path, QIODevice *device,
|
||||||
|
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
||||||
|
QObject* parent)
|
||||||
|
: AbstractNetworkJob(account, path, parent),
|
||||||
|
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
||||||
|
_errorStatus(SyncFileItem::NoStatus)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GETFileJob::GETFileJob(Account* account, const QUrl& url, QIODevice *device,
|
||||||
|
const QMap<QByteArray, QByteArray> &headers,
|
||||||
|
QObject* parent)
|
||||||
|
: AbstractNetworkJob(account, url.toEncoded(), parent),
|
||||||
|
_device(device), _headers(headers),
|
||||||
|
_errorStatus(SyncFileItem::NoStatus), _directDownloadUrl(url)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void GETFileJob::start() {
|
void GETFileJob::start() {
|
||||||
QNetworkRequest req;
|
QNetworkRequest req;
|
||||||
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
||||||
req.setRawHeader(it.key(), it.value());
|
req.setRawHeader(it.key(), it.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
setReply(davRequest("GET", path(), req));
|
if (_directDownloadUrl.isEmpty()) {
|
||||||
|
setReply(davRequest("GET", path(), req));
|
||||||
|
} else {
|
||||||
|
// Use direct URL
|
||||||
|
setReply(davRequest("GET", _directDownloadUrl, req));
|
||||||
|
}
|
||||||
setupConnections(reply());
|
setupConnections(reply());
|
||||||
|
|
||||||
if( reply()->error() != QNetworkReply::NoError ) {
|
if( reply()->error() != QNetworkReply::NoError ) {
|
||||||
|
@ -386,17 +411,21 @@ void GETFileJob::slotMetaDataChanged()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray etag = parseEtag(reply()->rawHeader("Etag"));
|
_etag = parseEtag(reply()->rawHeader("Etag"));
|
||||||
|
if (!_directDownloadUrl.isEmpty() && !_etag.isEmpty()) {
|
||||||
if (etag.isEmpty()) {
|
qDebug() << Q_FUNC_INFO << "Direct download used, ignoring server ETag" << _etag;
|
||||||
|
_etag = QByteArray(); // reset received ETag
|
||||||
|
} else if (!_directDownloadUrl.isEmpty()) {
|
||||||
|
// All fine, ETag empty and directDownloadUrl used
|
||||||
|
} else if (_etag.isEmpty()) {
|
||||||
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
|
qDebug() << Q_FUNC_INFO << "No E-Tag reply by server, considering it invalid";
|
||||||
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
|
_errorString = tr("No E-Tag received from server, check Proxy/Gateway");
|
||||||
_errorStatus = SyncFileItem::NormalError;
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
reply()->abort();
|
reply()->abort();
|
||||||
return;
|
return;
|
||||||
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != etag) {
|
} else if (!_expectedEtagForResume.isEmpty() && _expectedEtagForResume != _etag) {
|
||||||
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
|
qDebug() << Q_FUNC_INFO << "We received a different E-Tag for resuming!"
|
||||||
<< _expectedEtagForResume << "vs" << etag;
|
<< _expectedEtagForResume << "vs" << _etag;
|
||||||
_errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
|
_errorString = tr("We received a different E-Tag for resuming. Retrying next time.");
|
||||||
_errorStatus = SyncFileItem::NormalError;
|
_errorStatus = SyncFileItem::NormalError;
|
||||||
reply()->abort();
|
reply()->abort();
|
||||||
|
@ -431,6 +460,13 @@ void GETFileJob::slotReadyRead()
|
||||||
resetTimeout();
|
resetTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GETFileJob::slotTimeout()
|
||||||
|
{
|
||||||
|
_errorString = tr("Connection Timeout");
|
||||||
|
_errorStatus = SyncFileItem::FatalError;
|
||||||
|
reply()->abort();
|
||||||
|
}
|
||||||
|
|
||||||
void PropagateDownloadFileQNAM::start()
|
void PropagateDownloadFileQNAM::start()
|
||||||
{
|
{
|
||||||
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
if (_propagator->_abortRequested.fetchAndAddRelaxed(0))
|
||||||
|
@ -438,7 +474,7 @@ void PropagateDownloadFileQNAM::start()
|
||||||
|
|
||||||
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
|
qDebug() << Q_FUNC_INFO << _item._file << _propagator->_activeJobs;
|
||||||
|
|
||||||
// do a case clash check.
|
// do a klaas' case clash check.
|
||||||
if( _propagator->localFileNameClash(_item._file) ) {
|
if( _propagator->localFileNameClash(_item._file) ) {
|
||||||
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
done( SyncFileItem::NormalError, tr("File %1 can not be downloaded because of a local file name clash!")
|
||||||
.arg(QDir::toNativeSeparators(_item._file)) );
|
.arg(QDir::toNativeSeparators(_item._file)) );
|
||||||
|
@ -490,8 +526,6 @@ void PropagateDownloadFileQNAM::start()
|
||||||
|
|
||||||
|
|
||||||
QMap<QByteArray, QByteArray> headers;
|
QMap<QByteArray, QByteArray> headers;
|
||||||
/* Allow compressed content by setting the header */
|
|
||||||
//headers["Accept-Encoding"] = "gzip";
|
|
||||||
|
|
||||||
if (_tmpFile.size() > 0) {
|
if (_tmpFile.size() > 0) {
|
||||||
quint64 done = _tmpFile.size();
|
quint64 done = _tmpFile.size();
|
||||||
|
@ -506,9 +540,22 @@ void PropagateDownloadFileQNAM::start()
|
||||||
_startSize = done;
|
_startSize = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
_job = new GETFileJob(AccountManager::instance()->account(),
|
if (_item._directDownloadUrl.isEmpty()) {
|
||||||
_propagator->_remoteFolder + _item._file,
|
// Normal job, download from oC instance
|
||||||
&_tmpFile, headers, expectedEtagForResume);
|
_job = new GETFileJob(AccountManager::instance()->account(),
|
||||||
|
_propagator->_remoteFolder + _item._file,
|
||||||
|
&_tmpFile, headers, expectedEtagForResume);
|
||||||
|
} else {
|
||||||
|
// We were provided a direct URL, use that one
|
||||||
|
if (!_item._directDownloadCookies.isEmpty()) {
|
||||||
|
headers["Cookie"] = _item._directDownloadCookies.toUtf8();
|
||||||
|
}
|
||||||
|
QUrl url = QUrl::fromUserInput(_item._directDownloadUrl);
|
||||||
|
_job = new GETFileJob(AccountManager::instance()->account(),
|
||||||
|
url,
|
||||||
|
&_tmpFile, headers);
|
||||||
|
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item._file << _item._directDownloadUrl;
|
||||||
|
}
|
||||||
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
_job->setTimeout(_propagator->httpTimeout() * 1000);
|
||||||
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
|
||||||
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
connect(_job, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(slotDownloadProgress(qint64,qint64)));
|
||||||
|
@ -546,7 +593,11 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_item._etag = parseEtag(job->reply()->rawHeader("Etag"));
|
if (!job->etag().isEmpty()) {
|
||||||
|
// The etag will be empty if we used a direct download URL.
|
||||||
|
// (If it was really empty by the server, the GETFileJob will have errored
|
||||||
|
_item._etag = parseEtag(job->etag());
|
||||||
|
}
|
||||||
_item._requestDuration = job->duration();
|
_item._requestDuration = job->duration();
|
||||||
_item._responseTimeStamp = job->responseTimestamp();
|
_item._responseTimeStamp = job->responseTimestamp();
|
||||||
|
|
||||||
|
@ -628,13 +679,4 @@ void PropagateDownloadFileQNAM::abort()
|
||||||
_job->reply()->abort();
|
_job->reply()->abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GETFileJob::slotTimeout()
|
|
||||||
{
|
|
||||||
_errorString = tr("Connection Timeout");
|
|
||||||
_errorStatus = SyncFileItem::FatalError;
|
|
||||||
reply()->abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,15 +110,18 @@ class GETFileJob : public AbstractNetworkJob {
|
||||||
QString _errorString;
|
QString _errorString;
|
||||||
QByteArray _expectedEtagForResume;
|
QByteArray _expectedEtagForResume;
|
||||||
SyncFileItem::Status _errorStatus;
|
SyncFileItem::Status _errorStatus;
|
||||||
|
QUrl _directDownloadUrl;
|
||||||
|
QByteArray _etag;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// DOES NOT take owncership of the device.
|
// DOES NOT take owncership of the device.
|
||||||
explicit GETFileJob(Account* account, const QString& path, QIODevice *device,
|
explicit GETFileJob(Account* account, const QString& path, QIODevice *device,
|
||||||
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
const QMap<QByteArray, QByteArray> &headers, QByteArray expectedEtagForResume,
|
||||||
QObject* parent = 0)
|
QObject* parent = 0);
|
||||||
: AbstractNetworkJob(account, path, parent),
|
// For directDownloadUrl:
|
||||||
_device(device), _headers(headers), _expectedEtagForResume(expectedEtagForResume),
|
explicit GETFileJob(Account* account, const QUrl& url, QIODevice *device,
|
||||||
_errorStatus(SyncFileItem::NoStatus) {}
|
const QMap<QByteArray, QByteArray> &headers,
|
||||||
|
QObject* parent = 0);
|
||||||
|
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual bool finished() {
|
virtual bool finished() {
|
||||||
|
@ -134,6 +137,8 @@ public:
|
||||||
|
|
||||||
virtual void slotTimeout();
|
virtual void slotTimeout();
|
||||||
|
|
||||||
|
QByteArray &etag() { return _etag; }
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finishedSignal();
|
void finishedSignal();
|
||||||
|
|
|
@ -263,6 +263,12 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||||
item._instruction = file->instruction;
|
item._instruction = file->instruction;
|
||||||
item._direction = SyncFileItem::None;
|
item._direction = SyncFileItem::None;
|
||||||
item._fileId = file->file_id;
|
item._fileId = file->file_id;
|
||||||
|
if (file->directDownloadUrl) {
|
||||||
|
item._directDownloadUrl = QString::fromUtf8( file->directDownloadUrl );
|
||||||
|
}
|
||||||
|
if (file->directDownloadCookies) {
|
||||||
|
item._directDownloadCookies = QString::fromUtf8( file->directDownloadCookies );
|
||||||
|
}
|
||||||
|
|
||||||
// record the seen files to be able to clean the journal later
|
// record the seen files to be able to clean the journal later
|
||||||
_seenFiles[item._file] = QString();
|
_seenFiles[item._file] = QString();
|
||||||
|
|
|
@ -86,6 +86,8 @@ public:
|
||||||
quint64 _inode;
|
quint64 _inode;
|
||||||
bool _should_update_etag;
|
bool _should_update_etag;
|
||||||
QByteArray _fileId;
|
QByteArray _fileId;
|
||||||
|
QString _directDownloadUrl;
|
||||||
|
QString _directDownloadCookies;
|
||||||
bool _blacklistedInDb;
|
bool _blacklistedInDb;
|
||||||
|
|
||||||
// Variables usefull to report to the user
|
// Variables usefull to report to the user
|
||||||
|
|
Loading…
Reference in a new issue