XML Parsing error: no root element found (empty content) Django - javascript

I am using ajax to connect to a view in my web application.
$.ajax({
url: url,
type: 'PATCH',
success: function() {
var d = new Date();
img = e.target.parentElement.parentElement.getElementsByTagName('img')[0];
if (img.src.includes("?")){
img.src = img.src.split("?")[0] + '?' + d.getTime();
} else {
img.src = img.src + '?' + d.getTime();
}
},
});
When I click on the button that triggers this, everything works, but I get an XML Parsing error. According to the other questions on stack exchange, this might be beacuse of an empty content. When I use the firefox developer tools, the content of the reverse of the concerned view is indeed empty, because of which, I think, firefox interprets it as an xml.
My problem is, that I do not know how to fill the content. In my view, I changed return Response(status=200) to return Response(status=200, content_type='image/jpeg'), because the view does something to an image. But still the content seems to stay empty and I still get the error. I don't know how else to alter the content type than by specifying it in the response.
I only get this error in firefox, not in chrome.

Turns out I only had to set the content_type to text/html...

The server response is missing header Content-Type.
So the JavaScript 'success' handler cannot parse correctly the response body.

Related

Return Content with alert in Controller

I'm trying to somewhat replicate what I saw in this question, particularly in this answer, but not quite the same.
My intent is, if the zip has no files (it can happen because the folder could be empty) I want to return an alert just so the user is warned that is not possible to obtain the file at the time.
But I'm missing on the redirection point, I don't want the alert to redirect the user to a blank page refering the Action, I want it to stay in the page, also due to some filters.
Is this possible? I couldn't find anything that would stop the redirection from happening.
Here is my the Action Controller code:
public ActionResult DownloadZip(List<int> things)
{
// Create zip with files
if (!zip.Any())
{
return Content(#"<script language='javascript' type='text/javascript'>
alert('Message');
</script>
");
}
// Return zip
}
Here is the call from the view:
$("#btnExportToZip").on("click", function (e) {
var grid = $("#gridThings").data("kendoGrid");
var items = grid.dataSource.data();
var lstIds = [];
$.each(items, function (index, elem) {
if (elem.Checked) {
lstIds.push(elem.Id);
}
});
if (lstIds.length > 0) {
var params = lstIds.join("&listAmostras=")
var url = '/Search/DownloadZip?listAmostras=' + params;
window.location.href = url;
}
});
If you do a redirect as you're doing here, it's too late to take it back once you've determined the zip file is empty. Your best bet here is probably to do an AJAX file download. Bear in mind, though, that this will require that the browser supports the HTML5 File API, so IE 9 and under are out.
$.ajax({
url: url,
async: false,
xhrFields: {
responseType: 'blob'
},
success: function (data) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);
}
});
Essentially what this does is request the zip file via AJAX. Once the file data has been received, an anchor link is added to the DOM (not visible) and dynamically "clicked" to approximate the behavior of user click a link to a static file. In other words, a download prompt will pop as soon as the AJAX request completes successfully. However, this code only removes the need to redirect. You still need to conditionally pop the download only if the zip file has something in. There's two ways you can accomplish that.
In the success callback of the AJAX, you would wrap the code there in a conditional that checks that data.size > 0. However, that might not actually work. I've never looked at an empty zip file, but it's entirely possible that there's file headers in the binary that would cause the blob to actually have a size greater than zero, even though it's "empty".
The better approach is to return an error response in your zip action when the zip file is empty. Off the top of my head, I'm not sure what the most appropriate error response code would be, but anything in 400-500 range will work for triggering the appropriate AJAX callback. Then, you just need to add and error handler to this AJAX. In that handler, you could then notify the user however you like that there's no download because the zip would be empty.
As per my understanding, alert is redirect the user to the blank page because in the javascript you have the line window.location.href = url; which might be redirect to the same action again which shows the alert.
So try to give the different url to the window.location.href
for ex:window.location.href = '../somecontroller/someaction';
thanks
Karthik

Trying to build query string and scrape Google results

