title: jquery file upload with spring mvc : 400 bad request
body: <p>I coded a file upload with SpringMVC, following the manual example (LINK) and it works fine.</p>
  
  <p>Then, I changed the client to use jQuery file upload<br/>
  <a href="http://blueimp.github.com/jQuery-File-Upload/" rel="nofollow">http://blueimp.github.com/jQuery-File-Upload/</a><br/>
  in order to have a more powerful client (with drag and drop).<br/>
  I downloaded the widget and implemented a jsp with it.<br/>
  But it does not work. The browser receives a response 400 (bad request) and no exception is throw with tomcat7.</p>
  
  <p>I saw a difference in the request:
  with the working spring mvc doc exemple the request look like (firebug) :</p>
  
  <pre><code>-----------------------------26989305212543489571047641949 Content-Disposition: form-data; name="name"
  -----------------------------26989305212543489571047641949 Content-Disposition: form-data; name="file"; filename="content.txt"
  Content-Type: text/plain hello
  -----------------------------26989305212543489571047641949--
  </code></pre>
  
  <p>and for the non working jsp with jQuery fileupload default implementation the request in firebug looks like :</p>
  
  <pre><code>-----------------------------205805102810633831841397435868 Content-Disposition: form-data; name="files"; filename="content.txt" Content-Type: text/plain hello
  -----------------------------205805102810633831841397435868--
  </code></pre>
  
  <p>So, with the jQuery non working version, more is sent to the server. Some kind of extra meta-data. Is that the problem or am i searching in the wrong way? I’m no expert at all in file upload / multipart.</p>
  
  <p>Thanks for your help.</p>
  
  <p>Spring v3.1.2<br/>
  Tomcat v7.0<br/>
  jQuery 1.8<br/>
  The project use sitemesh (I don't think it makes a difference but...)</p>
  
  <p>The controller code</p>
  
  <pre><code>import java.io.IOException;
  
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestMethod;
  import org.springframework.web.bind.annotation.RequestParam;
  import org.springframework.web.multipart.MultipartFile;
  
  @Controller
  public class FileUploadController {
  
      @RequestMapping(value = "/form", method = RequestMethod.POST)
      public String handleFormUpload(@RequestParam(value="name",required=false) String  name,
         @RequestParam("file") MultipartFile file) throws IOException {
  
         if (!file.isEmpty()) {
             byte[] bytes = file.getBytes();
             // store the bytes somewhere
            return "redirect:home";
        } else {
            return "redirect:uploadFailure";
        }
         System.out.println(file.length);
         return "home";
      }
  
  }
  </code></pre>
  
  <p>working jsp:</p>
  
  <pre><code>&lt;%@ page language="java" contentType="text/html; charset=ISO-8859-1"
      pageEncoding="ISO-8859-1"%&gt;
  &lt;html&gt;
      &lt;head&gt;
         &lt;title&gt;Upload a file please&lt;/title&gt;
      &lt;/head&gt;
      &lt;body&gt;
         &lt;h1&gt;Please upload a file&lt;/h1&gt;
         &lt;form method="post" action="form" enctype="multipart/form-data"&gt;
             &lt;input type="text" name="name"/&gt;
             &lt;input type="file" name="file"/&gt;
             &lt;input type="submit"/&gt;
         &lt;/form&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Non working jsp (with jQuery) :</p>
  
  <pre><code>&lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;
  &lt;%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%&gt;
  &lt;%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator"
  
      prefix="decorator"%&gt;
      &lt;%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %&gt;
  
  &lt;!DOCTYPE html &gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;link rel="stylesheet" type="text/css" href="/ReformYourCountry/css/test-style.css" /&gt;
  &lt;link rel="stylesheet" type="text/css" href="/ReformYourCountry/css/template.css" /&gt;
  &lt;link rel="stylesheet" type="text/css" href="/ReformYourCountry/css/content.css" /&gt;
  &lt;!-- Shim to make HTML5 elements usable in older Internet Explorer versions --&gt;
  &lt;!--[if lt IE 9]&gt;&lt;script src="http://html5shim.googlecode.com/svn/trunk/html5.js"&gt;  &lt;/script&gt;&lt;![endif]--&gt;
  
  
  
  &lt;!-- for imageupload page --&gt;
  
  &lt;!-- Force latest IE rendering engine or ChromeFrame if installed --&gt;
  &lt;!--[if IE]&gt;&lt;meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"&gt;&lt;![endif]--&gt;
  &lt;meta charset="utf-8"&gt;
  &lt;title&gt;jQuery File Upload Demo&lt;/title&gt;
  &lt;meta name="description" content="File Upload widget with multiple file selection, drag&amp;amp;drop support, progress bar and preview images for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads."&gt;
  &lt;meta name="viewport" content="width=device-width"&gt;
  &lt;!-- jQuery UI styles --&gt;
  &lt;link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/base/jquery-ui.css" id="theme"&gt;
  &lt;!-- jQuery Image Gallery styles --&gt;
  &lt;link rel="stylesheet" href="http://blueimp.github.com/jQuery-Image-Gallery/css/jquery.image-gallery.min.css"&gt;
  &lt;!-- CSS to style the file input field as button and adjust the jQuery UI progress bars --&gt;
  &lt;link rel="stylesheet" href="css/jquery.fileupload-ui.css"&gt;
  &lt;!-- Generic page styles --&gt;
  &lt;link rel="stylesheet" href="css/style.css"&gt;
  &lt;!-- Shim to make HTML5 elements usable in older Internet Explorer versions --&gt;
  &lt;!--[if lt IE 9]&gt;&lt;script src="http://html5shim.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;&lt;![endif]--&gt;
  
  
  
  &lt;meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"&gt;
  &lt;title&gt;Insert title here&lt;/title&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
      &lt;!-- The file upload form used as target for the file upload widget --&gt;
      &lt;form id="fileupload" action="form" method="POST" enctype="multipart/form-data"&gt;
         &lt;!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --&gt;
         &lt;div class="row fileupload-buttonbar"&gt;
             &lt;div class="span7"&gt;
                 &lt;!-- The fileinput-button span is used to style the file input field as button --&gt;
                 &lt;span class="btn btn-success fileinput-button"&gt;
                     &lt;i class="icon-plus icon-white"&gt;&lt;/i&gt;
                     &lt;span&gt;Add files...&lt;/span&gt;
                     &lt;input type="file" name="files" multiple&gt;
                 &lt;/span&gt;
                 &lt;button type="submit" class="btn btn-primary start"&gt;
                     &lt;i class="icon-upload icon-white"&gt;&lt;/i&gt;
                     &lt;span&gt;Start upload&lt;/span&gt;
                 &lt;/button&gt;
                 &lt;button type="reset" class="btn btn-warning cancel"&gt;
                     &lt;i class="icon-ban-circle icon-white"&gt;&lt;/i&gt;
                     &lt;span&gt;Cancel upload&lt;/span&gt;
                 &lt;/button&gt;
                 &lt;button type="button" class="btn btn-danger delete"&gt;
                     &lt;i class="icon-trash icon-white"&gt;&lt;/i&gt;
                     &lt;span&gt;Delete&lt;/span&gt;
                 &lt;/button&gt;
                 &lt;input type="checkbox" class="toggle"&gt;
             &lt;/div&gt;
             &lt;!-- The global progress information --&gt;
             &lt;div class="span5 fileupload-progress fade"&gt;
                 &lt;!-- The global progress bar --&gt;
                 &lt;div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"&gt;
                     &lt;div class="bar" style="width:0%;"&gt;&lt;/div&gt;
                 &lt;/div&gt;
                 &lt;!-- The extended global progress information --&gt;
                 &lt;div class="progress-extended"&gt;&amp;nbsp;&lt;/div&gt;
             &lt;/div&gt;
         &lt;/div&gt;
         &lt;!-- The loading indicator is shown during file processing --&gt;
         &lt;div class="fileupload-loading"&gt;&lt;/div&gt;
         &lt;br&gt;
         &lt;!-- The table listing the files available for upload/download --&gt;
         &lt;table role="presentation" class="table table-striped"&gt;&lt;tbody class="files" data-toggle="modal-gallery" data-target="#modal-gallery"&gt;&lt;/tbody&gt;&lt;/table&gt;
      &lt;/form&gt;
  &lt;!-- The template to display files available for upload --&gt;
  &lt;script id="template-upload" type="text/x-tmpl"&gt;
  {% for (var i=0, file; file=o.files[i]; i++) { %}
      &lt;tr class="template-upload fade"&gt;
         &lt;td class="preview"&gt;&lt;span class="fade"&gt;&lt;/span&gt;&lt;/td&gt;
         &lt;td class="name"&gt;&lt;span&gt;{%=file.name%}&lt;/span&gt;&lt;/td&gt;
         &lt;td class="size"&gt;&lt;span&gt;{%=o.formatFileSize(file.size)%}&lt;/span&gt;&lt;/td&gt;
         {% if (file.error) { %}
             &lt;td class="error" colspan="2"&gt;&lt;span class="label label-important"&gt;{%=locale.fileupload.error%}&lt;/span&gt; {%=locale.fileupload.errors[file.error] || file.error%}&lt;/td&gt;
         {% } else if (o.files.valid &amp;&amp; !i) { %}
             &lt;td&gt;
                 &lt;div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"&gt;&lt;div class="bar" style="width:0%;"&gt;&lt;/div&gt;&lt;/div&gt;
             &lt;/td&gt;
             &lt;td class="start"&gt;{% if (!o.options.autoUpload) { %}
                 &lt;button class="btn btn-primary"&gt;
                     &lt;i class="icon-upload icon-white"&gt;&lt;/i&gt;
                     &lt;span&gt;{%=locale.fileupload.start%}&lt;/span&gt;
                 &lt;/button&gt;
             {% } %}&lt;/td&gt;
         {% } else { %}
             &lt;td colspan="2"&gt;&lt;/td&gt;
         {% } %}
         &lt;td class="cancel"&gt;{% if (!i) { %}
             &lt;button class="btn btn-warning"&gt;
                 &lt;i class="icon-ban-circle icon-white"&gt;&lt;/i&gt;
                 &lt;span&gt;{%=locale.fileupload.cancel%}&lt;/span&gt;
             &lt;/button&gt;
         {% } %}&lt;/td&gt;
      &lt;/tr&gt;
  {% } %}
  &lt;/script&gt;
  &lt;!-- The template to display files available for download --&gt;
  &lt;script id="template-download" type="text/x-tmpl"&gt;
  {% for (var i=0, file; file=o.files[i]; i++) { %}
      &lt;tr class="template-download fade"&gt;
         {% if (file.error) { %}
             &lt;td&gt;&lt;/td&gt;
             &lt;td class="name"&gt;&lt;span&gt;{%=file.name%}&lt;/span&gt;&lt;/td&gt;
             &lt;td class="size"&gt;&lt;span&gt;{%=o.formatFileSize(file.size)%}&lt;/span&gt;&lt;/td&gt;
             &lt;td class="error" colspan="2"&gt;&lt;span class="label label-important"&gt;{%=locale.fileupload.error%}&lt;/span&gt; {%=locale.fileupload.errors[file.error] || file.error%}&lt;/td&gt;
         {% } else { %}
             &lt;td class="preview"&gt;{% if (file.thumbnail_url) { %}
                 &lt;a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"&gt;&lt;img src="{%=file.thumbnail_url%}"&gt;&lt;/a&gt;
             {% } %}&lt;/td&gt;
             &lt;td class="name"&gt;
                 &lt;a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&amp;&amp;'gallery'%}" download="{%=file.name%}"&gt;{%=file.name%}&lt;/a&gt;
             &lt;/td&gt;
             &lt;td class="size"&gt;&lt;span&gt;{%=o.formatFileSize(file.size)%}&lt;/span&gt;&lt;/td&gt;
             &lt;td colspan="2"&gt;&lt;/td&gt;
         {% } %}
         &lt;td class="delete"&gt;
             &lt;button class="btn btn-danger" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}"&gt;
                 &lt;i class="icon-trash icon-white"&gt;&lt;/i&gt;
                 &lt;span&gt;{%=locale.fileupload.destroy%}&lt;/span&gt;
             &lt;/button&gt;
             &lt;input type="checkbox" name="delete" value="1"&gt;
         &lt;/td&gt;
      &lt;/tr&gt;
  {% } %}
  &lt;/script&gt;
  &lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"&gt;&lt;/script&gt;
  &lt;script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"&gt;&lt;/script&gt;
  &lt;!-- The Templates plugin is included to render the upload/download listings --&gt;
  &lt;script src="http://blueimp.github.com/JavaScript-Templates/tmpl.min.js"&gt;&lt;/script&gt;
  &lt;!-- The Load Image plugin is included for the preview images and image resizing functionality --&gt;
  &lt;script src="http://blueimp.github.com/JavaScript-Load-Image/load-image.min.js"&gt;&lt;/script&gt;
  &lt;!-- The Canvas to Blob plugin is included for image resizing functionality --&gt;
  &lt;script src="http://blueimp.github.com/JavaScript-Canvas-to-Blob/canvas-to-blob.min.js"&gt;&lt;/script&gt;
  &lt;!-- jQuery Image Gallery --&gt;
  &lt;script src="http://blueimp.github.com/jQuery-Image-Gallery/js/jquery.image-gallery.min.js"&gt;&lt;/script&gt;
  &lt;!-- The Iframe Transport is required for browsers without support for XHR file uploads --&gt;
  &lt;script src="js/jquery.iframe-transport.js"&gt;&lt;/script&gt;
  &lt;!-- The basic File Upload plugin --&gt;
  &lt;script src="js/jquery.fileupload.js"&gt;&lt;/script&gt;
  &lt;!-- The File Upload file processing plugin --&gt;
  &lt;script src="js/jquery.fileupload-fp.js"&gt;&lt;/script&gt;
  &lt;!-- The File Upload user interface plugin --&gt;
  &lt;script src="js/jquery.fileupload-ui.js"&gt;&lt;/script&gt;
  &lt;!-- The File Upload jQuery UI plugin --&gt;
  &lt;script src="js/jquery.fileupload-jui.js"&gt;&lt;/script&gt;
  &lt;!-- The localization script --&gt;
  &lt;script src="js/locale.js"&gt;&lt;/script&gt;
  &lt;!-- The main application script --&gt;
  &lt;script src="js/main.js"&gt;&lt;/script&gt;
  &lt;!-- The XDomainRequest Transport is included for cross-domain file deletion for IE8+ --&gt;
  &lt;!--[if gte IE 8]&gt;&lt;script src="js/cors/jquery.xdr-transport.js"&gt;&lt;/script&gt;&lt;![endif]--&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>