From 7b1d58962694bd6dd1971d6eda673ddc0877f7c2 Mon Sep 17 00:00:00 2001 From: aunsane Date: Thu, 27 Apr 2017 01:53:37 +0300 Subject: CloudFile: fix uploading small files for GDrive and OneDrive --- plugins/CloudFile/src/Services/google_api.h | 40 ++++++++++++++-- plugins/CloudFile/src/Services/google_service.cpp | 55 +++++++++++++++------- plugins/CloudFile/src/Services/google_service.h | 5 +- plugins/CloudFile/src/Services/microsoft_api.h | 29 ++++++++---- .../CloudFile/src/Services/microsoft_service.cpp | 54 +++++++++++++++------ plugins/CloudFile/src/Services/microsoft_service.h | 1 + 6 files changed, 140 insertions(+), 44 deletions(-) (limited to 'plugins/CloudFile/src/Services') diff --git a/plugins/CloudFile/src/Services/google_api.h b/plugins/CloudFile/src/Services/google_api.h index 50d12fc5d3..b609507caa 100644 --- a/plugins/CloudFile/src/Services/google_api.h +++ b/plugins/CloudFile/src/Services/google_api.h @@ -51,10 +51,42 @@ namespace GDriveAPI } }; - class StartUploadFileRequest : public HttpRequest + class UploadFileRequest : public HttpRequest + { + public: + UploadFileRequest(const char *token, const char *name, const char *data, size_t size) : + HttpRequest(REQUEST_POST, GDRIVE_UPLOAD) + { + AddBearerAuthHeader(token); + AddHeader("Content-Type", "multipart/related; boundary=upload"); + + CMStringA body = "--upload"; + body.AppendChar(0x0A); + body.Append("Content-Type: application/json"); + body.AppendChar(0x0A); + body.AppendChar(0x0A); + body.Append("{"); + body.AppendFormat("\"name\": \"%s\"", name); + body.Append("}"); + body.AppendChar(0x0A); + body.AppendChar(0x0A); + body.Append("--upload"); + body.AppendChar(0x0A); + body.Append("Content-Type: application/octet-stream"); + body.AppendChar(0x0A); + body.AppendChar(0x0A); + body.Append(data, size); + body.AppendChar(0x0A); + body.Append("--upload--"); + + SetData(body.GetBuffer(), body.GetLength()); + } + }; + + class CreateUploadSessionRequest : public HttpRequest { public: - StartUploadFileRequest(const char *token, const char *name) : + CreateUploadSessionRequest(const char *token, const char *name) : HttpRequest(REQUEST_POST, GDRIVE_UPLOAD) { AddUrlParameter("uploadType=resumable"); @@ -70,10 +102,10 @@ namespace GDriveAPI } }; - class UploadFileRequest : public HttpRequest + class UploadFileChunkRequest : public HttpRequest { public: - UploadFileRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) : + UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize): HttpRequest(REQUEST_PUT, uploadUri) { uint64_t rangeMin = offset; diff --git a/plugins/CloudFile/src/Services/google_service.cpp b/plugins/CloudFile/src/Services/google_service.cpp index af7d0400bd..bf6c7de90e 100644 --- a/plugins/CloudFile/src/Services/google_service.cpp +++ b/plugins/CloudFile/src/Services/google_service.cpp @@ -136,10 +136,21 @@ void CGDriveService::HandleJsonError(JSONNode &node) } } -void CGDriveService::StartUploadFile(char *uploadUri, const char *name) +void CGDriveService::UploadFile(const char *name, const char *data, size_t size, char *fileId) { ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); - GDriveAPI::StartUploadFileRequest request(token, name); + GDriveAPI::UploadFileRequest request(token, name, data, size); + NLHR_PTR response(request.Send(hConnection)); + + JSONNode root = GetJsonResponse(response); + JSONNode node = root.at("id"); + mir_strcpy(fileId, node.as_string().c_str()); +} + +void CGDriveService::CreateUploadSession(char *uploadUri, const char *name) +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + GDriveAPI::CreateUploadSessionRequest request(token, name); NLHR_PTR response(request.Send(hConnection)); if (response == NULL) @@ -161,9 +172,9 @@ void CGDriveService::StartUploadFile(char *uploadUri, const char *name) throw Exception(HttpStatusToError(response->resultCode)); } -void CGDriveService::UploadFile(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId) +void CGDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId) { - GDriveAPI::UploadFileRequest request(uploadUri, chunk, chunkSize, offset, fileSize); + GDriveAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize); NLHR_PTR response(request.Send(hConnection)); if (response == NULL) @@ -174,8 +185,8 @@ void CGDriveService::UploadFile(const char *uploadUri, const char *chunk, size_t if (HTTP_CODE_SUCCESS(response->resultCode)) { JSONNode root = GetJsonResponse(response); - JSONNode id = root.at("id"); - mir_strcpy(fileId, id.as_string().c_str()); + JSONNode node = root.at("id"); + mir_strcpy(fileId, node.as_string().c_str()); return; } @@ -241,25 +252,37 @@ UINT CGDriveService::Upload(FileTransferParam *ftp) uint64_t offset = 0; char fileId[32]; - char uploadUri[1024]; - StartUploadFile(uploadUri, T2Utf(fileName)); size_t chunkSize = ftp->GetCurrentFileChunkSize(); mir_ptrchunk((char*)mir_calloc(chunkSize)); - size_t size = 0; - for (size_t i = 0; i < (fileSize / chunkSize); i++) + if (chunkSize == fileSize) { ftp->CheckCurrentFile(); - size = ftp->ReadCurrentFile(chunk, chunkSize); - if (size == 0) - break; + size_t size = ftp->ReadCurrentFile(chunk, chunkSize); + + UploadFile(chunk, T2Utf(fileName), size, fileId); + } + else + { + char uploadUri[1024]; + CreateUploadSession(uploadUri, T2Utf(fileName)); + + size_t size = 0; + for (size_t i = 0; i < (fileSize / chunkSize); i++) + { + ftp->CheckCurrentFile(); + + size = ftp->ReadCurrentFile(chunk, chunkSize); + if (size == 0) + break; - UploadFile(uploadUri, chunk, size, offset, fileSize, fileId); + UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); - offset += size; - ftp->Progress(size); + offset += size; + ftp->Progress(size); + } } if (!wcschr(fileName, L'\\')) { diff --git a/plugins/CloudFile/src/Services/google_service.h b/plugins/CloudFile/src/Services/google_service.h index a35827eaf8..1da21b5fef 100644 --- a/plugins/CloudFile/src/Services/google_service.h +++ b/plugins/CloudFile/src/Services/google_service.h @@ -9,8 +9,9 @@ private: void HandleJsonError(JSONNode &node); - void StartUploadFile(char *uploadUri, const char *name); - void UploadFile(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId); + void UploadFile(const char *name, const char *data, size_t size, char *fileId); + void CreateUploadSession(char *uploadUri, const char *name); + void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId); void CreateFolder(const char *path); void CreateSharedLink(const char *fileId, char *url); diff --git a/plugins/CloudFile/src/Services/microsoft_api.h b/plugins/CloudFile/src/Services/microsoft_api.h index 1c3c323520..395d6e434d 100644 --- a/plugins/CloudFile/src/Services/microsoft_api.h +++ b/plugins/CloudFile/src/Services/microsoft_api.h @@ -37,21 +37,35 @@ namespace OneDriveAPI } }; - /*class RevokeAccessTokenRequest : public HttpRequest + class UploadFileRequest : public HttpRequest { public: - RevokeAccessTokenRequest(const char *token) : - HttpRequest(REQUEST_POST, MS_OAUTH "/logout") + UploadFileRequest(const char *token, const char *name, const char *data, size_t size) : + HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/special/approot:/%s:/content", ptrA(mir_urlEncode(name))) { - AddUrlParameter("token=%s", token); + AddUrlParameter("@microsoft.graph.conflictBehavior=rename"); + + AddBearerAuthHeader(token); + + SetData(data, size); + } + + UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size) : + HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/items/{parent-id}:/{filename}:/content", parentId, ptrA(mir_urlEncode(name))) + { + AddUrlParameter("@microsoft.graph.conflictBehavior=rename"); + + AddBearerAuthHeader(token); + + SetData(data, size); } - };*/ + }; class CreateUploadSessionRequest : public HttpRequest { public: CreateUploadSessionRequest(const char *token, const char *name) : - HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/special/approot:/%s:/createUploadSession", name) + HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/special/approot:/%s:/createUploadSession", ptrA(mir_urlEncode(name))) { AddBearerAuthHeader(token); AddHeader("Content-Type", "application/json"); @@ -59,8 +73,7 @@ namespace OneDriveAPI JSONNode item(JSON_NODE); item.set_name("item"); item - << JSONNode("@microsoft.graph.conflictBehavior", "rename") - << JSONNode("name", name); + << JSONNode("@microsoft.graph.conflictBehavior", "rename"); JSONNode params(JSON_NODE); params << item; diff --git a/plugins/CloudFile/src/Services/microsoft_service.cpp b/plugins/CloudFile/src/Services/microsoft_service.cpp index 209458b5c5..0cf41eb738 100644 --- a/plugins/CloudFile/src/Services/microsoft_service.cpp +++ b/plugins/CloudFile/src/Services/microsoft_service.cpp @@ -127,6 +127,20 @@ void COneDriveService::HandleJsonError(JSONNode &node) } } +void COneDriveService::UploadFile(const char *parentId, const char *name, const char *data, size_t size, char *fileId) +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + OneDriveAPI::UploadFileRequest *request = mir_strlen(parentId) + ? new OneDriveAPI::UploadFileRequest(token, parentId, name, data, size) + : new OneDriveAPI::UploadFileRequest(token, name, data, size); + NLHR_PTR response(request->Send(hConnection)); + delete request; + + JSONNode root = GetJsonResponse(response); + JSONNode node = root.at("id"); + mir_strcpy(fileId, node.as_string().c_str()); +} + void COneDriveService::CreateUploadSession(char *uploadUri, const char *name, const char *parentId) { ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); @@ -154,8 +168,8 @@ void COneDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, if (HTTP_CODE_SUCCESS(response->resultCode)) { JSONNode root = GetJsonResponse(response); - JSONNode id = root.at("id"); - mir_strcpy(itemId, id.as_string().c_str()); + JSONNode node = root.at("id"); + mir_strcpy(itemId, node.as_string().c_str()); return; } @@ -183,7 +197,7 @@ void COneDriveService::CreateSharedLink(const char *itemId, char *url) JSONNode root = GetJsonResponse(response); JSONNode node = root.at("link"); - JSONNode webUrl = root.at("webUrl"); + JSONNode webUrl = node.at("webUrl"); mir_strcpy(url, webUrl.as_string().c_str()); } @@ -216,25 +230,37 @@ UINT COneDriveService::Upload(FileTransferParam *ftp) uint64_t offset = 0; char fileId[32]; - char uploadUri[1024]; - CreateUploadSession(uploadUri, T2Utf(fileName), folderId); size_t chunkSize = ftp->GetCurrentFileChunkSize(); mir_ptrchunk((char*)mir_calloc(chunkSize)); - - size_t size = 0; - for (size_t i = 0; i < (fileSize / chunkSize); i++) + + if (chunkSize == fileSize) { ftp->CheckCurrentFile(); - size = ftp->ReadCurrentFile(chunk, chunkSize); - if (size == 0) - break; + size_t size = ftp->ReadCurrentFile(chunk, chunkSize); + + UploadFile(folderId, T2Utf(fileName), chunk, size, fileId); + } + else + { + char uploadUri[1024]; + CreateUploadSession(uploadUri, T2Utf(fileName), folderId); + + size_t size = 0; + for (size_t i = 0; i < (fileSize / chunkSize); i++) + { + ftp->CheckCurrentFile(); + + size = ftp->ReadCurrentFile(chunk, chunkSize); + if (size == 0) + break; - UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); + UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); - offset += size; - ftp->Progress(size); + offset += size; + ftp->Progress(size); + } } if (!wcschr(fileName, L'\\')) { diff --git a/plugins/CloudFile/src/Services/microsoft_service.h b/plugins/CloudFile/src/Services/microsoft_service.h index 8c3c30e035..3b49e1f6f3 100644 --- a/plugins/CloudFile/src/Services/microsoft_service.h +++ b/plugins/CloudFile/src/Services/microsoft_service.h @@ -8,6 +8,7 @@ private: void HandleJsonError(JSONNode &node); + void UploadFile(const char *parentId, const char *name, const char *data, size_t size, char *fileId); void CreateUploadSession(char *uploadUri, const char *name, const char *parentId = NULL); void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *itemId); void CreateFolder(const char *path, char *itemId); -- cgit v1.2.3