I'm trying to build a Google query string, make a request to that page, scrape the HTML, and parse it in a Chrome extension, which is JavaScript. So I have the following code:
var url = "https://www.google.com/search?#q=" + artist + "+" + title;
searchGoogleSampleInformation(url);
function searchGoogleSampleInformation(url)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.onreadystatechange = function ()
{
if (xhr.readyState == 4)
{
return parseGoogleInformation(xhr.responseText, url);
}
}
xhr.send();
}
function parseGoogleInformation(search_results, url)
{
var link = $(".srg li.g:eq(0) .r a", search_results).attr('href');
}
The parse method just grabs the url of the first search result (which is not want I'll end up doing, but just to test that the HTTP Request was working). But link is undefined after that line. Then I used alert(url) and verified that my query string was being built correctly; I copied it from the alert window and pasted into another tab, and it pulled up the results as expected. Then I opened a new window with search_results, and it appeared to be Google's regular homepage with no search at all. I thought that problem might be occurring because of the asynchrony of the xhr.open call, but flipping that didn't help either. Am I missing something obvious?
It's because "https://www.google.com/search?#q=" + artist + "+" + title initially has no search results in the content. Google renders the page initially with no results and then dynamically loads the results via JavaScript. Since you are just fetching the HTML of the page and processing it the JavaScript in the HTML never gets executed.
You are making a cross domain Ajax call, which is not allowed by default. You cannot make a cross domain call unless the server supports it and you pass the appropriate headers.
However, as you mentioned you are building a Chrome extension, it is possible by adding a few fields in the manifest file: https://developer.chrome.com/extensions/xhr#requesting-permission

JavaScript: How to open a returned file via AJAX

This is similar to: How to open a file using JavaScript?
Goal: to retrieve/open a file on an image's double click
function getFile(filename){
// setting mime this way is for example only
var mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
jQuery.ajax({ url : 'get_file.pl',
data : {filename:filename},
success : function(data){
var win = window.open('','title');
win.document.open(mime);
win.document.write(data);
win.document.close();
}
});
}
jQuery('#imgID').dblclick(function(){
getFile('someFile.docx');
});
I'm doing this off the top of my head, but I think the above would work for text files, but not binary. Is there a plugin that does this properly? The ideal would be to open the file in the browser (or application), rather than download, but I doubt that is a dream. If the file must be downloaded with the save/open dialog, that's fine.
Edit:
One piece of information that I forgot to mention is that I'd like this to be a POST request. This is partly why I was looking at AJAX to begin with. I've seen workarounds that have created forms/iframes to do something similar, but I was looking for a better handler of the returned info.
Seems to me there's no reason to do this via AJAX. Just open the new window to get_file.pl?filename=... and let the browser handle it. If the user has a plugin capable of handling the Content-Type sent by get_file.pl, the file will display; otherwise, it should download like any other file.
function getFile(filename) {
window.open('get_file.pl?filename=' + filename,'title');
}
jQuery('#imgID').dblclick(function() {
getFile('someFile.docx');
});
Edit: If you want to POST to your script, you can do it with some <form> hackery:
function getFile(filename) {
var win = 'w' + Math.floor(Math.random() * 10000000000000);
window.open('', win,'width=250,height=100');
var f = $('<form></form>')
.attr({target: win, method:'post', action: 'get_file.pl'})
.appendTo(document.body);
var i = $('<input>')
.attr({type:'hidden',name:'filename',value:filename})
.appendTo(f);
f[0].submit();
f.remove();
}
Of course, this is somewhat silly since it is impossible to hide your data from "prying eyes" with developer tools. If your filename really is sensitive, issue access tokens to the client, and look up the data in your sever script.

dojo.io.iframe erroring when uploading a file

Hit an interesting problem today when trying to upload an image file < 2MB using dojo.io.iframe.
My function to process the form is called, but before the form is posted to the server I am getting the following error:
TypeError: ifd.getElementsByTagName("textarea")[0] is undefined
My function that is used to action the post of the form is :
function uploadnewlogo(){
var logoDiv = dojo.byId('userlogo');
var logoMsg = dojo.byId('uploadmesg');
//prep the io frame to send logo data.
dojo.io.iframe.send({
url: "/users/profile/changelogo/",
method: "post",
handleAs: "text",
form: dojo.byId('logoUploadFrm'),
handle: function(data,ioArgs){
var response = dojo.fromJson(data);
if(response.status == 'success'){
//first clear the image
//dojo.style(logoDiv, "display", "none");
logoDiv.innerHTML = "";
//then we update the image
logoDiv.innerHTML = response.image;
}else if(response.status == 'error'){
logoMsg.innerHTML = data.mesg;
}else{
logoMsg.innerHTML = '<div class="error">Whoops! We can not process your image.</div>';
}
},
error: function(data, ioArgs){
logoMsg.innerHTML = '<div class="error">' + data + '</div>';
}
});
}
The form is very basic with just a File input component and a simple button that calls this bit of javascript and dojo.
I've got very similar code in my application that uploads word/pdf documents and that doesn't error, but for some reason this does.
Any ideas or pointers on what I should try to get this to work without errors?
Oh I'm using php and Zend framework for the backend if that has anything to do with it, but I doubt it as it's not even hitting the server before it fails.
Many thanks,
Grant
Another common reason for this error is the server isn't packaging the data correctly. This means even if you have set "handleAs: json" you have to send that json wrapped in some html. This is what it should look like:
<html>
<body>
<textarea>
{ payload: "my json payload here" }
</textarea>
</body>
</html>
Your error was saying it couldn't find the textarea in your return from the server. For more look at http://docs.dojocampus.org/dojo/io/iframe
Since the load handler of dojo.io.iframe.send() has been triggered, the request should have been sent to the server and response is back. I think the response from server is not correct. Maybe the server returns an error page.
Use Firebug to inspect current page's DOM and find the transporting iframe created by Dojo and check its content. Firebug can capture iframe I/O too, check its Net tab. You may find the root cause of this issue.
Did you respect the constraint written in the doc ?
IMPORTANT: For all values EXCEPT html and xml, The server response should be an HTML file with a textarea element. The response data should be inside the textarea element. Using an HTML document is the only reliable, cross-browser way this transport can know when the response has loaded. For the text/html (Or XML) mimetype, just return a normal HTML/XML document. In other words, your services for JSON and Text formats should return the data wrapped as the following:

Dynamically Preloading/Displaying Webcam Snapshots on a Web Page Using AJAX

I have an IP Camera that streams out live video to a web site of mine. Problem is, it is powered by an ActiveX control. Even worse, this control is unsigned. To provide a more secure alternative to the people that are using browsers other than IE, or are (rightfully) unwilling to change their security settings, I am tapping into the cameras built in snap-shot script that serves up a 640x480 live JPEG image. The plan was to update the image live on the screen every ~500ms using Javascript without having to reload the entire page.
I tried using the Image() object to pre-load the image and update the SRC attribute of the image element when onload fired:
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
img = new Image();
img.onload = function() {
$("#livePhoto").attr("src", url);
camTimer = setTimeout(updateCam, 500);
}
img.src = url;
}
This worked decently, but it was difficult to determine when the camera had been disabled, which I needed to do in order to degrade gracefully. The internal snapshot script is setup to return an HTTP status code of 204 (No Content) under this circumstance, and of course there is no way for me to detect that using the Image object. Additionally, the onload event was not 100% reliable.
Therefore, I am using the jQuery (version 1.2.6) ajax function to do a GET request on the URL, and on the complete callback I evaluate the status code and set the URL accordingly:
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
And this works beautifully. But only in IE! This is the question that I would like to have answered: Why doesn't this work in Firefox or Chrome? The complete event does not even fire in Firefox. It does fire in Chrome, but only very rarely does setting the SRC actually load the image that was requested (usually it displays nothing).
Posting a second answer, because the first was just really incorrect. I can't test this solution (because I don't have access to your webcam script), but I would suggest trying to sanitise the response from the camera - since you obviously can't handle the raw image data, try adding the dataFilter setting like so:
function updateCam() {
var url = "../snapshopt.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
dataFilter : function(data, type) {
return '<div></div>' //so it returns something...
},
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#live").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
Like I said, I haven't been able to test this - but it might allow jquery to use the status codes without breaking like crazy.
img.onerror = function(){
alert('offline');
}
Well, I ended up using the data URI scheme (hat tip to Eric Pascarello) for non-IE browsers. I wrote a HTTP handler (in VB.NET) to proxy the IP camera and base-64 encode the image:
Imports Common
Imports System.IO
Imports System.Net
Public Class LiveCam
Implements IHttpHandler
Private ReadOnly URL As String = "http://12.34.56.78/snapshot.cgi"
Private ReadOnly FAIL As String = Common.MapPath("~/i/cam-oos.jpg")
Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
Dim Data As Byte()
With context.Response
.ContentEncoding = Encoding.UTF8
.ContentType = "text/plain"
.Write("data:image/png;base64,")
Try
Using Client As New WebClient()
Data = Client.DownloadData(URL)
End Using
Catch ex As WebException
Data = File.ReadAllBytes(FAIL)
End Try
.Write(Convert.ToBase64String(Data))
End With
End Sub
End Class
Then I just put a little non-IE detection (using the classic document.all check) in order to call the correct URL/set the correct SRC:
function updateCam() {
var url = (document.all) ? "../snapshot.cgi?t=" : "../cam.axd?t=";
url += new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src;
if(document.all)
src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
else
src = xhr.responseText;
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
It's very unfortunate I had to resort to this workaround for. I hate browser detection code, and I hate the additional load that is put on my server. The proxy will not only force me to waste more bandwidth, but it will not operate as efficiently because of the inherent proxy drawbacks and due to the time required to base-64 encode the image. Additionally, it is not setup to degrade as gracefully as IE. Although I could re-write the proxy to use HttpWebRequest and return the proper status codes, etc. I just wanted the easiest way out as possible because I am sick of dealing with this!
Thanks to all!
I believe the jquery will try to interpret the response from the server. I believe some browsers are more tolerant of the response interpretation so more restrictive browsers will fail because an image cannot be seen as HTML!
The solution to this would be to use a HEAD request type instead of a GET ( type: "HEAD" ). That way you will still get status responses back, without grabbing the image itself. Therefore the response will be empty (and shouldn't mess you up). Also, the response should be much faster.

Categories