Skip to content

Commit a4c0fcf

Browse files
committed
Merge pull request #40 from qiniu/develop
Release 6.0.1
2 parents ad43020 + 17e8299 commit a4c0fcf

File tree

10 files changed

+269
-157
lines changed

10 files changed

+269
-157
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## CHANGE LOG
22

3+
### v6.0.1
4+
2014-04-03 issue [#40](https://github.com/qiniu/android-sdk/pull/40)
5+
6+
- [#35] fix bugs and close idle connection
7+
- [#36] 增加连接超时处理
8+
9+
310
### v6.0.0
411

512
增加 SDK 实现规范

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@ Qiniu Resource Storage SDK for Android
3232

3333
## 许可证
3434

35-
Copyright (c) 2013 qiniu.com
35+
Copyright (c) 2012-2014 qiniu.com
3636

3737
基于 MIT 协议发布:
3838

3939
* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT)
40-
*

docs/README.md

+144-112
Large diffs are not rendered by default.

src/com/qiniu/auth/Client.java

+28-15
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.http.util.EntityUtils;
2323

2424
import java.io.IOException;
25+
import java.util.concurrent.TimeUnit;
2526

2627
public class Client {
2728

@@ -31,6 +32,11 @@ public Client(HttpClient client) {
3132
mClient = client;
3233
}
3334

35+
public void close() {
36+
mClient.getConnectionManager().closeExpiredConnections();
37+
mClient.getConnectionManager().shutdown();
38+
}
39+
3440
public static ClientExecutor get(String url, CallRet ret) {
3541
Client client = Client.defaultClient();
3642
return client.get(client.makeClientExecutor(), url, ret);
@@ -77,6 +83,7 @@ protected HttpResponse roundtrip(HttpRequestBase httpRequest) throws IOException
7783
public class ClientExecutor extends AsyncTask<Object, Object, Object> implements ICancel {
7884
HttpRequestBase mHttpRequest;
7985
CallRet mRet;
86+
boolean failed;
8087
public void setup(HttpRequestBase httpRequest, CallRet ret) {
8188
mHttpRequest = httpRequest;
8289
mRet = ret;
@@ -90,22 +97,16 @@ protected Object doInBackground(Object... objects) {
9097
try {
9198
HttpResponse resp = roundtrip(mHttpRequest);
9299
int statusCode = resp.getStatusLine().getStatusCode();
93-
if (statusCode == 401) { // android 2.3 will not response
94-
return new Exception("unauthorized!");
95-
}
96-
byte[] data = EntityUtils.toByteArray(resp.getEntity());
100+
String xl = resp.getFirstHeader("X-Log").getValue();
97101

98-
if (statusCode / 100 != 2) {
99-
if (data.length == 0) {
100-
String xlog = resp.getFirstHeader("X-Log").getValue();
101-
if (xlog.length() > 0) {
102-
return new Exception(xlog);
103-
}
104-
return new Exception(resp.getStatusLine().getReasonPhrase());
105-
}
106-
return new Exception(new String(data));
107-
}
108-
return data;
102+
if (statusCode == 401) return new Exception("unauthorized!"); // android 2.3 will not response
103+
if (xl.contains("invalid BlockCtx")) return new Exception(xl);
104+
105+
byte[] data = EntityUtils.toByteArray(resp.getEntity());
106+
if (statusCode / 100 == 2) return data;
107+
if (data.length > 0) return new Exception(new String(data));
108+
if (xl.length() > 0) return new Exception(xl);
109+
return new Exception(resp.getStatusLine().getStatusCode() + ":" + resp.getStatusLine().getReasonPhrase());
109110
} catch (IOException e) {
110111
e.printStackTrace();
111112
return e;
@@ -114,17 +115,29 @@ protected Object doInBackground(Object... objects) {
114115

115116
@Override
116117
protected void onProgressUpdate(Object... values) {
118+
if (failed) return;
119+
if (values.length == 1 && values[0] instanceof Exception) {
120+
mRet.onFailure((Exception) values[0]);
121+
failed = true;
122+
return;
123+
}
117124
mRet.onProcess((Long) values[0], (Long) values[1]);
118125
}
119126

120127
@Override
121128
protected void onPostExecute(Object o) {
129+
if (failed) return;
122130
if (o instanceof Exception) {
123131
mRet.onFailure((Exception) o);
124132
return;
125133
}
126134
mRet.onSuccess((byte[]) o);
127135
}
136+
137+
public void onFailure(Exception ex) {
138+
publishProgress(ex);
139+
cancel(true);
140+
}
128141
};
129142

130143
public static Client defaultClient() {

src/com/qiniu/io/IO.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.json.JSONObject;
1313

1414
import java.io.File;
15+
import java.io.IOException;
1516
import java.net.URI;
1617
import java.net.URISyntaxException;
1718
import java.util.Map;
@@ -21,15 +22,21 @@ public class IO {
2122
public static String UNDEFINED_KEY = null;
2223
private static Client mClient;
2324
private static String mUptoken;
25+
private static long mClientUseTime;
2426
public IO(Client client, String uptoken) {
2527
mClient = client;
2628
mUptoken = uptoken;
2729
}
2830

2931
private static Client defaultClient() {
32+
if (mClient != null && System.currentTimeMillis() - mClientUseTime > 3 * 60 * 1000) { // 1 minute
33+
mClient.close();
34+
mClient = null;
35+
}
3036
if (mClient == null) {
3137
mClient = Client.defaultClient();
3238
}
39+
mClientUseTime = System.currentTimeMillis();
3340
return mClient;
3441
}
3542

@@ -44,9 +51,18 @@ private static Client defaultClient() {
4451
public void put(String key, InputStreamAt isa, PutExtra extra, JSONObjectRet ret) {
4552
MultipartEntity m = new MultipartEntity();
4653
if (key != null) m.addField("key", key);
47-
if (extra.checkCrc == PutExtra.AUTO_CRC32) extra.crc32 = isa.crc32();
54+
if (extra.checkCrc == PutExtra.AUTO_CRC32) {
55+
try {
56+
extra.crc32 = isa.crc32();
57+
} catch (IOException e) {
58+
ret.onFailure(e);
59+
return;
60+
}
61+
}
4862
if (extra.checkCrc != PutExtra.UNUSE_CRC32) m.addField("crc32", extra.crc32 + "");
49-
for (Map.Entry<String, String> i: extra.params.entrySet()) m.addField(i.getKey(), i.getValue());
63+
for (Map.Entry<String, String> i: extra.params.entrySet()) {
64+
m.addField(i.getKey(), i.getValue());
65+
}
5066

5167
m.addField("token", mUptoken);
5268
m.addFile("file", extra.mimeType, key == null ? "?" : key, isa);
@@ -58,6 +74,11 @@ public void put(String key, InputStreamAt isa, PutExtra extra, JSONObjectRet ret
5874
public void onProcess(long current, long total) {
5975
executor.upload(current, total);
6076
}
77+
78+
@Override
79+
public void onFailure(Exception ex) {
80+
executor.onFailure(ex);
81+
}
6182
});
6283
client.call(executor, Conf.UP_HOST, m, ret);
6384
}

src/com/qiniu/resumableio/ResumableClient.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,24 @@ public void onInit(int flag) {
4747

4848
public void putInit() {
4949
int chunkSize = Math.min(writeNeed, CHUNK_SIZE);
50-
crc32 = input.getCrc32(offset, chunkSize);
50+
try {
51+
crc32 = input.getCrc32(offset, chunkSize);
52+
} catch (IOException e) {
53+
onFailure(e);
54+
return;
55+
}
5156
canceler[0] = mkblk(input, offset, writeNeed, chunkSize, this);
5257
}
5358

5459
public void putNext() {
5560
wrote = putRet.offset;
5661
int remainLength = Math.min((int) (input.length() - offset - putRet.offset), CHUNK_SIZE);
57-
crc32 = input.getCrc32(offset+putRet.offset, remainLength);
62+
try {
63+
crc32 = input.getCrc32(offset+putRet.offset, remainLength);
64+
} catch (IOException e) {
65+
onFailure(e);
66+
return;
67+
}
5868
canceler[0] = bput(putRet.host, input, putRet.ctx, offset, putRet.offset, remainLength, this);
5969
}
6070

src/com/qiniu/resumableio/ResumableIO.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ private synchronized void removeTask(Integer id) {
3636
idCancels.remove(id);
3737
}
3838

39-
public int putAndClose(final String key, final InputStreamAt input, final PutExtra extra, final JSONObjectRet ret) {
39+
private int putAndClose(final String key, final InputStreamAt input, final PutExtra extra, final JSONObjectRet ret) {
4040
return put(key, input, extra, new JSONObjectRet() {
4141
@Override
4242
public void onSuccess(JSONObject obj) {
@@ -121,6 +121,10 @@ public void onProcess(long current, long total) {
121121

122122
@Override
123123
public void onFailure(Exception ex) {
124+
if (failure[0]) {
125+
ex.printStackTrace();
126+
return;
127+
}
124128
if (--retryTime <= 0 || (ex.getMessage() != null && ex.getMessage().contains("Unauthorized"))) {
125129
removeTask(taskId);
126130
failure[0] = true;

src/com/qiniu/utils/IOnProcess.java

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
public interface IOnProcess {
44
public void onProcess(long current, long total);
5+
public void onFailure(Exception ex);
56
}

src/com/qiniu/utils/InputStreamAt.java

+24-20
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import org.apache.http.entity.AbstractHttpEntity;
88

99
import java.io.*;
10-
import java.util.Arrays;
1110
import java.util.zip.CRC32;
1211

1312
public class InputStreamAt implements Closeable {
@@ -58,14 +57,14 @@ public InputStreamAt(byte[] data) {
5857
mData = data;
5958
}
6059

61-
public long getCrc32(long offset, int length) {
60+
public long getCrc32(long offset, int length) throws IOException {
6261
CRC32 crc32 = new CRC32();
6362
byte[] data = read(offset, length);
6463
crc32.update(data);
6564
return crc32.getValue();
6665
}
6766

68-
public long crc32() {
67+
public long crc32() throws IOException {
6968
if (mCrc32 >= 0) return mCrc32;
7069
CRC32 crc32 = new CRC32();
7170
long index = 0;
@@ -120,45 +119,50 @@ protected static File storeToFile(Context context, InputStream is) {
120119
}
121120
}
122121

123-
public byte[] read(long offset, int length) {
124-
if (mClosed) return null;
125-
try {
126-
if (mFileStream != null) {
127-
return fileStreamRead(offset, length);
128-
}
129-
if (mData != null) {
130-
byte[] ret = new byte[length];
131-
System.arraycopy(mData, (int) offset, ret, 0, length);
132-
return ret;
133-
}
134-
} catch (IOException e) {
135-
e.printStackTrace();
122+
public byte[] read(long offset, int length) throws IOException {
123+
if (mClosed) throw new IOException("inputStreamAt closed");
124+
if (mFileStream != null) {
125+
return fileStreamRead(offset, length);
136126
}
137-
138-
return null;
127+
if (mData != null) {
128+
byte[] ret = new byte[length];
129+
System.arraycopy(mData, (int) offset, ret, 0, length);
130+
return ret;
131+
}
132+
throw new IOException("inputStreamAt not init");
139133
}
140134

141135
protected byte[] fileStreamRead(long offset, int length) throws IOException {
142136
if (mFileStream == null) return null;
137+
long fileLength = mFileStream.length();
138+
if (length + offset > fileLength) length = (int) (fileLength - offset);
143139
byte[] data = new byte[length];
144140

145141
int read;
146142
int totalRead = 0;
147143
synchronized (data) {
148144
mFileStream.seek(offset);
149145
do {
150-
read = mFileStream.read(data, totalRead, length);
146+
read = mFileStream.read(data, totalRead, length - totalRead);
151147
if (read <= 0) break;
152148
totalRead += read;
153149
} while (length > totalRead);
154150
}
155151

156152
if (totalRead != data.length) {
157-
data = Arrays.copyOfRange(data, 0, totalRead);
153+
data = copyOfRange(data, 0, totalRead);
158154
}
159155
return data;
160156
}
161157

158+
public static byte[] copyOfRange(byte[] original, int from, int to) {
159+
int newLength = to - from;
160+
if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
161+
byte[] copy = new byte[newLength];
162+
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
163+
return copy;
164+
}
165+
162166
@Override
163167
public synchronized void close(){
164168
if (mClosed) return;

src/com/qiniu/utils/MultipartEntity.java

+24-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.io.OutputStream;
99
import java.util.ArrayList;
1010
import java.util.Random;
11+
import java.util.concurrent.*;
1112

1213
public class MultipartEntity extends AbstractHttpEntity {
1314
private String mBoundary;
@@ -33,7 +34,7 @@ public void addFile(String field, String contentType, String fileName, InputStre
3334

3435
@Override
3536
public boolean isRepeatable() {
36-
return false;
37+
return true;
3738
}
3839

3940
@Override
@@ -55,6 +56,7 @@ public InputStream getContent() throws IOException, IllegalStateException {
5556

5657
@Override
5758
public void writeTo(OutputStream outputStream) throws IOException {
59+
writed = 0;
5860
outputStream.write(mData.toString().getBytes());
5961
outputStream.flush();
6062
writed += mData.toString().getBytes().length;
@@ -80,6 +82,7 @@ public boolean isStreaming() {
8082
public void setProcessNotify(IOnProcess ret) {
8183
mNotify = ret;
8284
}
85+
ExecutorService executor = Executors.newFixedThreadPool(1);
8386

8487
class FileInfo {
8588

@@ -112,12 +115,18 @@ public void writeTo(OutputStream outputStream) throws IOException {
112115

113116
int blockSize = (int) (getContentLength() / 100);
114117
if (blockSize > 256 * 1024) blockSize = 256 * 1024;
115-
if (blockSize < 16 * 1024) blockSize = 16 * 1024;
118+
if (blockSize < 32 * 1024) blockSize = 32 * 1024;
116119
long index = 0;
117120
long length = mIsa.length();
118121
while (index < length) {
119122
int readLength = (int) StrictMath.min((long) blockSize, mIsa.length() - index);
120-
outputStream.write(mIsa.read(index, readLength));
123+
int timeout = readLength * 2;
124+
try {
125+
write(timeout, outputStream, mIsa.read(index, readLength));
126+
} catch (Exception e) {
127+
mNotify.onFailure(e);
128+
return;
129+
}
121130
index += blockSize;
122131
outputStream.flush();
123132
writed += readLength;
@@ -130,6 +139,18 @@ public void writeTo(OutputStream outputStream) throws IOException {
130139
}
131140
}
132141

142+
private void write(int timeout, final OutputStream outputStream, final byte[] data) throws InterruptedException, ExecutionException, TimeoutException {
143+
Callable<Object> readTask = new Callable<Object>() {
144+
@Override
145+
public Object call() throws Exception {
146+
outputStream.write(data);
147+
return null;
148+
}
149+
};
150+
Future<Object> future = executor.submit(readTask);
151+
future.get(timeout, TimeUnit.MILLISECONDS);
152+
}
153+
133154
private static String getRandomString(int length) {
134155
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
135156
Random random = new Random();

0 commit comments

Comments
 (0)