title: Java HTTP Client for Uploading Files (multipart/form-data)
body: <p>I'm trying implement an HTTP client that makes multipart requests for uploading files to a HTTP server. The HTML form has three input fields: one for the username, one for the password and one for the file. The server side looks as follows.</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
  &lt;title&gt;Uploader&lt;/title&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
     &lt;div id="header"&gt;
           &lt;h1&gt;Uploader&lt;/h1&gt;
     &lt;/div&gt;
     &lt;div id="content"&gt;
           &lt;form id="uploadformular" action="upload" method="post"
                  enctype="multipart/form-data" accept-charset="utf-8"&gt;
                  &lt;div class="block"&gt;
                         &lt;label for="user"&gt;Username&lt;/label&gt; &lt;input type="text" id="user"
                                name="myuser" required /&gt;
                  &lt;/div&gt;
                  &lt;div class="block"&gt;
                         &lt;label for="password"&gt;Password&lt;/label&gt; &lt;input type="password" id="pin"
                                name="mypassword" required /&gt;
                  &lt;/div&gt;
                  &lt;div class="block"&gt;
                         &lt;label for="file"&gt;ZIP File&lt;/label&gt; &lt;input type="file" id="file"
                                name="myfile" required /&gt;
                  &lt;/div&gt;
                  &lt;div&gt;
                         &lt;input type="submit" value="Upload" /&gt;
                  &lt;/div&gt;
           &lt;/form&gt;
     &lt;/div&gt;
  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>My implementation is as follows.</p>
  
  <pre><code>public class MultipartUploader {
  
      private static final String CHARSET = "UTF-8";
  
      private static final String CRLF = "\r\n";
  
      public String httpUpload(String url, String filename, byte[] byteStream)
          throws MalformedURLException, IOException {
  
          HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
          final String boundary = Strings.repeat("-", 15) + Long.toHexString(System.currentTimeMillis());
  
          connection.setDoOutput(true);
          connection.setDoInput(true);
          connection.setUseCaches(false);
          connection.setRequestMethod("POST");
          connection.setRequestProperty("Connection", "Keep-Alive");
          connection.setRequestProperty("Cache-Control", "no-cache");
          connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
  
          OutputStream directOutput = connection.getOutputStream();
          PrintWriter body = new PrintWriter(new OutputStreamWriter(directOutput, CHARSET), true);
  
          body.append(CRLF);
          addSimpleFormData("myuser", "myUserName", body, boundary);
          addSimpleFormData("mypassword", "mySecretPassword", body, boundary);
          addFileData("myfile", filename, byteStream, body, directOutput, boundary);
          addCloseDelimiter(body, boundary);
  
          int responseCode = connection.getResponseCode();
          String responseMessage = connection.getResponseMessage();
  
          String payload = CharStreams.toString(new InputStreamReader(connection.getInputStream()));
          return payload;
      }
  
      private static void addSimpleFormData(String paramName, String wert, PrintWriter body,
          final String boundary) {
  
          body.append(boundary).append(CRLF);
          body.append("Content-Disposition: form-data; name=\"" + paramName + "\"").append(CRLF);
          body.append("Content-Type: text/plain; charset=" + CHARSET).append(CRLF);
          body.append(CRLF);
          body.append(wert).append(CRLF);
          body.flush();
      }
  
      private static void addFileData(String paramName, String filename, byte[] byteStream, PrintWriter body,
          OutputStream directOutput, final String boundary) throws IOException {
  
          body.append(boundary).append(CRLF);
          body.append("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + filename + "\"")
              .append(CRLF);
          body.append("Content-Type: application/octed-stream").append(CRLF);
          body.append("Content-Transfer-Encoding: binary").append(CRLF);
          body.append(CRLF);
          body.flush();
  
          directOutput.write(byteStream);
          directOutput.flush();
  
          body.append(CRLF);
          body.flush();
      }
  
      private static void addCloseDelimiter(PrintWriter body, final String boundary) {
  
          body.append(boundary).append("--").append(CRLF);
          body.flush();
      }
  }
  </code></pre>
  
  <p>The server responds with <code>200 OK</code>. The problem I have is that somehow the HTTP body is not correctly created so that the response I get from the server says that not all fields of the form are set. The server doesn't say which field it is.
  So my question is do you see any problem with this code? Do I create the multipart request correctly?</p>
  
  <p>I also tried to upload a file using <code>cURL</code> with the following command and it worked.</p>
  
  <pre><code>cURL -F "myuser=myUserName" -F "mypassword=mySecretPassword" -F "myfile=@/path/to/my/file.zip" "http://abcdef.gh:1234/path/to/uploader"
  </code></pre>