PDA

View Full Version : Strange responseText with formUpdate and file upload



dbadke
18 Apr 2007, 1:29 PM
Ext JS 1.0 with YUI adaptor.

I load a form into a contentPanel dynamically (could be one of several forms):

var target = Ext.get('load-body');
if (target) {
var mgr = target.getUpdateManager();
mgr.update('servlets/get-uploader.php',
'node=' + this.clickedNode.id);
}


The JSON packet as sent from get-uploader.php is:

{"ok":true,"status":"",
"data":"<form id=\\"uploaderform\\" method=\\"post\\" action=\\"\\" enctype=\\"multipart\\/form-data\\">
<fieldset><label class=\\"normal\\">File to upload<\\/label>
<input type=\\"file\\" id=\\"ufile\\" name=\\"ufile\\" size=\\"32\\" \\/>
<div id=\\"uploadsubmit\\"><\\/div><\\/fieldset><\\/form>"}

and as received in the contentPanel renderer:

"{\"ok\":true,\"status\":\"\",
\"data\":\"<form id=\\"uploaderform\\" method=\\"post\\" action=\\"\\" enctype=\\"multipart\/form-data\\">
<fieldset><label class=\\"normal\\">File to upload<\/label><input type=\\"file\\" id=\\"ufile\\" name=\\"ufile\\" size=\\"32\\" \/>
<div id=\\"uploadsubmit\\"><\/div><\/fieldset><\/form>\"}"

The form has enctype="multipart/form-data" and is posted to the server with:

var url = 'servlets/uploadfiles.php?node=' + adminFileMgr.clickedNode.id;
var uploadForm = document.getElementById('uploaderform');
Ext.get('load-body').getUpdateManager().formUpdate(uploadForm, url, false);


The JSON response from uploadfiles.php is the same as before (ie: reloads the form):

{"ok":true,
"status":"<p>File upload successful.<\\/p>",
"data":"<form id=\\"uploaderform\\" method=\\"post\\" action=\\"\\" enctype=\\"multipart\\/form-data\\">
<fieldset><label class=\\"normal\\">File to upload<\\/label><input type=\\"file\\" id=\\"ufile\\" name=\\"ufile\\" size=\\"32\\" \\/>
<div id=\\"uploadsubmit\\"><\\/div><\\/fieldset><\\/form>"}

but the response as seen in the render is mangled:

"{\"ok\":true,
\"status\":\"<p>File upload successful.&lt;\/p&gt;\",
\"data\":\"</p><form id=\"\&quot;uploaderform\&quot;\" method=\"\&quot;post\&quot;\" action=\"\&quot;\&quot;\" enctype=\"\&quot;multipart\/form-data\&quot;\">
<fieldset><label class=\"\&quot;normal\&quot;\">File to upload&lt;\/label&gt;
<input id=\"\&quot;ufile\&quot;\" name=\"\&quot;ufile\&quot;\" size=\"32\" \=\"\" type=\"\&quot;file\&quot;\"></label>
<div id=\"\&quot;uploadsubmit\&quot;\">&lt;\/div&gt;&lt;\/fieldset&gt;&lt;\/form&gt;\"}
</div></fieldset></form>"

Note particularly the added crap at the end of the packet, outside the }. This only happens when enctype="multipart/form-data" - if I remove that and leave everything else the same, the form reloads correctly (though the file upload fails, of course).

I traced the formUpdate and the response as far as I could, but couldn't see where the problem might be. The JSON packet is already mangled when the formUpdate's processSuccess function triggers.

Help!

Animal
18 Apr 2007, 11:42 PM
It looks like a server problem. You can verify that using Fiddler to look at the HTTP traffic. It looks like the resopnse if being "overprocessed" on the server.

dbadke
19 Apr 2007, 7:42 AM
Fiddler shows that the response is arriving undamaged:

{"ok":true,"status":"<p>File upload successful.<\/p>",
"data":"<form id=\"uploaderform\" method=\"post\" action=\"\" enctype=\"multipart\/form-data\"><fieldset><label class=\"normal\">File to upload<\/label>
<input type=\"file\" id=\"ufile\" name=\"ufile\" size=\"32\" \/><br \/><br \/><div id=\"uploadsubmit\"><\/div><\/fieldset><\/form>"}

This suggests that the response handler in Ext or YUI is doing something to it, but only for enctype="multipart/form-data". I will try to trace it back to where the response is first received to see if I can locate where it changes.

dbadke
19 Apr 2007, 9:22 AM
Well, now I'm lost...

Fiddler reports that the JSON packet is OK when it goes through the proxy, but by the time YUI connection processing gets it in the uploadCallback function:

var uploadCallback = function() {

...

obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:null;

...
}

it is totally messed up - the innerHTML of the iframe used for the upload contains garbage. Something seems to be entity encoding the text AFTER it gets through the Fiddler proxy. Maybe Firefox is doing something to it? Is there anything happening between the browser receiving the response and loading it into the iframe, and the triggering of the callback?

Bafflement...

dbadke
19 Apr 2007, 10:57 AM
Further research...

It seems Firefox (at least, haven't tried others) objects strongly to getting a JSON packet as the response to a file upload request done through the Ext/YUI methods (that is, via a hidden iframe). If the response is straight text (even with HTML tags in it), there is no problem. I am not sure why this is, but Googling provides hints that it has something to do with security, perhaps an attempt to block cross-domain script attacks through hidden iframes.

Anyway, changing my JSON packet into a straight text packet that I parse myself solved the problem.

Perhaps a browser guru can explain this? :-?

Animal
19 Apr 2007, 11:05 AM
Ah, it was a file upload, and you were returning Json? It's probably going to cause problems. That just does a form submit with a target of an iframe. It does not use an XMLHttpRequest. The response goes straight into an HTML document and is scraped out of there by the YAHOO.util.Connect object.

The HTML parser might do strange things to a Json string.

chin
8 Jun 2007, 10:44 AM
I have the same problem. Yes, it is file upload + json.
It's a browser "feature", it tries to validate content delivered from backend.
If content-type in headers are text/html, it tries to close all html tags. So, if we send something like this:

{"html":"<b>bold<\/b>","output":""}
Browser will convert it to:

{"html":"<b>bold&lt;\/b&gt;","output":""}</b>
If content-type is text/plain, result content of iframe will be:

<pre>{"html":"&lt;b&gt;bold&lt;\/b&gt;","output":""}</pre>

The way I see, is to send valid xhtml content to iframe like this:

<script type="text/javascript">
doCallback({"html":"<b>bold<\/b>","output":""});
</script>
And use callback to fire response.

So, do we have some another ways to resolve it?

Animal
8 Jun 2007, 11:02 AM
You must send back an HTML document in response to a file upload. The response is sucked into an iframe document by the browser, and the innerHTML is scraped out to provide the responseText in a "faked" XHR object.

So if you must return a complex Json object, embed it in a <textarea> so that you can extract it from the faked responseText with a regex.

Animal
8 Jun 2007, 11:03 AM
chin's solution would work too. Send back code which you generate to execute whatever needs executing.