Skip to content

Commit a1b06b4

Browse files
authored
Merge pull request #1351 from couchbase/feature/issue_and_884
Fixed https://github.com/couchbase/couchbase-lite-android/issues/884
2 parents 21f064e + c333472 commit a1b06b4

5 files changed

Lines changed: 75 additions & 56 deletions

File tree

src/main/java/com/couchbase/lite/BlobStore.java

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -480,43 +480,6 @@ public InputStream blobStreamForKey(BlobKey key) {
480480
return null;
481481
}
482482

483-
/*
484-
NO Usages: Should be removed:
485-
public boolean storeBlobStream(InputStream inputStream, BlobKey outKey) {
486-
File tmp = null;
487-
try {
488-
tmp = File.createTempFile(TMP_FILE_PREFIX, TMP_FILE_EXTENSION, new File(path));
489-
FileOutputStream fos = new FileOutputStream(tmp);
490-
byte[] buffer = new byte[65536];
491-
int lenRead = inputStream.read(buffer);
492-
while (lenRead > 0) {
493-
fos.write(buffer, 0, lenRead);
494-
lenRead = inputStream.read(buffer);
495-
}
496-
inputStream.close();
497-
fos.close();
498-
} catch (IOException e) {
499-
Log.e(Log.TAG_DATABASE, "BlobStore: Error writing blob to tmp file", e);
500-
return false;
501-
}
502-
503-
BlobKey newKey = keyForBlobFromFile(tmp);
504-
outKey.setBytes(newKey.getBytes());
505-
String path = getRawPathForKey(outKey);
506-
File file = new File(path);
507-
508-
if (file.canRead()) {
509-
// object with this hash already exists, we should delete tmp file and return true
510-
tmp.delete();
511-
return true;
512-
} else {
513-
// does not exist, we should rename tmp file to this name
514-
tmp.renameTo(file);
515-
}
516-
return true;
517-
}
518-
*/
519-
520483
public boolean storeBlob(byte[] data, BlobKey outKey) {
521484
BlobKey newKey = keyForBlob(data);
522485
outKey.setBytes(newKey.getBytes());
@@ -682,4 +645,8 @@ public String getPath() {
682645
public SymmetricKey getEncryptionKey() {
683646
return encryptionKey;
684647
}
648+
649+
public boolean isEncrypted() {
650+
return encryptionKey != null;
651+
}
685652
}

src/main/java/com/couchbase/lite/replicator/BlobRequestBody.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
/**
2-
* Copyright (c) 2016 Couchbase, Inc. All rights reserved.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5-
* except in compliance with the License. You may obtain a copy of the License at
6-
*
7-
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
9-
* Unless required by applicable law or agreed to in writing, software distributed under the
10-
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11-
* either express or implied. See the License for the specific language governing permissions
12-
* and limitations under the License.
13-
*/
1+
//
2+
// Copyright (c) 2016 Couchbase, Inc. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
// except in compliance with the License. You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software distributed under the
10+
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
// either express or implied. See the License for the specific language governing permissions
12+
// and limitations under the License.
13+
//
1414
package com.couchbase.lite.replicator;
1515

1616
import com.couchbase.lite.BlobKey;
@@ -32,7 +32,9 @@
3232
public class BlobRequestBody {
3333
public static RequestBody create(final MediaType contentType,
3434
final BlobStore blobStore,
35-
final BlobKey blobKey) {
35+
final BlobKey blobKey,
36+
final long declaredLength,
37+
final boolean syncGateway) {
3638
if (blobStore == null) throw new NullPointerException("blobStore == null");
3739
if (blobKey == null) throw new NullPointerException("blobKey == null");
3840

@@ -42,6 +44,36 @@ public MediaType contentType() {
4244
return contentType;
4345
}
4446

47+
48+
/**
49+
* OkHttp use chunked transfer if content-length is unknown. And CouchDB 1.6.1 can not
50+
* handle chunked transer with multipart doc, then CouchDB disconnect .
51+
* To send non-chunked transfer with multipart document by OkHttp, the client needs
52+
* to specify content-length.
53+
* Sync Gateway can accept chunked transfer
54+
*/
55+
@Override
56+
public long contentLength() throws IOException {
57+
// Sync Gateway
58+
if (syncGateway) {
59+
return super.contentLength();
60+
}
61+
// CouchDB or Couchbase Lite
62+
else {
63+
// encrypted
64+
if (blobStore.isEncrypted()) {
65+
if (declaredLength > 0)
66+
return declaredLength;
67+
else
68+
return super.contentLength();
69+
} else {
70+
// gzipped or non-encrypted content
71+
// NOTE: gzipped: CBL Java sends gzipped contents without decode.
72+
return blobStore.getSizeOfBlob(blobKey);
73+
}
74+
}
75+
}
76+
4577
@Override
4678
public void writeTo(BufferedSink sink) throws IOException {
4779
InputStream in = blobStore.blobStreamForKey(blobKey);

src/main/java/com/couchbase/lite/replicator/RemoteMultipartRequest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class RemoteMultipartRequest extends RemoteRequest {
3636
////////////////////////////////////////////////////////////
3737
private Map<String, Object> attachments;
3838
private Database db;
39+
private boolean syncGateway;
3940

4041
////////////////////////////////////////////////////////////
4142
// Constructors
@@ -45,6 +46,7 @@ public RemoteMultipartRequest(
4546
HttpClientFactory clientFactory,
4647
String method,
4748
URL url,
49+
boolean syncGateway,
4850
boolean cancelable,
4951
Map<String, ?> body,
5052
Map<String, Object> attachments,
@@ -54,6 +56,7 @@ public RemoteMultipartRequest(
5456
super(clientFactory, method, url, cancelable, body, requestHeaders, onCompletion);
5557
this.attachments = attachments;
5658
this.db = db;
59+
this.syncGateway = syncGateway;
5760
}
5861

5962
////////////////////////////////////////////////////////////
@@ -148,8 +151,13 @@ private MultipartBody.Builder createMultipartBody() {
148151
if (contentEncoding != null)
149152
builder.add("Content-Encoding", contentEncoding);
150153

154+
// check content-length which is stored in attachments table.
155+
long declaredLength = 0;
156+
if(attachment.containsKey("length"))
157+
declaredLength = ((Integer)attachment.get("length")).longValue();
158+
151159
MediaType type = MediaType.parse(contentType);
152-
RequestBody body = BlobRequestBody.create(type, blobStore, blobKey);
160+
RequestBody body = BlobRequestBody.create(type, blobStore, blobKey, declaredLength, syncGateway);
153161
multipartBodyBuilder.addPart(builder.build(), body);
154162
}
155163
}

src/main/java/com/couchbase/lite/replicator/RemoteRequestRetry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public enum RemoteRequestType {
8484
private Throwable requestThrowable;
8585
private BlockingQueue<Future> pendingRequests;
8686
Map<Future, CancellableRunnable> runnables = new HashMap<Future, CancellableRunnable>();
87+
private boolean syncGateway = true;
8788
private boolean cancelable = true;
8889
// if true, we wont log any 404 errors (useful when getting remote checkpoint doc)
8990
private boolean dontLog404;
@@ -103,6 +104,7 @@ public RemoteRequestRetry(RemoteRequestType requestType,
103104
HttpClientFactory clientFactory,
104105
String method,
105106
URL url,
107+
boolean syncGateway,
106108
boolean cancelable,
107109
Map<String, Object> body,
108110
Map<String, Object> attachments,
@@ -114,6 +116,7 @@ public RemoteRequestRetry(RemoteRequestType requestType,
114116
this.clientFactory = clientFactory;
115117
this.method = method;
116118
this.url = url;
119+
this.syncGateway = syncGateway;
117120
this.cancelable = cancelable;
118121
this.body = body;
119122
this.attachments = attachments;
@@ -247,6 +250,7 @@ private RemoteRequest generateRemoteRequest() {
247250
clientFactory,
248251
method,
249252
url,
253+
syncGateway,
250254
cancelable,
251255
body,
252256
attachments,

src/main/java/com/couchbase/lite/replicator/ReplicationInternal.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ abstract class ReplicationInternal implements BlockingQueueListener {
8282
public static final String CHANNELS_QUERY_PARAM = "channels";
8383
public static final int EXECUTOR_THREAD_POOL_SIZE = 5;
8484
public static final int MIN_EXECUTOR_THREAD_POOL_SIZE = 2;
85+
public static final String SYNC_GATEWAY_PREFIX = "Couchbase Sync Gateway/";
8586

8687
private static int lastSessionID = 0;
8788
public static int RETRY_DELAY_SECONDS = 60; // #define kRetryDelay 60.0 in CBL_Replicator.m
@@ -677,6 +678,7 @@ public CustomFuture sendAsyncRequest(String method,
677678
clientFactory,
678679
method,
679680
url,
681+
serverIsSyncGateway(),
680682
cancelable,
681683
body,
682684
null,
@@ -723,6 +725,7 @@ public CustomFuture sendAsyncMultipartRequest(String method,
723725
clientFactory,
724726
method,
725727
url,
728+
serverIsSyncGateway(),
726729
true,
727730
body,
728731
attachments,
@@ -753,6 +756,7 @@ public CustomFuture sendAsyncMultipartRequest(String method,
753756
clientFactory,
754757
method,
755758
url,
759+
serverIsSyncGateway(),
756760
true,
757761
body,
758762
null,
@@ -1520,15 +1524,19 @@ protected boolean serverIsSyncGatewayVersion(String minVersion) {
15201524
return serverIsSyncGatewayVersion(serverType, minVersion);
15211525
}
15221526

1527+
@InterfaceAudience.Private
1528+
protected boolean serverIsSyncGateway() {
1529+
return serverType == null || !serverType.startsWith(SYNC_GATEWAY_PREFIX) ? false : true;
1530+
}
1531+
15231532
@InterfaceAudience.Private
15241533
protected static boolean serverIsSyncGatewayVersion(String serverName, String minVersion) {
1525-
String prefix = "Couchbase Sync Gateway/";
15261534
if (serverName == null) {
15271535
return false;
15281536
} else {
1529-
if (serverName.startsWith(prefix)) {
1530-
String versionString = serverName.substring(prefix.length());
1531-
// NOTE: If version number is higher than 10.xx, this comprison does not work eg. "10.0" < "2.0"
1537+
if (serverName.startsWith(SYNC_GATEWAY_PREFIX)) {
1538+
String versionString = serverName.substring(SYNC_GATEWAY_PREFIX.length());
1539+
// NOTE: If version number is higher than 10.xx, this comparison does not work eg. "10.0" < "2.0"
15321540
return versionString.compareTo(minVersion) >= 0;
15331541
}
15341542
}

0 commit comments

Comments
 (0)