Jean-Christophe Collet's Weblog
Jean-Christophe Collet's Weblog

20090316 Monday March 16, 2009

HttpURLConnection and 100-Continue

According to RFC 2616 section 8.2.3 a client can use the 'Expect: 100-continue' request header to make sure the server will accept the 'PUT' or 'POST' operation before actually sending the request body. This is particularly useful when said body is of a significant size, like when uploading a file. Indeed, if the request is denied by the server for any reason, checking this before sending the body can save a lot of bandwidth.

Unfortunately, at the moment, the HTTP protocol handler doesn't implement this correctly. There is code that is basically here to ignore the 100-continue response if it is ever returned by the HTTP server.

CR #6726695 has been filed against this and I just wanted to post a quick note as to how we intend to fix this in JDK 7.

In a effort to limit bloat, instead of introducing a specific API (new methods typically) we're planning on using the existing setRequestProperty() method. Basically if the applications sets the "Expect: 100-Continue" header, then the protocol handler will wait for a 100-Continue response code.  When the application calls getOutputStream() it will throw a ProtocolException if the server rejected the request (i.e. returned something else than 100-Continue). A typical usage would be something like:

        URLConnection con = url.openConnection();
        HttpURLConnection http = (HttpURLConnection) con;
        http.setRequestMethod("POST");
        http.setRequestProperty("Expect", "100-Continue");
        http.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        http.setDoOutput(true);
        int l = data.length() + (boundary.length()*2) + 14 + dispo.length() + ctype.length();
        http.setFixedLengthStreamingMode(l);
        OutputStream out = null;
        try {
            out = http.getOutputStream();
        } catch (ProtocolException e) {
            System.err.println("Server rejected the request. Code = " + http.getResponseCode());
            return;
        }

Note that getResponseCode() will provide the actual code returned.

IF 100-continue was received then the application can proceed providing the request body by writing to the OutputStream. The response code will then be updated with the one sent by the server after the POST (or PUT). Hopefully a 200-OK.

E.g (as a followup of code above):

        BufferedWriter outs = new BufferedWriter(new OutputStreamWriter(out));
        outs.write("--" + boundary + "\r\n");
        outs.write(dispo);
        outs.write(ctype);
        outs.write("\r\n");
        outs.write(data);
        outs.write("\r\n--" + boundary + "--\r\n");
        outs.flush();
        InputStream in = http.getInputStream();
        System.err.println("Response code is " + http.getResponseCode());
        BufferedReader ins = new BufferedReader(new InputStreamReader(in));
        String line = ins.readLine();
        while (line != null) {
            System.err.println(line);
            line = ins.readLine();
        }
        ins.close();
        outs.close();

Let me know what you think of this. Unless there are serious objections to this solution, I intend to push the fix into JDK 7 master in a week or two.

 
  

(2009-03-16 06:07:10.0) Permalink Comments [3]


archives
links
referers