Uploading files cross-domain, ajax-style

July 22, 2010 by: oyvind.kinsey

Uploading files the ‘ajax’-style is something that has been easy to do, as it’s really as easy as targeting a hidden iframe and returning the windows content after load. But when doing these uploads cross-domain, how are you then to get back the response? Well, once again, easyXDM comes to the rescue :)

If you want to skip to the result, check out the demo at http://consumer.easyxdm.net/current/example/upload.html!

We’ll start with the consumer, the document that will perform the upload

var rpc = new easyXDM.Rpc({
    remote: "http://remotedomain.com/upload-rpc.html"
}, {
    local: {
        returnUploadResponse: function(response){
            // here we will receive the result from the upload
            alert(response.msg);
        }
    }
});
<form enctype="multipart/form-data" target="upload_target" method="POST" action="http://remotedomain.com/upload.aspx">
    <input type="file" name="file"/>
    <input type="submit" value="Upload File"/>
</form>

As you can see, we defined and expose a method that will in the end receive the response from the remote domain.
In the HTML we create a form, and point its action at the remote upload.aspx file (where your upload will be directed) and its target to the upload_target frame that we will soon define.

Now lets take a look at the upload-rpc.html file referred to in the above code

var rpc= new easyXDM.Rpc({}, {
    remote: {
        returnUploadResponse: {}
    }
});
<iframe name="upload_target" src="about:blank"></iframe>

Doesn’t get much simpler than this :)
Here we simply create the provider and in the HTML we create the iframe that will be the target for our upload.

Ok, so far so good, but how do we get the response from the upload document (upload.aspx in our case) back to the consumer?

    <html><body><script>
        parent.rpc.returnUploadResponse({
            status: "success",
            msg: "The upload succeeded!"
        });
    </body></html>

As you can see, all this has to do is render Javascript code that uses its parents rpc object to return the response. Dead simple!

To sum it up, the upload goes directly from the consumer document to upload.aspx via POST, and then the response is returned via easyXDM in upload-rpc.html.

