Skip to content

Commit 1629ad7

Browse files
committed
Avoid reading whole files into memory
1 parent b7dbe24 commit 1629ad7

File tree

3 files changed

+204
-87
lines changed

3 files changed

+204
-87
lines changed

src/com/loopj/android/http/AsyncHttpClient.java

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,7 @@
1818

1919
package com.loopj.android.http;
2020

21-
import java.io.IOException;
22-
import java.io.InputStream;
23-
import java.lang.ref.WeakReference;
24-
import java.util.HashMap;
25-
import java.util.LinkedList;
26-
import java.util.List;
27-
import java.util.Map;
28-
import java.util.WeakHashMap;
29-
import java.util.concurrent.Executors;
30-
import java.util.concurrent.Future;
31-
import java.util.concurrent.ThreadPoolExecutor;
32-
import java.util.zip.GZIPInputStream;
21+
import android.content.Context;
3322

3423
import org.apache.http.Header;
3524
import org.apache.http.HeaderElement;
@@ -67,7 +56,18 @@
6756
import org.apache.http.protocol.HttpContext;
6857
import org.apache.http.protocol.SyncBasicHttpContext;
6958

70-
import android.content.Context;
59+
import java.io.IOException;
60+
import java.io.InputStream;
61+
import java.lang.ref.WeakReference;
62+
import java.util.HashMap;
63+
import java.util.LinkedList;
64+
import java.util.List;
65+
import java.util.Map;
66+
import java.util.WeakHashMap;
67+
import java.util.concurrent.Executors;
68+
import java.util.concurrent.Future;
69+
import java.util.concurrent.ThreadPoolExecutor;
70+
import java.util.zip.GZIPInputStream;
7171

7272

7373
/**
@@ -389,7 +389,7 @@ public void post(String url, RequestParams params, AsyncHttpResponseHandler resp
389389
* @param responseHandler the response handler instance that should handle the response.
390390
*/
391391
public void post(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
392-
post(context, url, paramsToEntity(params), null, responseHandler);
392+
post(context, url, null, params, null, responseHandler);
393393
}
394394

395395
/**
@@ -420,7 +420,13 @@ public void post(Context context, String url, HttpEntity entity, String contentT
420420
public void post(Context context, String url, Header[] headers, RequestParams params, String contentType,
421421
AsyncHttpResponseHandler responseHandler) {
422422
HttpEntityEnclosingRequestBase request = new HttpPost(url);
423-
if(params != null) request.setEntity(paramsToEntity(params));
423+
if (params != null) {
424+
try {
425+
request.setEntity(paramsToEntity(params));
426+
} catch (IOException e) {
427+
responseHandler.onFailure(e, null);
428+
}
429+
}
424430
if(headers != null) request.setHeaders(headers);
425431
sendRequest(httpClient, httpContext, request, contentType,
426432
responseHandler, context);
@@ -479,7 +485,11 @@ public void put(String url, RequestParams params, AsyncHttpResponseHandler respo
479485
* @param responseHandler the response handler instance that should handle the response.
480486
*/
481487
public void put(Context context, String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
482-
put(context, url, paramsToEntity(params), null, responseHandler);
488+
try {
489+
put(context, url, paramsToEntity(params), null, responseHandler);
490+
} catch (IOException e) {
491+
responseHandler.onFailure(e, null);
492+
}
483493
}
484494

