Bug 1253111 - Part 1: Introduce new sync stage to handle info/configuration r=rnewman

MozReview-Commit-ID: 7MOgR7A5SOF

--HG--
extra : rebase_source : e029d60a063b2e1dd9061362c4d4a647263dd3ec
This commit is contained in:
Grigory Kruglov 2016-08-15 18:35:17 -07:00
Родитель 141464cd20
Коммит 29e4dd5c85
7 изменённых файлов: 166 добавлений и 1 удалений

Просмотреть файл

@ -893,6 +893,7 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/GlobalSession.java',
'sync/HTTPFailureException.java',
'sync/InfoCollections.java',
'sync/InfoConfiguration.java',
'sync/InfoCounts.java',
'sync/JSONRecordFetcher.java',
'sync/KeyBundleProvider.java',
@ -1030,6 +1031,7 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'sync/stage/EnsureCrypto5KeysStage.java',
'sync/stage/FennecTabsServerSyncStage.java',
'sync/stage/FetchInfoCollectionsStage.java',
'sync/stage/FetchInfoConfigurationStage.java',
'sync/stage/FetchMetaGlobalStage.java',
'sync/stage/FormHistoryServerSyncStage.java',
'sync/stage/GlobalSyncStage.java',

Просмотреть файл

@ -32,6 +32,7 @@ import org.mozilla.gecko.sync.stage.CompletedStage;
import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
import org.mozilla.gecko.sync.stage.FennecTabsServerSyncStage;
import org.mozilla.gecko.sync.stage.FetchInfoCollectionsStage;
import org.mozilla.gecko.sync.stage.FetchInfoConfigurationStage;
import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
import org.mozilla.gecko.sync.stage.FormHistoryServerSyncStage;
import org.mozilla.gecko.sync.stage.GlobalSyncStage;
@ -177,6 +178,8 @@ public class GlobalSession implements HttpResponseObserver {
stages.put(Stage.checkPreconditions, new CheckPreconditionsStage());
stages.put(Stage.fetchInfoCollections, new FetchInfoCollectionsStage());
stages.put(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
stages.put(Stage.fetchInfoConfiguration, new FetchInfoConfigurationStage(
config.infoConfigurationURL(), getAuthHeaderProvider()));
stages.put(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());
stages.put(Stage.syncClientsEngine, new SyncClientsEngineStage());

Просмотреть файл

@ -0,0 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync;
import android.util.Log;
import org.mozilla.gecko.background.common.log.Logger;
/**
* Wraps and provides access to configuration data returned from info/configuration.
* Docs: https://docs.services.mozilla.com/storage/apis-1.5.html#general-info
*
* - <bold>max_request_bytes</bold>: the maximum size in bytes of the overall
* HTTP request body that will be accepted by the server.
*
* - <bold>max_post_records</bold>: the maximum number of records that can be
* uploaded to a collection in a single POST request.
*
* - <bold>max_post_bytes</bold>: the maximum combined size in bytes of the
* record payloads that can be uploaded to a collection in a single
* POST request.
*
* - <bold>max_total_records</bold>: the maximum number of records that can be
* uploaded to a collection as part of a batched upload.
*
* - <bold>max_total_bytes</bold>: the maximum combined size in bytes of the
* record payloads that can be uploaded to a collection as part of
* a batched upload.
*/
public class InfoConfiguration {
private static final String LOG_TAG = "InfoConfiguration";
public static final String MAX_REQUEST_BYTES = "max_request_bytes";
public static final String MAX_POST_RECORDS = "max_post_records";
public static final String MAX_POST_BYTES = "max_post_bytes";
public static final String MAX_TOTAL_RECORDS = "max_total_records";
public static final String MAX_TOTAL_BYTES = "max_total_bytes";
private static final long DEFAULT_MAX_REQUEST_BYTES = 1048576;
private static final long DEFAULT_MAX_POST_RECORDS = 100;
private static final long DEFAULT_MAX_POST_BYTES = 1048576;
private static final long DEFAULT_MAX_TOTAL_RECORDS = 10000;
private static final long DEFAULT_MAX_TOTAL_BYTES = 104857600;
// While int's upper range is (2^31-1), which in bytes is equivalent to 2.147 GB, let's be optimistic
// about the future and use long here, so that this code works if the server decides its clients are
// all on fiber and have congress-library sized bookmark collections.
// Record counts are long for the sake of simplicity.
public final long maxRequestBytes;
public final long maxPostRecords;
public final long maxPostBytes;
public final long maxTotalRecords;
public final long maxTotalBytes;
public InfoConfiguration() {
Logger.debug(LOG_TAG, "info/configuration is unavailable, using defaults");
maxRequestBytes = DEFAULT_MAX_REQUEST_BYTES;
maxPostRecords = DEFAULT_MAX_POST_RECORDS;
maxPostBytes = DEFAULT_MAX_POST_BYTES;
maxTotalRecords = DEFAULT_MAX_TOTAL_RECORDS;
maxTotalBytes = DEFAULT_MAX_TOTAL_BYTES;
}
public InfoConfiguration(final ExtendedJSONObject record) {
Logger.debug(LOG_TAG, "info/configuration is " + record.toJSONString());
maxRequestBytes = getValueFromRecord(record, MAX_REQUEST_BYTES, DEFAULT_MAX_REQUEST_BYTES);
maxPostRecords = getValueFromRecord(record, MAX_POST_RECORDS, DEFAULT_MAX_POST_RECORDS);
maxPostBytes = getValueFromRecord(record, MAX_POST_BYTES, DEFAULT_MAX_POST_BYTES);
maxTotalRecords = getValueFromRecord(record, MAX_TOTAL_RECORDS, DEFAULT_MAX_TOTAL_RECORDS);
maxTotalBytes = getValueFromRecord(record, MAX_TOTAL_BYTES, DEFAULT_MAX_TOTAL_BYTES);
}
private static Long getValueFromRecord(ExtendedJSONObject record, String key, long defaultValue) {
if (!record.containsKey(key)) {
return defaultValue;
}
try {
Long val = record.getLong(key);
if (val == null) {
return defaultValue;
}
return val;
} catch (NumberFormatException e) {
Log.w(LOG_TAG, "Could not parse key " + key + " from record: " + record, e);
return defaultValue;
}
}
}

Просмотреть файл

@ -30,6 +30,8 @@ public class SyncConfiguration {
public URI clusterURL;
public KeyBundle syncKeyBundle;
public InfoConfiguration infoConfiguration;
public CollectionKeys collectionKeys;
public InfoCollections infoCollections;
public MetaGlobal metaGlobal;
@ -366,6 +368,10 @@ public class SyncConfiguration {
return infoBaseURL() + "collections";
}
public String infoConfigurationURL() {
return infoBaseURL() + "configuration";
}
public String infoCollectionCountsURL() {
return infoBaseURL() + "collection_counts";
}

Просмотреть файл

@ -9,7 +9,8 @@ import org.mozilla.gecko.sync.net.SyncStorageResponse;
/**
* A fairly generic delegate to handle fetches of single JSON object blobs, as
* provided by <code>info/collections</code> and <code>info/collection_counts</code>.
* provided by <code>info/configuration</code>, <code>info/collections</code>
* and <code>info/collection_counts</code>.
*/
public interface JSONRecordFetchDelegate {
public void handleSuccess(ExtendedJSONObject body);

Просмотреть файл

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.stage;
import org.mozilla.gecko.sync.ExtendedJSONObject;
import org.mozilla.gecko.sync.InfoConfiguration;
import org.mozilla.gecko.sync.JSONRecordFetcher;
import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
import org.mozilla.gecko.sync.net.SyncStorageResponse;
/**
* Fetches configuration data from info/configurations endpoint.
*/
public class FetchInfoConfigurationStage extends AbstractNonRepositorySyncStage {
private final String configurationURL;
private final AuthHeaderProvider authHeaderProvider;
public FetchInfoConfigurationStage(final String configurationURL, final AuthHeaderProvider authHeaderProvider) {
super();
this.configurationURL = configurationURL;
this.authHeaderProvider = authHeaderProvider;
}
public class StageInfoConfigurationDelegate implements JSONRecordFetchDelegate {
@Override
public void handleSuccess(final ExtendedJSONObject result) {
session.config.infoConfiguration = new InfoConfiguration(result);
session.advance();
}
@Override
public void handleFailure(final SyncStorageResponse response) {
// Handle all non-404 failures upstream.
if (response.getStatusCode() != 404) {
session.handleHTTPError(response, "Failure fetching info/configuration");
return;
}
// End-point might not be available (404) if server is running an older version.
// We will use default config values in this case.
session.config.infoConfiguration = new InfoConfiguration();
session.advance();
}
@Override
public void handleError(final Exception e) {
session.abort(e, "Failure fetching info/configuration");
}
}
@Override
public void execute() {
final StageInfoConfigurationDelegate delegate = new StageInfoConfigurationDelegate();
final JSONRecordFetcher fetcher = new JSONRecordFetcher(configurationURL, authHeaderProvider);
fetcher.fetch(delegate);
}
}

Просмотреть файл

@ -18,6 +18,7 @@ public interface GlobalSyncStage {
idle, // Start state.
checkPreconditions, // Preparation of the basics. TODO: clear status
fetchInfoCollections, // Take a look at timestamps.
fetchInfoConfiguration, // Fetch server upload limits
fetchMetaGlobal,
ensureKeysStage,
/*