Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7df84b1
fix ResumableIO: ignore other exception when upload failure
chzyer Nov 12, 2013
9e49982
close idle connection after finish a request;
chzyer Nov 20, 2013
90ace81
fix inputstreamat bug
chzyer Nov 21, 2013
691d6e3
fix client output info
chzyer Dec 2, 2013
e500fe1
change format
chzyer Dec 4, 2013
2b31fc3
Merge pull request #35 from chzyer/feature/v6
longbai Dec 4, 2013
f671b8b
fix MultipartEntity isRepeatable to true
chzyer Dec 4, 2013
7e18951
add timeout for multipartEntity
chzyer Dec 4, 2013
132f663
fix
chzyer Dec 4, 2013
a7d33a8
fix
chzyer Dec 4, 2013
dfe0583
fix
chzyer Dec 4, 2013
5988b4e
fix
chzyer Dec 4, 2013
894c8f0
fix
chzyer Dec 4, 2013
d1659f8
add close for client
chzyer Dec 4, 2013
fdcbd59
fix close Idle connection
chzyer Dec 4, 2013
2c9d466
add timeout
chzyer Dec 4, 2013
efc080b
add timeout
chzyer Dec 4, 2013
95703fc
use copyOfRange
chzyer Dec 4, 2013
66bd46e
use copyOfRange
chzyer Dec 4, 2013
84be071
fix arrays import
chzyer Dec 4, 2013
72c55cf
add httpclient pool expired to 3 minutes
chzyer Dec 4, 2013
46c5633
Add Title for docs/README.md.
BluntBlade Dec 10, 2013
931f7a3
Merge pull request #37 from BluntBlade/develop
xushiwei Dec 13, 2013
698cd85
Merge pull request #36 from chzyer/feature/v6
xushiwei Dec 24, 2013
815fad9
Refactoring developer guide.
hughlv Jan 9, 2014
dfd2614
Update README.md
chzyer Jan 9, 2014
dbc9726
Merge pull request #1 from chzyer/patch-2
hughlv Jan 10, 2014
83d63e8
Refined doc.
hughlv Jan 10, 2014
b395331
Refined doc.
hughlv Jan 10, 2014
df4c795
Refined doc.
hughlv Jan 10, 2014
33db1b9
Refined doc.
hughlv Jan 10, 2014
69dd162
Update README.md
chzyer Jan 13, 2014
30d36c2
Update README.md
chzyer Jan 13, 2014
0522489
Update README.md
chzyer Jan 14, 2014
f8df993
Update README.md
chzyer Jan 14, 2014
5362045
Merge pull request #2 from chzyer/patch-3
hughlv Jan 14, 2014
1da2e19
Refined doc.
hughlv Jan 14, 2014
e038677
Merge pull request #38 from hughlv/develop
xushiwei Jan 14, 2014
2431dd6
Update README.md
longbai Apr 3, 2014
17e8299
changelog update
longbai Apr 3, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## CHANGE LOG

