Multipart HTTP Forms Submitter – with Progress Information

Introduction

In one of my projects, I had to be able to submit data to the web server using HTTP. The issue was, that this data was multi-part – that is, a combination of binary data and text data. A simple GET or POST call would not be sufficient.

To my rescue, came Vlad Patryshev’s class: ClientHTTPRequest. This highly versatile class allows you to easily submit multi-part data via HTTP. However it was missing one thing: progress information. That is, when sending a large file via HTTP, the users would need to know how much of the file was already sent and how much more still remains to be sent. Therefore, I extended Vlad’s class to provide upload progress information.

Background

To better understand the methodology of using this class and the ideas behind it, I suggest reading Vlad’s article about his class ClientHTTPRequest. You can find that at: http://www.devx.com/Java/Article/17679/1954?pf=true

I modified the class to provide for progress information by making the following changes:

  1. Defer making the http connection until the actual posting takes place – the original class connects as soon as the write() function is called. In this version, the write function is called but no connection is made.
  2. All the write() calls cause the data to be written to a ByteArrayOutputStream, rather then directly to the OutputStream of the connection. This is done because the content-length is needed to know ahead of time (before actually steaming the data over through the socket) in order to provide for progress information and also in order to use the special setFixedLengthStreamingMode mode for the connection:
        b&ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
        protected void write(char c) throws Exception {
            baos.write(c);
        }
    
        protected void write(String s) throws Exception {
            baos.write(s.getBytes());
        }
    
  3. When the post() is called, only then an HTTP connection is created. This connection is given the setFixedLengthStreamingMode setting. Then, the contents of baos (the ByteArrayOutputStream to which everything was written), gets piped into the HTTP connection output stream in increments of 50KB at a time.
  4. It is also worthwhile to mention the addition of the SubmitProgress Interface, which is used to make clients of this class able to receive the following progress call backs:
    public interface SubmitProgress {
        public void bytesTransferred(long bytes); //called every 50KB of transfer to
                                                  // report how much was transferred so far
        public void setBytesToTransfer(long bytes); //tells the client how many bytes will
                                                    //actually get transferred. Useful to set a
                                                    //progress bar's top limit (setMaximum()).
        public void statusMessage(String status); //provides the current status of the operation
        public void transferComplete(); //called when the upload has been completed.
    }
    

Using the code

To use this code, you will need to include ClientHTTPRequest2.java and SubmitProgress.java in your project. You will also need to implement the SubmitProgress interface in order to receive progress information about the upload. Notice that you can set HTTP parameters (ones that can later be retrieved by your servlet/cgi code as if a web browser placed them in the URL query) and of course you can also append an entire file to the request. For instance the snippet below shows how you would submit a file and 2 parameters: user and password

        ClientHttpRequest2 chr=new ClientHttpRequest2(submitUrl);
        chr.setSubmitProgress(csp); //csp is an implementation of the SubmitProgress Interface.
        chr.setParameter("user",user);
        chr.setParameter("password",password);
        chr.setParameter("filename",new File(filename));

The above code will send an HTTP request to the web server pointed to by submitUrl. This request will have the parameters user, password and will also submit the contents of the file “filename” to the server. (Note: the server will need to know how to parse the multi-part format of the data). Progress information will be provided through the SubmitProgress interface. For example, the method SubmitProgress.bytesTransferred(long bytes) will be called periodically to notify how many bytes were already transferred.

The enclosed Demo performs a submit to a server at the localhost URL. You should change that URL to a webserver that is running remotely, and if the connection to it is say, DSL, which is relatively slow, you will get to see the upload progress. To run the Demo, simply compile all the files (javac *.java) and run the Main.java file (java Main). Then on the frame that shows up, click “Choose File”. You should choose a large file. Then, the button will change to “Upload File”. Press that and the file + the two parameters will get uploaded. The class DemoFrame in this Demo, is a good example of how to implement the SubmitProgress Interface in order to get progress information.

Downloads

Source file: ClientHTTPRequest2_src.zip

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read