Introduction
In one of my projects, I had to be able to submit a data to the Web server using HTTP. The issue was that this data was multipart – that is, a combination of binary data and text data. So a simple GET
or POST
call would not have been sufficient. To my rescue, came Vlad Patryshev’s class: ClientHTTPRequest
. This highly versatile class allows you to easily submit multipart 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 the article here.
Now I modified this class to provide for progress information by making the following changes:
- 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.
- All the
write()
calls cause the data to be written to a ByteArrayOutputStream
, rather than directly to the OutputStream
of the connection. This is done because the content-length is needed to know ahead of time (before actually streaming 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:
…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());
}
- 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 50 KB at a time.
- 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);
public void setBytesToTransfer(long bytes);
public void statusMessage(String status);
public void transferComplete();
}
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);
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 multipart 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 demo (available for download with this article) 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.
History
- 27th January, 2006: Version 1.0