mirror of
https://github.com/abraunegg/onedrive
synced 2026-03-14 14:35:46 +01:00
This change fixes incorrect error handling when Microsoft Graph returns 204 No Content for successful PATCH operations. Previously, the client always enforced JSON object validation for PATCH responses. When Graph legitimately returned 204 No Content (with an empty response body), the client incorrectly treated the operation as a failure, generated a OneDriveException, and entered a retry loop. This update adjusts the response validation logic to correctly treat 204 No Content and empty response bodies as successful outcomes, while preserving strict JSON validation for responses that are expected to return JSON payloads. This resolves scenarios where the client would continuously retry a successful Graph API call, resulting in repeated log messages such as: Retrying the respective Microsoft Graph API call for Internal Thread ID No behavioural change occurs for genuine error responses. Additional code changes: * Clarify message based on feedback - this ensures the right message is being presented * Ensure message changes when --verbose is used * Update patch() and consumers of patch() to flag if the JSON response needs to be validated or not * Update checking of response when a 204 generated * Only save if the JSON response is a valid JSON object
This commit is contained in:
parent
5f523047e2
commit
87cb0cc98f
2 changed files with 43 additions and 15 deletions
|
|
@ -1018,7 +1018,7 @@ class OneDriveApi {
|
|||
string[string] requestHeaders;
|
||||
const(char)[] url = driveByIdUrl ~ driveId ~ "/items/" ~ id;
|
||||
if (eTag) requestHeaders["If-Match"] = to!string(eTag);
|
||||
return patch(url, data.toString(), requestHeaders);
|
||||
return patch(url, data.toString(), false, requestHeaders);
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_delete
|
||||
|
|
@ -1158,7 +1158,7 @@ class OneDriveApi {
|
|||
const JSONValue request = [
|
||||
"expirationDateTime": expirationDateTime.toISOExtString()
|
||||
];
|
||||
return patch(url, request.toString());
|
||||
return patch(url, request.toString(), true);
|
||||
}
|
||||
|
||||
// Delete Webhook subscription
|
||||
|
|
@ -1761,8 +1761,8 @@ class OneDriveApi {
|
|||
}, validateJSONResponse, callingFunction, lineno);
|
||||
}
|
||||
|
||||
private JSONValue patch(const(char)[] url, const(char)[] patchData, string[string] requestHeaders=null, const(char)[] contentType = "application/json", string callingFunction=__FUNCTION__, int lineno=__LINE__) {
|
||||
bool validateJSONResponse = true;
|
||||
private JSONValue patch(const(char)[] url, const(char)[] patchData, bool validateJSONResponseInput, string[string] requestHeaders=null, const(char)[] contentType = "application/json", string callingFunction=__FUNCTION__, int lineno=__LINE__) {
|
||||
bool validateJSONResponse = validateJSONResponseInput;
|
||||
return oneDriveErrorHandlerWrapper((CurlResponse response) {
|
||||
connect(HTTP.Method.patch, url, false, response, requestHeaders);
|
||||
curlEngine.setContent(contentType, patchData);
|
||||
|
|
@ -1857,8 +1857,20 @@ class OneDriveApi {
|
|||
|
||||
// Do we need to validate the JSON response?
|
||||
if (validateJSONResponse) {
|
||||
if (result.type() != JSONType.object) {
|
||||
throw new OneDriveException(0, "Caller request a non null JSON response, get null instead", response);
|
||||
const code = response.statusLine.code;
|
||||
|
||||
// 204 = No Content is a valid success response for some Graph operations (e.g. PATCH/DELETE).
|
||||
// In that case, there is no JSON payload to validate.
|
||||
if (code != 204) {
|
||||
// If caller expects JSON, an empty body is not acceptable
|
||||
if (response.content.length == 0) {
|
||||
throw new OneDriveException( 0, "Caller requested a JSON object response, but the response body was empty", response);
|
||||
}
|
||||
|
||||
// Body is present: it must be a JSON object
|
||||
if (result.type() != JSONType.object) {
|
||||
throw new OneDriveException(0, "Caller requested a JSON object response, but the response was not a JSON object", response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
34
src/sync.d
34
src/sync.d
|
|
@ -4950,9 +4950,13 @@ class SyncEngine {
|
|||
// Everything else should remain the same .. and then save this DB record to the DB ..
|
||||
// However, we did this, for the local modified file right before calling this function to update the online timestamp ... so .. do we need to do this again, effectively performing a double DB write for the same data?
|
||||
if ((originItem.type != ItemType.remote) && (originItem.remoteType != ItemType.file)) {
|
||||
// Save the response JSON
|
||||
// Is the response a valid JSON object - validation checking done in saveItem
|
||||
saveItem(response);
|
||||
if (response.type() == JSONType.object) {
|
||||
// Save the response JSON
|
||||
saveItem(response);
|
||||
} else {
|
||||
// Log why we are not saving
|
||||
if (debugLogging) {addLogEntry("uploadLastModifiedTime: updateById returned no JSON payload (likely HTTP 204); skipping saveItem()", ["debug"]);}
|
||||
}
|
||||
}
|
||||
} catch (OneDriveException exception) {
|
||||
// Handle a 409 - ETag does not match current item's value
|
||||
|
|
@ -10539,9 +10543,17 @@ class SyncEngine {
|
|||
addLogEntry("ERROR: " ~ sanitiseJSONItem(jsonItem));
|
||||
}
|
||||
} else {
|
||||
// log error
|
||||
addLogEntry("ERROR: An error was returned from OneDrive and the resulting response is not a valid JSON object that can be processed.");
|
||||
addLogEntry("ERROR: Increase logging verbosity to assist determining why.");
|
||||
// Log that the provided JSON could not be processed
|
||||
addLogEntry("ERROR: Invalid JSON object - the provided data cannot be processed or stored in the database.");
|
||||
|
||||
// What level of next message is provided?
|
||||
if (appConfig.verbosityCount == 0) {
|
||||
// Standard error message
|
||||
addLogEntry("ERROR: Please rerun the application with --verbose enabled to obtain additional diagnostic information.");
|
||||
} else {
|
||||
// verbose or debug
|
||||
addLogEntry("ERROR: The following JSON data failed validation and could not be saved: " ~ to!string(jsonItem));
|
||||
}
|
||||
}
|
||||
|
||||
// Display function processing time if configured to do so
|
||||
|
|
@ -11976,9 +11988,13 @@ class SyncEngine {
|
|||
// Perform Garbage Collection
|
||||
GC.collect();
|
||||
|
||||
// save the move response from OneDrive in the database
|
||||
// Is the response a valid JSON object - validation checking done in saveItem
|
||||
saveItem(response);
|
||||
// Save the move response from OneDrive in the database
|
||||
if (isMoveSuccess && response.type() == JSONType.object) {
|
||||
saveItem(response);
|
||||
} else {
|
||||
// Log why we are not saving
|
||||
if (debugLogging) {addLogEntry("uploadMoveItem: skipping saveItem() (no JSON payload returned or move not successful)", ["debug"]);}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Moved item is unwanted
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue