Thursday, May 6, 2010

Re: [android-developers] Re: Uploading large files - using setChunkedStreamingMode

keianhzo,
Do you have an example of how you call this class? 
I think I understand, but wanted to doublecheck.

I am using an HttpURLConnection with ChunkedStreaming mode to upload videos to Facebook.
Using that mode successfully avoids running into memory issues, but I am not successful in getting a response back from Facebook.

Carmen

> > // Set up URL Connection for streaming
> > HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
> > conn.setDoInput(true);
> > conn.setDoOutput(true);
> > conn.setUseCaches(false);
> > conn.setChunkedStreamingMode(
1000*1024);
> > conn.setRequestMethod("POST");
> > conn.setRequestProperty("Connection", "Keep-Alive");
> > conn.setRequestProperty("Content-Type",
> > "multipart/form-data;boundary="+boundary);



On Tue, Apr 27, 2010 at 7:53 PM, keianhzo <imanol.martin@gmail.com> wrote:
Hi,

I had big headaches with this issue too, and finally opted for using
sockets to upload big files otherwise any way tried always led me to
the OutOfMemoryException or BufferOverflowException. So here is the
code that works for me. All the meat is in the send() method, but I
post the whole class for a better understanding. Feel free to use it
or modify it to fit your needs if your find it useful:

public class HttpMultipartClient {

       public class Parameter {

               private String name;
               private String value;

               public Parameter(String n, String v) {
                       name = n;
                       value = v;
               }

               public void setName(String n) {
                       name = n;
               }

               public void setValue(String v) {
                       value = v;
               }

               public String getName() {
                       return name;
               }

               public String getValue() {
                       return value;
               }

               @Override
               public String toString() {
                       return getName() + ":" + getValue();
               }
       }

       private static final String TAG = "HttpMultipartClient";

       private static final int CONNECTION_TIMEOUT = 10000;
       private static final String END = "\r\n";
       private final String boundary = new Integer(new Random()
                       .nextInt(Integer.MAX_VALUE)).toString();
       private final String lastBoundary = END + "--" + boundary + "--" +
END;

       private Socket socket;
       private String host;
       private int port;
       private String path;
       private String method;
       private List<Parameter> headers;
       private List<Parameter> cookies;
       private List<Parameter> fields;
       private String fileName;
       private InputStream fileStream;
       private int fileSize;
       private int responseCode;
       private String responseMessage;
       private String responseBody;
       private List<Parameter> responseHeaders;

       private StringBuilder headersBuffer;
       private StringBuilder bodyBuffer;
       private long length = 0;

       public HttpMultipartClient(String h, String pth, int p)
                       throws IllegalArgumentException {
               if (h == null || h.length() == 0)
                       throw new IllegalArgumentException("Invalid host name: host=" + h);
               else {
                       host = h;
                       path = pth;
                       port = p;
                       socket = new Socket();
                       headers = new ArrayList<Parameter>();
                       cookies = new ArrayList<Parameter>();
                       fields = new ArrayList<Parameter>();
                       responseHeaders = new ArrayList<Parameter>();
                       responseBody = null;
               }
       }

       public void disconnect() throws IOException {
               socket.close();
       }

       public void addHeader(String name, String value)
                       throws IllegalArgumentException {
               if (name == null || value == null)
                       throw new IllegalArgumentException("Header invalid: name=" + name
                                       + ", value=" + value);
               else {
                       headers.add(new Parameter(name, value));
                       if (Log.isLoggable(TAG, Log.DEBUG))
                               Log.d(TAG, "Adding header [" + name + ": " + value + "]");
               }
       }

       public void addCookie(String name, String value)
                       throws IllegalArgumentException {
               if (name == null || value == null)
                       throw new IllegalArgumentException("Cookie invalid: name=" + name
                                       + ", value=" + value);
               else {
                       cookies.add(new Parameter(name, value));
                       if (Log.isLoggable(TAG, Log.DEBUG))
                               Log.d(TAG, "Adding cookie [" + name + ": " + value + "]");
               }
       }

       public void addField(String name, String value)
                       throws IllegalArgumentException {
               if (name == null || value == null)
                       throw new IllegalArgumentException("Field invalid: name=" + name
                                       + ", value=" + value);
               else {
                       fields.add(new Parameter(name, value));
                       if (Log.isLoggable(TAG, Log.DEBUG))
                               Log.d(TAG, "Adding field [" + name + ": " + value + "]");
               }
       }

