Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0d8b2bb authored by Guillaume Jacquart's avatar Guillaume Jacquart
Browse files

Merge branch '3293-fix_sync_failed_message' into 'main'

fix:3293: parse last-modified and etag case-insensitive

See merge request !69
parents 1d33b432 7c8ff6ee
Loading
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ import com.nextcloud.android.sso.model.SingleSignOnAccount;

import it.niedermann.owncloud.notes.shared.model.Capabilities;
import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil;
import it.niedermann.owncloud.notes.shared.util.ResponseUtil;
import it.niedermann.owncloud.notes.shared.util.SSOUtil;
import trikita.log.Log;

@@ -18,7 +19,7 @@ public class CapabilitiesClient {

    private static final String TAG = CapabilitiesClient.class.getSimpleName();

    private static final String HEADER_KEY_ETAG = "ETag";
    private static final String HEADER_KEY_ETAG = "etag";

    @WorkerThread
    public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag, @NonNull ApiProvider apiProvider) throws Throwable {
@@ -30,8 +31,8 @@ public class CapabilitiesClient {
        try {
            final var response = ocsAPI.getCapabilities(lastETag).blockingSingle();
            final var capabilities = response.getResponse().ocs.data;
            final var headers = response.getHeaders();
            if (headers != null) {
            final var headers = ResponseUtil.getLowerCaseHeaders(response);
            if (!headers.isEmpty()) {
                capabilities.setETag(headers.get(HEADER_KEY_ETAG));
            } else {
                Log.w(TAG, "Response headers of capabilities are null");
+28 −1
Original line number Diff line number Diff line
package it.niedermann.owncloud.notes.persistence;

import static it.niedermann.owncloud.notes.persistence.NotesServerSyncTask.HEADER_KEY_ETAG;
import static it.niedermann.owncloud.notes.persistence.NotesServerSyncTask.HEADER_KEY_LAST_MODIFIED;

import android.content.Context;

import it.niedermann.owncloud.notes.shared.util.ResponseUtil;
import trikita.log.Log;

import androidx.annotation.NonNull;
@@ -10,6 +15,8 @@ import androidx.lifecycle.MutableLiveData;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -54,7 +61,9 @@ public class NotesImportTask {
            Log.i(TAG, "… Fetching notes IDs");
            final var status = new ImportStatus();
            try {
                final var remoteIds = notesAPI.getNotesIDs().blockingSingle();
                final var response = notesAPI.getNotesIDs().blockingSingle();
                final var cleanedHeaders = ResponseUtil.getLowerCaseHeaders(response.getKey());
                final var remoteIds = response.getValue();
                status.total = remoteIds.size();
                status$.postValue(status);
                Log.i(TAG, "… Total count: " + remoteIds.size());
@@ -74,6 +83,24 @@ public class NotesImportTask {
                }
                try {
                    latch.await();

                    // update ETag and Last-Modified in order to reduce size of next response
                    localAccount.setETag(cleanedHeaders.get(HEADER_KEY_ETAG));

                    final var lastModified = Calendar.getInstance();
                    lastModified.setTimeInMillis(0);
                    final String lastModifiedHeader = cleanedHeaders.get(HEADER_KEY_LAST_MODIFIED);
                    if (lastModifiedHeader != null) {
                        lastModified.setTimeInMillis(Date.parse(lastModifiedHeader));
                    }

                    Log.d(TAG, "ETag: " + cleanedHeaders.get(HEADER_KEY_ETAG) + "; Last-Modified: " + lastModified + " (" + lastModified + ")");

                    localAccount.setModified(lastModified);

                    repo.updateETag(localAccount.getId(), localAccount.getETag());
                    repo.updateModified(localAccount.getId(), localAccount.getModified().getTimeInMillis());

                    Log.i(TAG, "IMPORT FINISHED");
                    callback.onSuccess(null);
                } catch (InterruptedException e) {
+9 −7
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import it.niedermann.owncloud.notes.shared.model.DBStatus;
import it.niedermann.owncloud.notes.shared.model.ISyncCallback;
import it.niedermann.owncloud.notes.shared.model.SyncResultStatus;
import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil;
import it.niedermann.owncloud.notes.shared.util.ResponseUtil;
import trikita.log.Log;


@@ -47,9 +48,9 @@ abstract class NotesServerSyncTask extends Thread {

    private static final String TAG = NotesServerSyncTask.class.getSimpleName();

    private static final String HEADER_KEY_X_NOTES_API_VERSIONS = "X-Notes-API-Versions";
    private static final String HEADER_KEY_ETAG = "ETag";
    private static final String HEADER_KEY_LAST_MODIFIED = "Last-Modified";
    static final String HEADER_KEY_ETAG = "etag";
    static final String HEADER_KEY_LAST_MODIFIED = "last-modified";
    private static final String HEADER_KEY_X_NOTES_API_VERSIONS = "x-notes-api-versions";

    private NotesAPI notesAPI;
    @NonNull
@@ -307,21 +308,22 @@ abstract class NotesServerSyncTask extends Thread {
            }

            // update ETag and Last-Modified in order to reduce size of next response
            localAccount.setETag(fetchResponse.getHeaders().get(HEADER_KEY_ETAG));
            final var cleanedHeaders = ResponseUtil.getLowerCaseHeaders(fetchResponse);
            localAccount.setETag(cleanedHeaders.get(HEADER_KEY_ETAG));

            final var lastModified = Calendar.getInstance();
            lastModified.setTimeInMillis(0);
            final String lastModifiedHeader = fetchResponse.getHeaders().get(HEADER_KEY_LAST_MODIFIED);
            final String lastModifiedHeader = cleanedHeaders.get(HEADER_KEY_LAST_MODIFIED);
            if (lastModifiedHeader != null)
                lastModified.setTimeInMillis(Date.parse(lastModifiedHeader));
            Log.d(TAG, "ETag: " + fetchResponse.getHeaders().get(HEADER_KEY_ETAG) + "; Last-Modified: " + lastModified + " (" + lastModified + ")");
            Log.d(TAG, "ETag: " + cleanedHeaders.get(HEADER_KEY_ETAG) + "; Last-Modified: " + lastModified + " (" + lastModified + ")");

            localAccount.setModified(lastModified);

            repo.updateETag(localAccount.getId(), localAccount.getETag());
            repo.updateModified(localAccount.getId(), localAccount.getModified().getTimeInMillis());

            final String newApiVersion = ApiVersionUtil.sanitize(fetchResponse.getHeaders().get(HEADER_KEY_X_NOTES_API_VERSIONS));
            final String newApiVersion = ApiVersionUtil.sanitize(cleanedHeaders.get(HEADER_KEY_X_NOTES_API_VERSIONS));
            localAccount.setApiVersion(newApiVersion);
            repo.updateApiVersion(localAccount.getId(), newApiVersion);
            Log.d(TAG, "ApiVersion: " + newApiVersion);
+11 −3
Original line number Diff line number Diff line
@@ -10,8 +10,10 @@ import com.google.gson.annotations.Expose;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.api.ParsedResponse;

import java.util.AbstractMap;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import io.reactivex.Observable;
@@ -70,11 +72,17 @@ public class NotesAPI {
        }
    }

    public Observable<List<Long>> getNotesIDs() {
    public Observable<AbstractMap.SimpleEntry<Map<String, String>, List<Long>>> getNotesIDs() {
        if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) {
            return notesAPI_1_0.getNotesIDs().map(response -> response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList()));
            return notesAPI_1_0.getNotesIDs().map(response -> new AbstractMap.SimpleEntry(
                    response.getHeaders(),
                    response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList())
            ));
        } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) {
            return notesAPI_0_2.getNotesIDs().map(response -> response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList()));
            return notesAPI_0_2.getNotesIDs().map(response -> new AbstractMap.SimpleEntry(
                    response.getHeaders(),
                    response.getResponse().stream().map(Note::getRemoteId).collect(Collectors.toList())
            ));
        } else {
            throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support getNotesIDs().");
        }
+31 −0
Original line number Diff line number Diff line
package it.niedermann.owncloud.notes.shared.util;

import androidx.annotation.NonNull;

import com.nextcloud.android.sso.api.ParsedResponse;

import java.util.HashMap;
import java.util.Map;

public class ResponseUtil {
    /*
     * Move headers key to lowercase
     */
    @NonNull
    public static <T> Map<String, String> getLowerCaseHeaders(Map<String, String> headers) {
        final var cleanedHeaders = new HashMap<String, String>();

        if (headers != null) {
            headers.forEach((k, v) -> cleanedHeaders.put(k.toLowerCase(), v));
        }
        return cleanedHeaders;
    }

    /*
     * Get response headers and move headers key to lowercase
     */
    @NonNull
    public static <T> Map<String, String> getLowerCaseHeaders(ParsedResponse<T> fetchResponse) {
        return getLowerCaseHeaders(fetchResponse.getHeaders());
    }
}