Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I would like to have the files that are dropped in this angularjs html5 upload example at JSFiddle:

http://jsfiddle.net/danielzen/utp7j/

uploaded to a backend by a grails controller. While trying to accomplish this I created a simple grails controller:

class UploadController {

    def index() {

        if (request instanceof MultipartHttpServletRequest){
            for(filename in request.getFileNames()){
                MultipartFile file = request.getFile(filename)
                String newFileName = UUID.randomUUID().toString() + file.originalFilename.substring(file.originalFilename.lastIndexOf("."))
                file.transferTo(new File("/home/myuser/temp/$newFileName"))
            }
        }

        render "ok"
    }

}

Then I open an ajax XmlHttpRequest2 POST to the grails controller:

xhr.open("POST", "http://localhost:8080/app/upload")

but the grails controller cannot cast the request to MultipartHttpServletRequest, probably because this ajax way of invoking the grails controller is not using the multipart/form-data way of uploading. I tried setting the header on xhr for enctype multipart/form-data to no avail.

I'm completely stuck at the moment and would like to know how I can process the uploaded files in the grails controller

share|improve this question
 
Look inside params whats in there? –  James Kleeh Oct 15 '13 at 4:40
add comment

2 Answers

up vote 1 down vote accepted

I traced the POST request that was generated by the XmlHttpRequest.send(formData) call with the built-in Chrome Developer Tools. To my surprise the request method was not of type POST with enctype=multipart/form-data but of type OPTIONS.

This hint got me on the right track and with the help of Google I found out that this OPTIONS request happens as a preflight check as per-spec defined by CORS.

From wikipdia:

Cross-origin resource sharing (CORS) is a mechanism that allows JavaScript on a web page to make XMLHttpRequests to another domain, not the domain the JavaScript originated from.[1] Such "cross-domain" requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request.[2] It is more powerful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.

The CORS standard works by adding new HTTP headers that allow servers to serve resources to permitted origin domains. Browsers support these headers and enforce the restrictions they establish. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers “preflight” the request, soliciting supported methods from the server with an HTTP OPTIONS request header, and then, upon “approval” from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether “credentials” (including Cookies and HTTP Authentication data) should be sent with requests.

Because my grails (tomcat) server was running from localhost:8080 and my html/javascript was running from within the WebStorm IDE on its built-in http server on localhost:63342, the XmlHttpRequest was effectively CORS, because different port numbers on the same host are also considered cross-origin.

Thus, I needed to make sure that the Grails (tomcat) server allowed this, and I was able to do this with the excellent cors plugin for Grails which can be found at https://github.com/davidtinker/grails-cors

After that the request was recognized as a MultipartHttpServletRequest and the file could be fetched from params

share|improve this answer
add comment

Taking a peek at the network when doing the upload from the fiddle you get:

------WebKitFormBoundarygZi30fqQLB2A9qAC
Content-Disposition: form-data; name="uploadedFile"; filename="file.txt"
Content-Type: text/javascript


------WebKitFormBoundarygZi30fqQLB2A9qAC--

I believe then you'll get an "uploadedFile" as the param key into Grails, so you could write a controller action like:

def uploadFile(CommonsMultipartFile uploadedFile) {
    ///accessing the file data: uploadedFile.bytes, uploadedFile.contentType, uploadedFile.originalFilename
}

To be sure what is being passed do a debug on the params map that the action receives and change the action method parameter name accordingly.

share|improve this answer
 
That's what would be expected, but I ran into an issue because of CORS (Cross-Origin Resource Sharing) with the XmlHttpRequest. See my answer for more details. –  nkr1pt Oct 16 '13 at 16:44
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.