       public void addFile(String fn, InputStream is, int fs) {
               if (is == null)
                       throw new IllegalArgumentException("Invalid null input stream");
               else {
                       fileName = fn;
                       fileStream = is;
                       fileSize = fs;
                       if (Log.isLoggable(TAG, Log.DEBUG))
                               Log.d(TAG, "Adding file [filename: " + fileName + "]");
               }
       }

       private void prepare() {
               preHeaders();
               prepareBody();
               postHeaders();
       }

       private void preHeaders() {
               if (Log.isLoggable(TAG, Log.DEBUG))
                       Log.d(TAG, "Pre headers");

               headersBuffer = new StringBuilder();
               headersBuffer.append(method + " " + path + " HTTP/1.1" + END);
               headersBuffer.append("User-Agent: FileSocialClient 1.0" + END);
               headersBuffer.append("Host: " + host + END);
               headersBuffer.append("Content-Type: multipart/form-data; boundary="
                               + boundary + END);

               if (!headers.isEmpty()) {
                       for (Iterator<Parameter> it = headers.iterator(); it.hasNext();) {
                               Parameter param = it.next();
                               headersBuffer.append(param.getName());
                               headersBuffer.append(": ");
                               headersBuffer.append(param.getValue());
                               headersBuffer.append(END);

                               if (Log.isLoggable(TAG, Log.DEBUG))
                                       Log.d(TAG, "Header added: " + param);
                       }
               }

               if (!cookies.isEmpty()) {
                       headersBuffer.append("Cookie: ");
                       for (Iterator<Parameter> it = cookies.iterator(); it.hasNext();) {
                               Parameter param = it.next();

                               headersBuffer.append(param.getName());
                               headersBuffer.append("=");
                               headersBuffer.append(param.getValue());

                               if (it.hasNext())
                                       headersBuffer.append("; ");

                               if (Log.isLoggable(TAG, Log.DEBUG))
                                       Log.d(TAG, "Cookie added: " + param);
                       }
                       headersBuffer.append(END);
               }

               headersBuffer.append("Content-Length: ");
       }

       private void postHeaders() {
               if (Log.isLoggable(TAG, Log.DEBUG))
                       Log.d(TAG, "Post headers");

               length = fileSize + lastBoundary.length() + bodyBuffer.length();
               headersBuffer.append(length);
               headersBuffer.append(END + END);
       }

       private void prepareBody() {
               if (Log.isLoggable(TAG, Log.DEBUG))
                       Log.d(TAG, "Preparing body");

               bodyBuffer = new StringBuilder();

               if (!fields.isEmpty()) {
                       for (Parameter param : fields) {
                               bodyBuffer.append("--");
                               bodyBuffer.append(boundary);
                               bodyBuffer.append(END);
                               bodyBuffer.append("Content-Disposition: form-data; name=\"");
                               bodyBuffer.append(param.getName());
                               bodyBuffer.append("\"");
                               bodyBuffer.append(END);
                               bodyBuffer.append(END);
                               bodyBuffer.append(param.getValue());
                               bodyBuffer.append(END);

                               if (Log.isLoggable(TAG, Log.DEBUG))
                                       Log.d(TAG, "Field added: " + param);
                       }
               }

               if (fileStream != null) {
                       bodyBuffer.append("--");
                       bodyBuffer.append(boundary);
                       bodyBuffer.append(END);
                       bodyBuffer.append("Content-Disposition: form-data; name=\"");
                       bodyBuffer.append("file");
                       bodyBuffer.append("\"; filename=\"");
                       bodyBuffer.append(fileName);
                       bodyBuffer.append("\"");
                       bodyBuffer.append(END);
                       bodyBuffer.append(END);
               }
       }

