Skip to content

Commit 94e5da4

Browse files
authored
Ignore corrupted ghosts (#216)
* Ignore corrupted ghosts There are occasions where the stored contents of a ghost may be corrupted outside of the control of this library. One such occasion was discovered when sqlite was improperly converting malformed UTF-16 data into UTF-8. In these cases we risk treating corrupted data as valid and causing more harm to the ghost and bucket value. Additionally we risk corrupting the JSON structure stored in the database which can lead to crashes when reading or using it. In this patch we're performing one simple validation to make sure that we don't attempt to use a ghost which we cannot parse as JSON. Should the occasion arise then the library should attempt to retrieve the latest ghost from the server and start fresh with its processing. Although it looks like this patch may introduce a vector for losing changes it's actually closing a vector for an app crash; the data would have never made it in the first place. * Rearrange some of the existing code - According to what I read, `try/catch` blocks with resources are available to us in the SDK version 19, which I believe we are using. By moving the cursor into the `try/catch` block it will automatically close the cursor regardless of whether we raise an exception or return. - `cursor.moveToFirst()` returns whether or not it was able to find a first result which means that the call to `cursor.getCount()` was redundant and provided no information for our needs beyond what we already had. - since we only return a `Ghost` when all the conditions hold the `ghost` variable wasn't necessary and only introduced opportunities for creating `null` reference errors. I took it out to remove that opportunity.
1 parent 0e35535 commit 94e5da4

File tree

1 file changed

+12
-11
lines changed

1 file changed

+12
-11
lines changed

Simperium/src/main/java/com/simperium/android/GhostStore.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.simperium.client.GhostStorageProvider;
1212
import com.simperium.util.Logger;
1313

14+
import org.json.JSONException;
1415
import org.json.JSONObject;
1516

1617
public class GhostStore implements GhostStorageProvider {
@@ -119,21 +120,21 @@ public void saveGhost(Bucket bucket, Ghost ghost) {
119120

120121
@Override
121122
public Ghost getGhost(Bucket bucket, String key) throws GhostMissingException {
122-
// public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
123123
String[] columns = { BUCKET_NAME_FIELD, OBJECT_KEY_FIELD, VERSION_FIELD, PAYLOAD_FIELD };
124124
String where = "bucketName=? AND simperiumKey=?";
125125
String[] args = { bucket.getName(), key };
126-
Cursor cursor = database.query(GHOSTS_TABLE_NAME, columns, where, args, null, null, null);
127-
Ghost ghost = null;
128-
if (cursor.getCount() > 0) {
129-
cursor.moveToFirst();
130-
ghost = new Ghost(cursor.getString(1), cursor.getInt(2), deserializeGhostData(cursor.getString(3)));
131-
}
132-
cursor.close();
133-
if (ghost == null) {
134-
throw(new GhostMissingException(String.format("Ghost %s does not exist for bucket %s", bucket.getName(), key)));
126+
127+
try (Cursor cursor = database.query(GHOSTS_TABLE_NAME, columns, where, args, null, null, null)) {
128+
if (cursor.moveToFirst()) {
129+
JSONObject ghostData = new JSONObject(cursor.getString(3));
130+
return new Ghost(cursor.getString(1), cursor.getInt(2), ghostData);
131+
}
132+
} catch (org.json.JSONException e){
133+
// a corrupted ghost is effectively equal to a missing ghost
134+
// so pass through here and let the library request a new copy
135135
}
136-
return ghost;
136+
137+
throw(new GhostMissingException(String.format("Ghost %s does not exist for bucket %s", bucket.getName(), key)));
137138
}
138139

139140
@Override

0 commit comments

Comments
 (0)