2.5.3 Resuming the Upload of a File
In this scenario, the client application will resume a previously interrupted file upload by detecting that the file to be uploaded to the server
already exists in the target folder, but in a “partially uploaded” state.
To support this kind of resume upload action, the Thru Server API has been extended to provide the client applications a method
to inquire whether there are any partially uploaded files in a given folder that match a provided file name list.
The method is not exposed as a traditional web service method, but, instead, is exposed as RESTful-type of endpoint, published in the following URL:
http(s)://<application-root>/WS4/FTHAppletService.ashx
The endpoint expects two parameters:
Operation:
o GetInternalResumableUploadFiles (for internal uploads)
o GetExternalResumableUploadFiles (for external uploads)
Message:
An FTHAppletUploadData structure, serialized as XML and URL-encoded (to support files with Unicode names).
As a result to this call, an FTHAppletUploadData structure, serialized as XML and URL-encoded, will be returned in the body of the response.
The FTHAppletUploadData structure is defined as:
<FTHAppletUploadData>
<SessionID />
<ParentFolderID />
<UserID />
<FileUploadData>
[<FTHFileUploadData>
<FileID/>
<Name/>
<ServerFilePath/>
<Size/>
<PartialUpload/>
</FTHFileUploadData>]* (zero or more elements)
</FileUploadData>
</FTHAppletUploadData>
In C# or Java, FTHAppletUploadData structure can be defined as:
FTHAppletUploadData
{
String SessionID;
int ParentFolderID;
int UserID;
FTHFileUploadData[] FileUploadData;
}
FTHFileUploadData
{
int FileID;
String Name;
String ServerFilePath;
long Size;
bool PartialUpload;
}
The definition of each element of the FTHAppletUploadData structure is explained below.
FTHAppletUploadData
Element | Definition |
---|---|
SessionID | Contains the ID of the current session under which the upload operation is being performed. Required for the request message, with internal download operations. |
ParentFolderID | The ID of the folder to which the files will be uploaded. Required for the request message, with internal download operations. |
UserID | The ID of the user that owns the Dropbox folder to which the files will be uploaded. Required for the request message, with external download operations. |
FileUploadData | An array with information for each file that will be uploaded to the server. |
FileID | The ID of the corresponding partially uploaded file in the server. Returned by the response message. |
---|---|
Name | The name of the file being uploaded, with no directory information. Required for the request message. Uploaded files will be compared with existing files in the server based on their names. The server will also take in consideration versioned names. Files that were, upon upload, renamed to a different name with a sequential number (Uploaded “Image.jpg” => Saved Image1].jpg”) |
ServerFilePath | The path in the server for the corresponding partially uploaded file. Returned by the response message. |
Size | The size of the file being uploaded (request) or the current size of the corresponding partially uploaded file in the server (response). Required for the request message and returned by the response message. |
PartialUpload | Indicates if the matching file in the server is partially uploaded. Returned by the response message. It will always have a value of “true” (see following explanation). |
Note that the current protocol behavior is to re-add the uploaded file information to the FileUploadData array member in the response message,
if a matching file with partial content is found in the server.
As a result, the response message will probably contain fewer files than the request message submitted, since only the ones flagged with having a corresponding file with partial content (PartialUpload == true) will be returned.
Also, because of the way the protocol is designed, only allowing one parent folder ID (ParentFolderID) to be sent for each request, that implies that if user is uploading a multi-level set of files and folder, the client will have to send a separate message for each uploaded folder to inquire whether there are corresponding files with partial content in the folders.
So, we will walk through a real scenario, where 3 files will be uploaded through an internal upload operation:
One of them corresponding to a file whose upload has been previously interrupted.
Since it is an internal upload scenario, the app has connected to the server and been provided a Session ID (SessionID_NNN).
Also, the ID of target folder in the server is already known (RootFolderID_NNN).
![](../__attachments/2003402753/54.png?inst-v=533adeab-defe-4d59-a386-ead535dbfa6e)
As shown in the screenshot above, “Test.bmp,” “SP Connector.doc” and “7.5 Webinar.pptx” are being uploaded.
The first thing the client application needs to do is to send the “GetInternalResumableUploadFiles” message to the FTHAppletService endpoint in order to find out whether there are partially uploaded files in the server that correspond with the files to be uploaded.
GetInternalResumableUploadFiles Request
Operation: GetInternalResumableUploadFiles
Message:
<FTHAppletUploadData>
<SessionID>SessionID_NNN</SessionID>
<ParentFolderID>RootFolderID_NNN</ParentFolderID>
<UserID>0</UserID>
<FileUploadData>
<FTHFileUploadData>
<FileID>0</FileID>
<Name>Test.bmp</Name>
<ServerFilePath></ServerFilePath>
<Size>3072</Size>
<PartialUpload>false</PartialUpload>
</FTHFileUploadData>
<FTHFileUploadData>
<FileID>0</FileID>
<Name>SP Connector.doc </Name>
<ServerFilePath></ServerFilePath>
<Size>43008</Size>
<PartialUpload>false</PartialUpload>
</FTHFileUploadData>
<FTHFileUploadData>
<FileID>0</FileID>
<Name>7.5 Webinar.pptx</Name>
<ServerFilePath></ServerFilePath>
<Size>4508876</Size>
<PartialUpload>false</PartialUpload>
</FTHFileUploadData>
</FileUploadData>
</FTHAppletUploadData>
GetInternalResumableUploadFiles Response
Let’s assume that “7.5 Webinar.pptx” does exist in the target folder and is flagged as “Partial Upload”, while the other two files do not exist.
If the file in the server has a file ID of WebinarFileID_NNN, size of 2 MB and the target folder corresponds to the “/Presentations” server path, this would be the response returned to the client application.
<FTHAppletUploadData>
<SessionID>SessionID_NNN</SessionID>
<ParentFolderID>RootFolderID_NNN</ParentFolderID>
<UserID>0</UserID>
<FileUploadData>
<FTHFileUploadData>
<FileID> WebinarFileID_NNN</FileID>
<Name>7.5 Webinar.pptx</Name>
<ServerFilePath>/Presentations/7.5Webinar.pptx </ServerFilePath>
<Size>2097152</Size>
<PartialUpload>true</PartialUpload>
</FTHFileUploadData>
</FileUploadData>
</FTHAppletUploadData>
With this information, the client application can start (either automatically or by requesting the user to confirm) an upload operation that will resume the previously interrupted upload operation.
Note that there is no explicit “Resume” action in the upload protocol. Instead, the client will use the chunked upload protocol to perform the upload with resume.
Here is the sequence of request to upload the three files.
The first request uploads two files (Test.bmp and “SP Connector.doc”)
Request 1
Form Fields | Example |
---|---|
Upload operation | Internal upload |
Upload action | Upload file |
InternalUpload_AppletUID | SessionID_NNN |
ImmediateParentFolderID | RootFolderID_NNN |
RootFolderID | RootFolderID_NNN |
DeletePartiallyUploadedFile | 0 |
File Fields | Example |
name | File1 |
filename | Test.bmp |
[content] | |
name | File2 |
filename | SP Connector.doc |
[content] |
As a result of a successful request, the server creates a new file system log operation entry (LogOpID_NNN) that will be associated with the upload operation and saves the uploaded files. The ID (FileID_NNN) of the last uploaded file of the set (“SP Connector.doc”) is returned in the headers.
Response 1
X-FileSystemLogOpID | LogOpID_NNN |
X-FileID | FileID_NNN |
X-FolderID | RootFolderID_NNN |
The second request uploads the “7.5 Webinar.pptx” file. Instead of uploading the entire content of the file, the client application will use the information obtained through “GetInternalResumableUploadFiles” message to upload just the part of the file that is missing in the server.
For that, it will use the chunked upload protocol. Because the “first chunk” of the file is “already” in the server, the client app can start with a “upload file middle chunk” action (if more than one file chunk will be uploaded, due to the missing part of the file being very large) or go immediately to the “upload file last chunk” action (if the missing part fits in a single file chunk).
Because the missing part of “7.5 Webinar.pptx” has less than 3 MB, in this scenario the client app will only need one “upload file last chunk” request.
Request 2
Form Fields | Example |
---|---|
Upload operation | Internal upload |
Upload action | Upload file last chunk |
InternalUpload_AppletUID | SessionID_NNN |
FileID | WebinarFileID_NNN |
ImmediateParentFolderID | RootFolderID_NNN |
RootFolderID | RootFolderID_NNN |
FileSystemLogOpID | LogOpID_NNN |
Overwrite | 1 |
DeletePartiallyUploadedFile | 0 |
ExpectedSizeBeforeAppendChunk | 2,097,152 (2 MB) |
File Fields | Example |
name | File1 |
filename | 7.5 Webinar.pptx |
[final chunk – 2.3 MB] |
Response 2
X-FileSystemLogOpID | LogOpID_NNN |
X-FileID | WebinarFileID_NNN |
X-FolderID | FolderID_NNN |
Note that the “Overwrite” field in the request is set to “1.”
As defined by the protocol, in the case of a chunked upload that is being performed in order to resume the upload of a file, the “Overwrite” field should be set to true (“1”).