       public void send() throws IOException {
               prepare();

               BufferedReader reader = null;
               try {
                       // We send the Http Request
                       socket.connect(new InetSocketAddress(host, port));
//                      socket.setSoTimeout(CONNECTION_TIMEOUT);
                       int bytesSent = 0;
                       PrintStream out = new PrintStream(socket.getOutputStream());
                       out.print(headersBuffer);
                       out.print(bodyBuffer);
                       bytesSent += headersBuffer.length() + headersBuffer.length();

                       byte[] bytes = new byte[1024 * 65];
                       int size;
                       while ((size = fileStream.read(bytes)) > 0) {
                               bytesSent += size;
                               out.write(bytes, 0, size);
                               out.flush();
                       }

                       out.print(lastBoundary);
                       out.flush();

                       // We read the response from the server
                       reader = new BufferedReader(new
InputStreamReader(socket.getInputStream()));
                       String line = reader.readLine();
                       String[] responseLine = line.trim().split(" ",3);
                       responseCode = new Integer(responseLine[1]);
                       responseMessage = responseLine[2];

                       boolean headersEnd = false;
                       while (( line = reader.readLine()) != null && !headersEnd){
                               if (line.length() == 0)
                                       headersEnd = true;
                               else {
                                       String[] headerLine = line.trim().split(":",2);
                                       responseHeaders.add(new Parameter(headerLine[0], headerLine[1]));
                               }
                       }

                       StringBuffer payload = new StringBuffer();
                       boolean bodyEnd = false;
                       while (( line = reader.readLine()) != null && !bodyEnd) {
                               if (line.length() == 0)
                                       bodyEnd = true;
                               else
                                       payload.append(line.trim());
                       }

                       responseBody = payload.toString();

               } finally {
                       try {
                               fileStream.close();
                               if (reader != null)
                                       reader.close();

                       } catch (IOException e) {
                               // TODO Auto-generated catch block
                               e.printStackTrace();
                       }
               }
       }

       public void setRequestMethod(String m) {
               method = m;
       }

       public void setPath(String p) {
               path = p;
       }

       public String getRequestMethod() {
               return method;
       }

       public String getPath() {
               return path;
       }

       public int getResponseCode() {
               return responseCode;
       }

       public String getResponseMessage() {
               return responseMessage;
       }

       public List<Parameter> getResponseHeaders() {
               return responseHeaders;
       }

       public String getResponseBody() {
               return responseBody;
       }
}

Hope it helps!
Bye!

On Apr 27, 2:50 pm, ferob...@gmail.com wrote:
> Hi Carmen,
>
> I run into the same OutOfMemoryError issue when uploading video files of  
> several MB within my app. I decided to look into this for the next version  
> of the app. So, in the unlikely event you still haven't found a solution  
> for this, here is how I get an answer from the server, even when using  
> setChunkedStreamingMode:
>
> DataInputStream inStream = new DataInputStream ( conn.getInputStream() );
> String oneLine, fullMsg="", msgStr;
> while (( oneLine = inStream.readLine()) != null) {
> if (DEBUG) Log.d(TAG, "Server Response: " + oneLine);
> fullMsg += oneLine + "\n";}
>
> inStream.close();
>
> I could have used a StringBuilder for fullMsg, but I have 2 lines at most  
> coming from the server.
>
> Robert
> ------http://dailyroads.com/voyager/
>
>
>
>
>
> > If I upload a large file using an HttpURLConnection and
> > setChunkedStreamingMode the file is successfully uploaded. But, I am not
> > able to read the response from the server.
> > If I leave out streaming mode line:
> > conn.setChunkedStreamingMode(1000*1024);
> > I get an out of memory error on large file, but this works well for small
> > files and I get a response from the server.
> > Any insights on this?
> > Carmen
> > // Set up URL Connection for streaming
> > HttpURLConnection conn = (HttpURLConnection) connectURL.openConnection();
> > conn.setDoInput(true);
> > conn.setDoOutput(true);
> > conn.setUseCaches(false);
> > conn.setChunkedStreamingMode(1000*1024);
> > conn.setRequestMethod("POST");
> > conn.setRequestProperty("Connection", "Keep-Alive");
> > conn.setRequestProperty("Content-Type",
> > "multipart/form-data;boundary="+boundary);
> > // Read response
> > // this works for small files when not in streaming mode
> > // for large files, connection is reset by server (time outs)
> > Reader reader = new InputStreamReader( conn.getInputStream() );
> > StringBuilder in = new StringBuilder( 32000 );
> > int x;
> > while ( (x=reader.read()) != -1 ){
> > in.append( (char)x );
> > }
>
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-developers@googlegroups.com
> To unsubscribe from this group, send email to
> android-developers+unsubscribe@googlegroups.com
> For more options, visit this group athttp://groups.google.com/group/android-developers?hl=en

--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en



--
Carmen
http://www.twitter.com/CarmenDelessio
http://www.talkingandroid.com
http://www.facebook.com/BFFPhoto
http://www.twitter.com/DroidDrop

--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

No comments:

Post a Comment