### v6.0.1
2014-04-03 issue [#40](https://github.com/qiniu/android-sdk/pull/40)

- [#35] fix bugs and close idle connection
- [#36] 增加连接超时处理


### v6.0.0

增加 SDK 实现规范
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ Qiniu Resource Storage SDK for Android

## 许可证

Copyright (c) 2013 qiniu.com
Copyright (c) 2012-2014 qiniu.com

基于 MIT 协议发布:

* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT)
*
256 changes: 144 additions & 112 deletions docs/README.md

Large diffs are not rendered by default.

43 changes: 28 additions & 15 deletions src/com/qiniu/auth/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class Client {

Expand All @@ -31,6 +32,11 @@ public Client(HttpClient client) {
mClient = client;
}

public void close() {
mClient.getConnectionManager().closeExpiredConnections();
mClient.getConnectionManager().shutdown();
}

public static ClientExecutor get(String url, CallRet ret) {
Client client = Client.defaultClient();
return client.get(client.makeClientExecutor(), url, ret);
Expand Down Expand Up @@ -77,6 +83,7 @@ protected HttpResponse roundtrip(HttpRequestBase httpRequest) throws IOException
public class ClientExecutor extends AsyncTask<Object, Object, Object> implements ICancel {
HttpRequestBase mHttpRequest;
CallRet mRet;
boolean failed;
public void setup(HttpRequestBase httpRequest, CallRet ret) {
mHttpRequest = httpRequest;
mRet = ret;
Expand All @@ -90,22 +97,16 @@ protected Object doInBackground(Object... objects) {
try {
HttpResponse resp = roundtrip(mHttpRequest);
int statusCode = resp.getStatusLine().getStatusCode();
if (statusCode == 401) { // android 2.3 will not response
return new Exception("unauthorized!");
}
byte[] data = EntityUtils.toByteArray(resp.getEntity());
String xl = resp.getFirstHeader("X-Log").getValue();

if (statusCode / 100 != 2) {
if (data.length == 0) {
String xlog = resp.getFirstHeader("X-Log").getValue();
if (xlog.length() > 0) {
return new Exception(xlog);
}
return new Exception(resp.getStatusLine().getReasonPhrase());
}
return new Exception(new String(data));
}
return data;
if (statusCode == 401) return new Exception("unauthorized!"); // android 2.3 will not response
if (xl.contains("invalid BlockCtx")) return new Exception(xl);

byte[] data = EntityUtils.toByteArray(resp.getEntity());
if (statusCode / 100 == 2) return data;
if (data.length > 0) return new Exception(new String(data));
if (xl.length() > 0) return new Exception(xl);
return new Exception(resp.getStatusLine().getStatusCode() + ":" + resp.getStatusLine().getReasonPhrase());
} catch (IOException e) {
e.printStackTrace();
return e;
Expand All @@ -114,17 +115,29 @@ protected Object doInBackground(Object... objects) {

@Override
protected void onProgressUpdate(Object... values) {
if (failed) return;
if (values.length == 1 && values[0] instanceof Exception) {
mRet.onFailure((Exception) values[0]);
failed = true;
return;
}
mRet.onProcess((Long) values[0], (Long) values[1]);
}

@Override
protected void onPostExecute(Object o) {
if (failed) return;
if (o instanceof Exception) {
mRet.onFailure((Exception) o);
return;
}
mRet.onSuccess((byte[]) o);
}

public void onFailure(Exception ex) {
publishProgress(ex);
cancel(true);
}
};

public static Client defaultClient() {
Expand Down
25 changes: 23 additions & 2 deletions src/com/qiniu/io/IO.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
Expand All @@ -21,15 +22,21 @@ public class IO {
public static String UNDEFINED_KEY = null;
private static Client mClient;
private static String mUptoken;
private static long mClientUseTime;
public IO(Client client, String uptoken) {
mClient = client;
mUptoken = uptoken;
}

private static Client defaultClient() {
if (mClient != null && System.currentTimeMillis() - mClientUseTime > 3 * 60 * 1000) { // 1 minute
mClient.close();
mClient = null;
}
if (mClient == null) {
mClient = Client.defaultClient();
}
mClientUseTime = System.currentTimeMillis();
return mClient;
}

Expand All @@ -44,9 +51,18 @@ private static Client defaultClient() {
public void put(String key, InputStreamAt isa, PutExtra extra, JSONObjectRet ret) {
MultipartEntity m = new MultipartEntity();
if (key != null) m.addField("key", key);
if (extra.checkCrc == PutExtra.AUTO_CRC32) extra.crc32 = isa.crc32();
if (extra.checkCrc == PutExtra.AUTO_CRC32) {
try {
extra.crc32 = isa.crc32();
} catch (IOException e) {
ret.onFailure(e);
return;
}
}
if (extra.checkCrc != PutExtra.UNUSE_CRC32) m.addField("crc32", extra.crc32 + "");
for (Map.Entry<String, String> i: extra.params.entrySet()) m.addField(i.getKey(), i.getValue());
for (Map.Entry<String, String> i: extra.params.entrySet()) {
m.addField(i.getKey(), i.getValue());
}

m.addField("token", mUptoken);
m.addFile("file", extra.mimeType, key == null ? "?" : key, isa);
Expand All @@ -58,6 +74,11 @@ public void put(String key, InputStreamAt isa, PutExtra extra, JSONObjectRet ret
public void onProcess(long current, long total) {
executor.upload(current, total);
}

@Override
public void onFailure(Exception ex) {
executor.onFailure(ex);
}
});
client.call(executor, Conf.UP_HOST, m, ret);
}
Expand Down
14 changes: 12 additions & 2 deletions src/com/qiniu/resumableio/ResumableClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,24 @@ public void onInit(int flag) {

public void putInit() {
int chunkSize = Math.min(writeNeed, CHUNK_SIZE);
crc32 = input.getCrc32(offset, chunkSize);
try {
crc32 = input.getCrc32(offset, chunkSize);
} catch (IOException e) {
onFailure(e);
return;
}
canceler[0] = mkblk(input, offset, writeNeed, chunkSize, this);
}

public void putNext() {
wrote = putRet.offset;
int remainLength = Math.min((int) (input.length() - offset - putRet.offset), CHUNK_SIZE);
crc32 = input.getCrc32(offset+putRet.offset, remainLength);
try {
crc32 = input.getCrc32(offset+putRet.offset, remainLength);
} catch (IOException e) {
onFailure(e);
return;
}
canceler[0] = bput(putRet.host, input, putRet.ctx, offset, putRet.offset, remainLength, this);
}

Expand Down
6 changes: 5 additions & 1 deletion src/com/qiniu/resumableio/ResumableIO.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private synchronized void removeTask(Integer id) {
idCancels.remove(id);
}

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

@Override
public void onFailure(Exception ex) {
if (failure[0]) {
ex.printStackTrace();
return;
}
if (--retryTime <= 0 || (ex.getMessage() != null && ex.getMessage().contains("Unauthorized"))) {
removeTask(taskId);
failure[0] = true;
Expand Down
1 change: 1 addition & 0 deletions src/com/qiniu/utils/IOnProcess.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

public interface IOnProcess {
public void onProcess(long current, long total);
public void onFailure(Exception ex);
}
44 changes: 24 additions & 20 deletions src/com/qiniu/utils/InputStreamAt.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.apache.http.entity.AbstractHttpEntity;

import java.io.*;
import java.util.Arrays;
import java.util.zip.CRC32;

public class InputStreamAt implements Closeable {
Expand Down Expand Up @@ -58,14 +57,14 @@ public InputStreamAt(byte[] data) {
mData = data;
}

public long getCrc32(long offset, int length) {
public long getCrc32(long offset, int length) throws IOException {
CRC32 crc32 = new CRC32();
byte[] data = read(offset, length);
crc32.update(data);
return crc32.getValue();
}

public long crc32() {
public long crc32() throws IOException {
if (mCrc32 >= 0) return mCrc32;
CRC32 crc32 = new CRC32();
long index = 0;
Expand Down Expand Up @@ -120,45 +119,50 @@ protected static File storeToFile(Context context, InputStream is) {
}
}

public byte[] read(long offset, int length) {
if (mClosed) return null;
try {
if (mFileStream != null) {
return fileStreamRead(offset, length);
}
if (mData != null) {
byte[] ret = new byte[length];
System.arraycopy(mData, (int) offset, ret, 0, length);
return ret;
}
} catch (IOException e) {
e.printStackTrace();
public byte[] read(long offset, int length) throws IOException {
if (mClosed) throw new IOException("inputStreamAt closed");
if (mFileStream != null) {
return fileStreamRead(offset, length);
}

return null;
if (mData != null) {
byte[] ret = new byte[length];
System.arraycopy(mData, (int) offset, ret, 0, length);
return ret;
}
throw new IOException("inputStreamAt not init");
}

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

int read;
int totalRead = 0;
synchronized (data) {
mFileStream.seek(offset);
do {
read = mFileStream.read(data, totalRead, length);
read = mFileStream.read(data, totalRead, length - totalRead);
if (read <= 0) break;
totalRead += read;
} while (length > totalRead);
}

if (totalRead != data.length) {
data = Arrays.copyOfRange(data, 0, totalRead);
data = copyOfRange(data, 0, totalRead);
}
return data;
}

public static byte[] copyOfRange(byte[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0) throw new IllegalArgumentException(from + " > " + to);
byte[] copy = new byte[newLength];
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
}

@Override
public synchronized void close(){
if (mClosed) return;
Expand Down
27 changes: 24 additions & 3 deletions src/com/qiniu/utils/MultipartEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;

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

@Override
public boolean isRepeatable() {
return false;
return true;
}

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

@Override
public void writeTo(OutputStream outputStream) throws IOException {
writed = 0;
outputStream.write(mData.toString().getBytes());
outputStream.flush();
writed += mData.toString().getBytes().length;
Expand All @@ -80,6 +82,7 @@ public boolean isStreaming() {
public void setProcessNotify(IOnProcess ret) {
mNotify = ret;
}
ExecutorService executor = Executors.newFixedThreadPool(1);

class FileInfo {

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

int blockSize = (int) (getContentLength() / 100);
if (blockSize > 256 * 1024) blockSize = 256 * 1024;
if (blockSize < 16 * 1024) blockSize = 16 * 1024;
if (blockSize < 32 * 1024) blockSize = 32 * 1024;
long index = 0;
long length = mIsa.length();
while (index < length) {
int readLength = (int) StrictMath.min((long) blockSize, mIsa.length() - index);
outputStream.write(mIsa.read(index, readLength));
int timeout = readLength * 2;
try {
write(timeout, outputStream, mIsa.read(index, readLength));
} catch (Exception e) {
mNotify.onFailure(e);
return;
}
index += blockSize;
outputStream.flush();
writed += readLength;
Expand All @@ -130,6 +139,18 @@ public void writeTo(OutputStream outputStream) throws IOException {
}
}

private void write(int timeout, final OutputStream outputStream, final byte[] data) throws InterruptedException, ExecutionException, TimeoutException {
Callable<Object> readTask = new Callable<Object>() {
@Override
public Object call() throws Exception {
outputStream.write(data);
return null;
}
};
Future<Object> future = executor.submit(readTask);
future.get(timeout, TimeUnit.MILLISECONDS);
}

private static String getRandomString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
Expand Down