Filed under: Blog,Examples/How-to's
Tags: ,
  • Kuba

    so let me check if I got it straight – my consumer’s form posts to upload url, with the specified target iframe being in upload_rpc.html. After upload I’m getting back my result. I have two more questions – how the code in upload_rpc knows the result of upload ? And secondly do I get the iframe returned or just the rpc response ? I’m especially interested in the remote server sidesteps I need to take to get it going since I’ve got really limited access there and it would be best if I did it in a single tr

    • http://kinsey.no/ Øyvind Sean Kinsey

      It goes kinda like this;
      Domain A (the consumer) loads a document from domain B (the provider) using easyXDM.
      Domain A then targets a POST to an iframe located on domain B
      The POSTs action returns data via its parent which was loaded using easyXDM.

      Consumer > [POST] > upload-handler > [REF] > Provider (parent) > [easyXDM] > Consumer.

      The returned data is whatever the upload-handler chooses to pass back – but only data, no refs.

      • Kuba

        Ok so domain A loads ‘upload-rpc.htm’ using easyXDM, and then targets post to iframe located in ‘upload-rpc.htm’ but under ‘../upload.aspx’ address ? Function located under this address performs upload and what next ? It returns response under ‘/upload.aspx’ or sends it to iframe at ‘upload_rpc.html’ ? Do you have maybe some working code ? sorry for the trouble but I really need te get it going and I’m not sure if my remote server administrator will manage to work out how it should work.

  • bin

    If the Page used to upload itself is a ModalDialog it doesn’t work.

    • bin

      I am using IE 7

      • http://kinsey.no/ Øyvind Sean Kinsey

        Please take a minute and read through your comment before hitting ‘post’ – I have little idea of what you are talking about. What do you mean by Page (capital P), and what is a ModalDialog (is this a window created by window.showModalDialog ?)

        If you can provide a describe the issue so that I can understand it, then I will take the time to review it, ok? ;)

  • http://phun-ky.net/ phun-ky

    The example confuses me.. Here’s what I’m trying to do:

    I have a popupbox on a site (local) witch fetches content with XDS Ajax (JSONP) from another domain (remote).

    One of these popupbox content contains an image upload. I need to somehow incorporate the example stated above into this.

    Files:

    * index of local domain
    * ajax (over XDS file that fetches popupbox content and displays it on the local domain), the content contains the upload form and the upload target iframe
    * file on remote domain that uploads the file and saves it

    What should I add where? Hope you can give me a hint here ;)

    • http://kinsey.no/ Øyvind Sean Kinsey

      I suggest you follow the link to the example, go through this, and learn what makes it tick.
      After this it shouldn’t be a problem to figure out how it applies to your situation.

      Unfortunately it’s impossible for me (and I do not have the time for it) to give a precise answer here.
      Therefor you get my ‘standard’ answer, understand the basics, then apply it ;)

    • http://kinsey.no/ Øyvind Sean Kinsey

      Men ellers så virker det som et scenario ganske tilsvarende det som er vist her, og som eksempelet viser. Koden referert til som ‘consumer’ legger du inn i siden med popup’en, upload.(aspx|php|…) og upload-rpc.html legger du på domenet som skal ta i mot opplastingen. Videre er det bare å la upload-form’en poste til riktig frame, akkurat slik som i eksempelet…

      • http://phun-ky.net/ phun-ky

        Takk skal se på dette; )

        Men, hva gjør du når alle nettlesere fikser denne buggen med å tillate cross domain scripting? XDS er vel “forbudt” ?

        • http://kinsey.no/ Øyvind Sean Kinsey

          XDM (Messaging) er ikke forbudt, det er nettopp det HTML5 sin postMessage tilbyr – easyXDM utvider bare denne støtten til også å gjelde eldre nettlesere, da vha det som kan ansees som bugs, men som ikke kan lukkes på de spesifikke versjonene pga bakoverkompatibilitet.
          easyXDM er trygg i såmåte.

          Les artikkelen min på ScriptJunkie for å få litt bakgrunn: http://msdn.microsoft.com/en-us/scriptjunkie/ff800814

          • http://phun-ky.net/ phun-ky

            Ser nå at jeg får:

            “Access denied” på filen som prosesserer bildeopplastingen:

            parent.upload_avatar_rpc.returnUploadResponse({ i uploadImage.php

            Jeg må være molbo om dagen som ikke ser feilen her. Noen tips?

          • http://kinsey.no/ Øyvind Sean Kinsey

            Da har du gjort noe feil :)
            Det essensielle her er at `target` for form’en er plassert i filen som her er navngitt ‘upload-rpc.html’, og dette dokumentet er jo på samme domene som ‘uploadImage.php’. Om så er tilfelle vil du ikke få noen feil.

            Undersøk den genererte DOM’en i Firebug og verifiser at posten ender opp i riktig iframe.

          • http://phun-ky.net/ phun-ky

            “Det essensielle her er at `target` for form’en er plassert i filen som
            her er navngitt ‘upload-rpc.html’”

            Skjønte ikke det. Target i formen min er uploadImage.php som ligger på
            domene Y. Iframen ligger i samme form.

            Dette ligger i index.php på domene X som viser formen:
            http://pastebin.com/s8NXyBBV

            Og upload_avatar_rpc.html ligger på domene Y:
            http://pastebin.com/gxcsJK76

            ma., 07.02.2011 kl. 08.02 +0000, skrev Disqus:

          • http://phun-ky.net/ phun-ky

            NÅ fikk jeg det til ;) Så først nå at iframen måtte være i rpc filen eksternt! *doh*

            Takk for tålmodigheten ;)

          • http://kinsey.no/ Øyvind Sean Kinsey

            ‘target’ er ikke en ressurs men referanse til frame ved navn som requesten skal gjennomføres i. Ifm form så er det ‘action’ som designerer mål-ressursen. Er bakvendt, jeg vet det, men slik er nå HTML-standarden :)

  • elintegro inc

    The following PHP code snippet works on the server side. Note: I couldn’t get it to post the response at first and the doctype at the top did the trick!
    <!doctype html>
    <?
    $target_path = "pics/";
    $target_path = $target_path . basename( $_FILES['uploadedfile']['name']);
    $success = move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path);
    ?><html>
    <body>
    <script>
    parent.rpc.returnUploadResponse({
    status: "success",
    msg: "The upload succeeded!"
    });
    </body>
    </html>

    • http://kinsey.no/ Øyvind Sean Kinsey

      I’m guessing you’re not sending a content-type header?

      • elintegro inc

        Aha. Should that be done through an HTML tag on the uploader script (upload.php) ? What is the proper header in this case?

        • http://kinsey.no/ Øyvind Sean Kinsey

          The header needs to be set by the server (so php).
          http://php.net/manual/en/function.header.php

          • elintegro inc

            Makes sense. But what should the header be? Is it Content-type: text/javascript or text/html ?

          • http://kinsey.no/ Øyvind Sean Kinsey

            What is the document? Is a HTML-document or a javascript file ?

  • http://www.facebook.com/sime.vidas Šime Vidas

    Could you explain which files (HTML pages and server scripts) are involved in this process. Let’s say we have a HTML page from domain A, and we want to upload a file from that page to a server-site script on domain B (and then return the response back to the page). 

    So the HTML page is:
    http://www.domain-a.com/page.html

    And the server-side script is:
    http://www.domain-b.com/script.aspx
    (and let’s assume that the script returns an XML response)

    Are there any more HTML pages that are involved in this process? You mention “upload-rpc.html” which is on the remote domain – does this mean that an additional HTML document is required on the remote domain in order for this to work?

    That would be unfortunate because I cannot put additional HTML pages on the remote domain. I communicate with a Perl script which is on the remote domain, and I have CORS-rights to communicate with that script from my domain, but I am not able to put additional HTML pages on that domain.

    Does this mean that it is not possible for me to use your method?

    • http://kinsey.no/ Øyvind Sean Kinsey

      To use easyXDM the provider must always opt in to it by providing an easyXDM endpoint – so yes, you need to host a file on that domain, and also, the target needs to emit code specifically crafted to return the data.

      • http://www.facebook.com/sime.vidas Šime Vidas

        Ok, I’ll have to find another way (if there is one… I’ve set up a question over at Stack Overflow - http://stackoverflow.com/questions/6718664 )

        Anyways, thanks for the response :)

  • Parsmaninus

    sorry, but that example just is not self explaining at all!
    either documentation is just very poor or so am i.

    for example:

    you mention the iframe:
    but if i check the source of your demo at http://consumer.easyxdm.net/current/example/upload.htmlthen there is no iframe. so i have to guess that it is generated somehow by easyxdm – but whereis the documentation about that???how do i wire the submit action (click ob button) to actual upload? how does easyxdm know which form data (which includes the file selected) to upload???furthermore it is totally unclear where to put which file. and google does not help…

    • http://kinsey.no/ Øyvind Sean Kinsey

      The example works, is available in the download, and is easy to follow as long as you know what easyXDM is. Read the readme and look through the example files and you should be good to go.

      • Parsmaninus

        i followed every little step and what i have to say is: 
        just amazing!!! that’s a great peace of work!but it seems i have a problem with chrome. in chrome whenever i submit the form in order to upload the file a new tab opens. in your example the content of the new tab would be upload.aspx. and since a tab is opened the response cannot be returned to the parent via easyXDM – because there is no parent. i guess i am simply doing something wrong – any idea? in firefox everything works just fine and as expected, which means that no tab is opened and instead the “upload_target” is used correctly. To me it seems that chrome does not know that the “upload_target” is in the upload-rpc.html file (which is added to the dom via a dynamically created iframe).

  • Noreply

    great work! i am just having some security concerns, but maybe they are not relevant:
    As I have debugged with firebug easyxdm creates iframes like this here:

    My Questions are:

    Question-1. what is xdm_e used for?
    Question-2. what could happen if someone passes xdm_e=https://www.phishing.com ?
    Question-3. does easyxdm really support “cross-domain” or only “cross-sub-domain”?

    Imagine someone hacker sends you an email with the following link:
    https://test.mydomain.com/upload-rpc.html?xdm_e=https%3A%2F%2Fwww.mydomain.com&xdm_c=default7040&xdm_p=1

    You might think “well, I know that site so it is safe to click the link”.
    If you do that you might see a page that was created by the hacker to trick you and to make you type your username and password (“phishing”).

    On the other side I have debugged that in upload-rpc.html an additional iFrame is created (in case of that phishing attempt example) with the style

    element.style {    position: absolute;    top: -2000px;}

    The content of that iFrame is not visible – but the JavaScript is executed.

    Question-4. Do I have to worry about the JavaScript of that page (which comes from a different domain)?

    Now I am just wondering how easyxdm is handling such phishing attempts. Obviousely easyxdm recognizes that “something is wrong” and therefore the element style is used to hide the “bad” iFrame (see above).

    Question-5. But wouldn’t it be better to not add the iFrame to the dom in such cases in stead of using css?

    • http://kinsey.no/ Øyvind Sean Kinsey

      1) to state who/how the provider should talk to the consumer
      2) nothing, you would simply open https://test.mydomain.com/.. 
      3) yes, really – did you know that the text box I’m currently writing in is resized using easyXDM?
      4) no, only string messages are ever transferred across the SOP
      5) you are mistaking, the -2000px has nothing to do with this. Hiding the iframe is simply easyXDM’s default behavior.
      This should all be fairly well documented..

      • Anon

        4) If my Javascript contains an alert(“Hello World”), would this be shown?

        If it is shown, what prevents me from Building a Phishing-Form?;–

        • http://kinsey.no/ Øyvind Sean Kinsey

          I’m not sure what you are on about… If you have specific concerns then feel free to raise them, but please be specific.
          Asking if easyXDM could be used to build a phishing form is like asking if java can be used on a webpage – sure it’s possible, but why would you…

          • Noreply

            I think Anon wants to know if there is a possibility to make the upload-rpc.html file display/render the content of any other site. If that would work one could abuse the easyxdm upload-rpc.html for phishing attacks, i.e. to display a login form that makes the user think the form can be trused.

            An example:
            Lets say twitter has the upload-rpc.html file at
            easyxdm.twitter.com/upload-rpc.html
            Then the hacker could abuse it and send emails like 
            easyxdm.twitter.com/upload-rpc.html?xdm_e=https%3A%2F%2Fwww.phishing.com&xdm_c=default7040&xdm_p=1 what would make any user think that this link is trusted since it comes from twitter. 

            Now to Anon’s question, which I think you have already answered indirectly in your response 4) to my question from above: would it be possible that the upload-rpc.html file displays a faked form (in our example it come from http://www.phishing.com) if the user clicks the twitter link? Let’s also assume that www.phishing.com returns a form that looks and feels like a real twitter login form. I that form would be displayed then easyxdm could be easily used in my example for phishing attacks.

            From your responses to my questions I would understand that this is nothing to be concerned about, because per default easyxdm hides the iframe, so anything that comes from http://www.phishing.com and is inserted into the iframe is not visible. Anon is right – the alert is executed (I already mentioned that JavaScript is executed), but you will not be able to harm the user with that. I also understand that there is no way that the JavaScript in the iframe can access the cookies or session data from easyxdm.twitter.com since upload-rpc.html does not use this kind of data for the messaging.

            my conclusion: easyxdm is resistent to my phishing-email example and that is exactly ehat i wanted to know.

            Or am I wrong?

          • http://kinsey.no/ Øyvind Sean Kinsey

            Ah, I see the attack vector you are referring to now, the fact that the HashTransport will inject an I frame – I thought you were referring to a more general one. Full links are obscured by the commenting system.

            As you say, this frame is hidden and will not never be visible to any users – but to avoid the issue in total, you could use the Acl mechanism to only allow certain frames.

          • Noreply

            ok, i was wrong. let’s say the file coming
            from  http://www.phishing.com has nothing but
            the following JavaScript code:

            parent.window.location.href=’http://twitter.phishing.com’;

            In this case when the user clicks on the
            link from the email, then the user will be
            redirected to http://twitter.phishing.com
            where a twitter like login screen is displayed.

            to prevent this we have to set the acl property, i.e.
            acl : new Array(“*.twitter.com”)
            This way easyxdm only trusts *.twitter.com domains and
            therefore http://twitter.phishing.com would
            throw an error if passed via xdm_e.

            another option would be that in case upload-rpc.html
            is called first of all the xdm_e parameter is checked
            on server side. now if the server recognizes that
            xdm_e has an invalid url (i.e. from an other domain
            than expected) the the server will return a 404 page.
            but this also means one has to trust that easyxdm never
            changes the usage of xdm_e.

  • http://www.facebook.com/matteodepalo Matteo Depalo

    I’m not really sure where to put the script to return the response to the consumer. Could you be more specific? This is all really new to me…

  • Nobody

    Kind of important that a code blog has CSS such that you can read the code. Fixed width design can’t die soon enough.

  • Dmitry Stepankov

    it’s diffucult (((

  • Saša Milenković

    I am trying to use one form to select multiple files and then post each with separate post request using “multipart/form-data” as content type. I have “not allowed by Access-Control-Allow-Origin.” error. Could easyXDM help me with this post requests? Have you any example for multi-selected files (HTML5 for input type=file” has flag: multiple=”multiple”)?

  • lera

    set to ‘pre’ tag ‘white-space:pre-wrap’ style please =)

  • Smitenka

    Hi. 
    I have an interesting case. I’ve tried this code and works great. But i need something a bit different. I have a Parent website, which holds and iframe that points to localhost (it’s a must). 
    Now i need to get a file from http://localhost/myFile.png to my Parents website. Your example is based on file input. In my case it a local url. And i can’t submit to php with a custom link.
    Thank you.

  • Guest

    Hi when I am trying to use this its adding NAN to the resolveURL. something like this 13:58:13.617:{Private}: resolved url ‘https://mydomain.comNaN’

    var REMOTE= “https://mydomain.com”;

    var remote = new easyXDM.Rpc({
    remote: REMOTE + + “/staging/data/upload_handler.aspx”,
    onReady: function(){
    //display the upload form
    var frm = document.getElementById(“frmUpload”);
    frm.action = REMOTE + “/staging/data/uploadphoto.json”;
    btn = document.getElementById(“btnSubmit”);

    can someone help me with what I am missing?