485495
/**
@@ -584,7 +594,7 @@ public static String getUrlWithQueryString(String url, RequestParams params) {
584594
return url;
585595
}
586596

587-
private HttpEntity paramsToEntity(RequestParams params) {
597+
private HttpEntity paramsToEntity(RequestParams params) throws IOException {
588598
HttpEntity entity = null;
589599

590600
if(params != null) {

src/com/loopj/android/http/RequestParams.java

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
import org.apache.http.protocol.HTTP;
2626

2727
import java.io.File;
28-
import java.io.FileInputStream;
2928
import java.io.FileNotFoundException;
29+
import java.io.IOException;
3030
import java.io.InputStream;
3131
import java.io.UnsupportedEncodingException;
3232
import java.util.ArrayList;
@@ -56,7 +56,10 @@
5656
*/
5757
public class RequestParams {
5858

59+
private static final String TAG = "RequestParams";
60+
5961
protected ConcurrentHashMap<String, String> urlParams;
62+
protected ConcurrentHashMap<String, StreamWrapper> streamParams;
6063
protected ConcurrentHashMap<String, FileWrapper> fileParams;
6164
protected ConcurrentHashMap<String, ArrayList<String>> urlParamsWithArray;
6265

@@ -128,7 +131,20 @@ public void put(String key, String value){
128131
* @param file the file to add.
129132
*/
130133
public void put(String key, File file) throws FileNotFoundException {
131-
put(key, new FileInputStream(file), file.getName());
134+
put(key, file, null);
135+
}
136+
137+
/**
138+
* Adds a file to the request.
139+
*
140+
* @param key the key name for the new param.
141+
* @param file the file to add.
142+
* @param contentType the content type of the file, eg. application/json
143+
*/
144+
public void put(String key, File file, String contentType) throws FileNotFoundException {
145+
if (key != null && file != null) {
146+
fileParams.put(key, new FileWrapper(file, contentType));
147+
}
132148
}
133149

134150
/**
@@ -155,22 +171,22 @@ public void put(String key, InputStream stream) {
155171
* Adds an input stream to the request.
156172
* @param key the key name for the new param.
157173
* @param stream the input stream to add.
158-
* @param fileName the name of the file.
174+
* @param name the name of the stream.
159175
*/
160-
public void put(String key, InputStream stream, String fileName) {
161-
put(key, stream, fileName, null);
176+
public void put(String key, InputStream stream, String name) {
177+
put(key, stream, name, null);
162178
}
163179

164180
/**
165181
* Adds an input stream to the request.
166182
* @param key the key name for the new param.
167183
* @param stream the input stream to add.
168-
* @param fileName the name of the file.
184+
* @param name the name of the stream.
169185
* @param contentType the content type of the file, eg. application/json
170186
*/
171-
public void put(String key, InputStream stream, String fileName, String contentType) {
187+
public void put(String key, InputStream stream, String name, String contentType) {
172188
if(key != null && stream != null) {
173-
fileParams.put(key, new FileWrapper(stream, fileName, contentType));
189+
streamParams.put(key, new StreamWrapper(stream, name, contentType));
174190
}
175191
}
176192

@@ -180,6 +196,7 @@ public void put(String key, InputStream stream, String fileName, String contentT
180196
*/
181197
public void remove(String key){
182198
urlParams.remove(key);
199+
streamParams.remove(key);
183200
fileParams.remove(key);
184201
urlParamsWithArray.remove(key);
185202
}
@@ -196,10 +213,19 @@ public String toString() {
196213
result.append(entry.getValue());
197214
}
198215

199-
for(ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
216+
for (ConcurrentHashMap.Entry<String, StreamWrapper> entry : streamParams.entrySet()) {
200217
if(result.length() > 0)
201218
result.append("&");
202219

220+
result.append(entry.getKey());
221+
result.append("=");
222+
result.append("STREAM");
223+
}
224+
225+
for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
226+
if (result.length() > 0)
227+
result.append("&");
228+
203229
result.append(entry.getKey());
204230
result.append("=");
205231
result.append("FILE");
@@ -222,14 +248,16 @@ public String toString() {
222248
return result.toString();
223249
}
224250

225-
/**
251+
/**
226252
* Returns an HttpEntity containing all request parameters
253+
*
254+
* @throws IOException if one of the streams cannot be read
227255
*/
228-
public HttpEntity getEntity() {
229-
if(!fileParams.isEmpty()) {
230-
return createMultipartEntity();
231-
} else {
256+
public HttpEntity getEntity() throws IOException {
257+
if (streamParams.isEmpty() && fileParams.isEmpty()) {
232258
return createFormEntity();
259+
} else {
260+
return createMultipartEntity();
233261
}
234262
}
235263

@@ -241,7 +269,7 @@ private HttpEntity createFormEntity() {
241269
}
242270
}
243271

244-
private HttpEntity createMultipartEntity() {
272+
private HttpEntity createMultipartEntity() throws IOException {
245273
SimpleMultipartEntity entity = new SimpleMultipartEntity();
246274

247275
// Add string params
@@ -258,25 +286,27 @@ private HttpEntity createMultipartEntity() {
258286
}
259287
}
260288

289+
// Add stream params
290+
for (ConcurrentHashMap.Entry<String, StreamWrapper> entry : streamParams.entrySet()) {
291+
StreamWrapper stream = entry.getValue();
292+
if (stream.inputStream != null) {
293+
entity.addPart(entry.getKey(), stream.name, stream.inputStream,
294+
stream.contentType);
295+
}
296+
}
297+
261298
// Add file params
262299
for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
263-
FileWrapper file = entry.getValue();
264-
if (file.inputStream != null) {
265-
if (file.contentType != null) {
266-
entity.addPart(entry.getKey(), file.getFileName(),
267-
file.inputStream, file.contentType);
268-
} else {
269-
entity.addPart(entry.getKey(), file.getFileName(),
270-
file.inputStream);
271-
}
272-
}
300+
FileWrapper fileWrapper = entry.getValue();
301+
entity.addPart(entry.getKey(), fileWrapper.file, fileWrapper.contentType);
273302
}
274303

275304
return entity;
276305
}
277306

278307
private void init(){
279308
urlParams = new ConcurrentHashMap<String, String>();
309+
streamParams = new ConcurrentHashMap<String, StreamWrapper>();
280310
fileParams = new ConcurrentHashMap<String, FileWrapper>();
281311
urlParamsWithArray = new ConcurrentHashMap<String, ArrayList<String>>();
282312
}
@@ -303,22 +333,24 @@ protected String getParamString() {
303333
}
304334

305335
private static class FileWrapper {
306-
public InputStream inputStream;
307-
public String fileName;
336+
public File file;
308337
public String contentType;
309338

310-
public FileWrapper(InputStream inputStream, String fileName, String contentType) {
311-
this.inputStream = inputStream;
312-
this.fileName = fileName;
339+
public FileWrapper(File file, String contentType) {
340+
this.file = file;
313341
this.contentType = contentType;
314342
}
343+
}
315344

316-
public String getFileName() {
317-
if(fileName != null) {
318-
return fileName;
319-
} else {
320-
return "nofilename";
321-
}
345+
private static class StreamWrapper {
346+
public InputStream inputStream;
347+
public String name;
348+
public String contentType;
349+
350+
public StreamWrapper(InputStream inputStream, String name, String contentType) {
351+
this.inputStream = inputStream;
352+
this.name = name;
353+
this.contentType = contentType;
322354
}
323355
}
324356
}

0 commit comments

Comments
 (0)