read/write Google Spreadsheet cell feed with Javascript - javascript

I try to read and write a cell in google spreadsheet with http request by javascript. The "read" operation works, but the "write" operation fail.
Please help to point out which part I should modify in my code of "write" operation.
The write example I followed is from here https://developers.google.com/google-apps/spreadsheets/,
and it is not working.
My read operation (this is working):
http_request.onreadystatechange = function() {
process_cellrw(http_request);
};
http_request.open('GET',"https://spreadsheets.google.com/feeds/cells/0Aqed....RHdGc/od6/private/full/R1C1", true);
http_request.setRequestHeader('Authorization','Bearer ' + strAccessToken);
http_request.send(null);
My write operation (this is not working):
var testxml = ['<entry xmlns="http://www.w3.org/2005/Atom" <br>
xmlns:gs="http://schemas.google.com/spreadsheets/2006">',<br>
'<id>https://spreadsheets.google.com/feeds/cells/0Aqed....RHdGc/od6/private/full/R1C1</id>',<br>
'<link rel="edit" type="application/atom+xml"<br> href="https://spreadsheets.google.com/feeds/cells/0Aqed....RHdGc/od6/private/full/R1C2/9zlgi"/>',<br>
'<gs:cell row="1" col="1" inputValue="xxxx"/>',<br>
'</entry>'].join('');<br>
http_request.onreadystatechange = function() {
process_cellrw();
};
http_request.open('PUT',"https://spreadsheets.google.com/feeds/cells/0Aqed....RHdGc/od6/private/full/R1C2/9zlgi");
http_request.setRequestHeader('Authorization','Bearer ' + strAccessToken);
http_request.setRequestHeader('GData-Version','3.0');
http_request.setRequestHeader('Content-Type', 'application/atom+xml');
http_request.setRequestHeader('If-Match','*');
http_request.setRequestHeader('Content-Length', testxml.length.toString());
http_request.send(testxml);
The write operation always receive http_request.status = 0 at callback function process_cellrw().
My environment is Windows 7 + Chrome browser. I also tested it on Android + Webkit, still fails.
I also tested to add a row by list feed, also fails by receive http_request.status = 0.

I know this doesn't answer your question, but I would open up the Chrome "Developer Tools", go to "Network" and inspect the response from google for the API call. It may contain headers that explain what failed...

I found the root cause : cross domain XMLHttpRequest POST/PUT are not support by docs.googole.com and spreadsheets.google.com
The XMLHttpRequest POST/PUT will first send a HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. But docs.googole.com and preadsheets.google.com always reply "404 Not Found" for this request. That's why I always received http_request.status = 0 at callback function process_cellrw().
One solution is to use another CGI which allows cross domain HTTP request, such as PHP.
Another solution is to implement the write operation with the function UrlFetchApp to send HTTP PUT request in Google Apps Script, and then we can use XMLHttpRequest GET to trigger this Apps Script.

Related

How to call browser function with URL/URI local to the client?

I want to call a browser function, e.g. AddSearchProvider(engineURL), which requires an URL to a XML-file. However, I want the user to generate the content of the XML-file himself, thus I want to call the function by passing (a reference to) the user generated content directly. It is key that all of this happens client-side only, such that no server is required to temporarily host files in the process.
I tried to encode the XML file into the URI:
uri = "data:application/xml;charset=utf-8," + encodeURIComponent($('#edit-search-engine').val());
window.external.AddSearchProvider(uri);
But Firefox (57.0) rejects this approach with the following message:
I guess¹ Firefox expects a "true", remote, URL. How can I realize the above functionality without a server in the loop?
¹Update: Firefox is indeed enforcing the URL to be of HTTP, HTTPS or FTP:
[...]
// Make sure the URLs are HTTP, HTTPS, or FTP.
let isWeb = ["https", "http", "ftp"];
if (isWeb.indexOf(engineURL.scheme) < 0)
throw "Unsupported search engine URL: " + engineURL;
if (iconURL && isWeb.indexOf(iconURL.scheme) < 0)
throw "Unsupported search icon URL: " + iconURL;
[...]

ajax call to localhost from site loaded over https fails in chrome

-------------------- UPDATE 2 ------------------------
I see now that what I am trying to accomplish is not possible with chrome. But I am still curios, why is the policy set stricter with chrome than for example Firefox? Or is it perhaps that firefox doesn't actually make the call either, but javascript-wise it deems the call failed instead of all together blocked?
---------------- UPDATE 1 ----------------------
The issue indeed seems to be regarding calling http from https-site, this error is produced in the chrome console:
Mixed Content: The page at 'https://login.mysite.com/mp/quickstore1' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://localhost/biztv_local/video/video_check.php?video=253d01cb490c1cbaaa2b7dc031eaa9f5.mov&fullscreen=on'. This request has been blocked; the content must be served over HTTPS.
Then the question is why Firefox allows it, and whether there is a way to make chrome allow it. It has indeed worked fine until just a few months ago.
Original question:
I have some jQuery making an ajax call to http (site making the call is loaded over https).
Moreover, the call from my https site is to a script on the localhost on the clients machine, but the file starts with the
<?php header('Access-Control-Allow-Origin: *'); ?>
So that's fine. Peculiar setup you might say but the client is actually a mediaplayer.
It has always worked fine before, and still works fine in firefox, but since about two months back it isn't working in chrome.
Has there been a revision to policies in chrome regarding this type of call? Or is there an error in my code below that firefox manages to parse but chrome doesn't?
The error only occurs when the file is NOT present on the localhost (ie if a regular web user goes to this site with their own browser, naturally they won't have the file on their localhost, most won't even have a localhost) so one theory might be that since the file isn't there, the Access-Control-Allow-Origin: * is never encountered and therefore the call in its entirety is deemed insecure or not allowed by chrome, therefore it is never completed?
If so, is there an event handler I can attach to my jQuery.ajax method to catch that outcome instead? As of now, complete is never run if the file on localhost isn't there.
before : function( self ) {
var myself = this;
var data = self.slides[self.nextSlide-1].data;
var html = myself.getHtml(data);
$('#module_'+self.moduleId+'-slide_'+self.slideToCreate).html(html);
//This is the fullscreen-always version of the video template
var fullscreen = 'on';
//console.log('runnin beforeSlide method for a video template');
var videoCallStringBase = "http://localhost/biztv_local/video/video_check.php?"; //to call mediaplayers localhost
var videoContent='video='+data['filename_machine']+'&fullscreen='+fullscreen;
var videoCallString = videoCallStringBase + videoContent;
//TODO: works when file video_check.php is found, but if it isn't, it will wait for a video to play. It should skip then as well...
//UPDATE: Isn't this fixed already? Debug once env. is set up
console.log('checking for '+videoCallString);
jQuery.ajax({
url: videoCallString,
success: function(result) {
//...if it isn't, we can't playback the video so skip next slide
if (result != 1) {
console.log('found no video_check on localhost so skip slide '+self.nextSlide);
self.skip();
}
else {
//success, proceed as normal
self.beforeComplete();
}
},
complete: function(xhr, data) {
if (xhr.status != 200) {
//we could not find the check-video file on localhost so skip next slide
console.log('found no video_check on localhost so skip slide '+self.nextSlide);
self.skip();
}
else {
//success, proceed as normal
self.beforeComplete();
}
}, //above would cause a double-slide-skip, I think. Removed for now, that should be trapped by the fail clause anyways.
async: true
});

Firefox Extension : Stopping the page load when suspicious url found

I am working on a simple firefox extension that tracks the url requested and call a web service at the background which detects whether the URL is suspicious or not and based on the result returned by the service, extension decides to stop the page load and alert the user about the case of forgery or whatever, and if user still wishes to go to that page he can get redirected to the original page he has requested for
I have added a http-on-modify-request observer
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(requestObserverListener.observe, "http-on-modify-request", false);
and the observer
var requestObserverListener = {observe: function (subject, topic, data) {
//alert("Inside observe");
if (topic == "http-on-modify-request") {
subject.QueryInterface(Components.interfaces.nsIHttpChannel);
var url = subject.URI.spec; //url being requested. you might want this for something else
//alert("inside modify request");
var urlbarvalue = document.getElementById("urlbar").value;
urlbarvalue = processUrl(urlbarvalue, url);
//alert("url bar: "+urlbarvalue);
//alert("url: "+url);
document.getElementById("urlbar").style.backgroundColor = "white";
if(urlbarvalue == url && url != "")
{
var browser = getWindowForRequest(subject);
if (browser != null) {
//alert(""+browser.contentDocument.body.innerHTML);
alert("inside browser: "+url);
getXmlHttpRequest(url);
}
}
}
},
}
so when the URL in the URLbar and the requested url matches REST service will be called through ajax getXmlHttpRequest(url); method
now when i am running this extension call is made to the service but before the service return any response the page gets loaded which is not appropriate because user might enter his credentials in the meanwhile and get compromised
I want to first display user a warning message on the browser tab and if he still wanted to visit to that page he can then be redirected to that page on a link click in warning message window
I haven't tried this code out so I'm not sure that suspend and resume will work well but here's what I would try. You're working with an nsIRequest object as your subject so you can call subject.suspend() on it. From there use callbacks to your XHR call to either cancel() or resume() the nsIRequest.
Here's the relevant (untested) snippet of code. My XHR assumes some kind of promise .the() return but hopefully you understand the intention:
if(urlbarvalue == url && url != "")
{
var browser = getWindowForRequest(subject);
if (browser != null) {
// suspend the pending request
subject.suspend();
getXmlHttpRequest(url).then(
function success() { subject.resume(); },
function failure() { subject.cancel(Components.results.NS_BINDING_ABORTED); });
}
}
Just some fair warning that you actually don't want to implement an add-on in this way.
It's going to be extremely slow to do a remote call for every HTTP request. The safe browsing module does a single call to download a database of sites considered 'unsafe', it then can quickly check the database against the HTTP request page such that it doesn't have to make individual calls every time.
Here's some more info on this kind of intercepting worth reading: https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Intercepting_Page_Loads#HTTP_Observers
Also I'd worry that your XHR request will actually loop because XHR calls creates an http-on-modify-request event so your code might actually check that your XHR request is valid before being able to check the current URL. You probably want a safety check for your URL checking domain.
And here's another stackoverflow similar question to yours that might be useful: How to block HTTP request on a particular tab?
Good luck!

The request is too large for IE to process properly

I am using Websync3, Javascript API, and subscribing to approximately 9 different channels on one page. Firefox and Chrome have no problems, but IE9 is throwing an alert error stating The request is too large for IE to process properly.
Unfortunately the internet has little to no information on this. So does anyone have any clues as to how to remedy this?
var client = fm.websync.client;
client.initialize({
key: '********-****-****-****-************'
});
client.connect({
autoDisconnect: true,
onStreamFailure: function(args){
alert("Stream failure");
},
stayConnected: true
});
client.subscribe({
channel: '/channel',
onSuccess: function(args) {
alert("Successfully connected to stream");
},
onFailure: function(args){
alert("Failed to connect to stream");
},
onSubscribersChange: function(args) {
var change = args.change;
for (var i = 0; i < change.clients.length; i++) {
var changeClient = change.clients[i];
// If someone subscribes to the channel
if(change.type == 'subscribe') {
// If something unsubscribes to the channel
}else{
}
}
},
onReceive: function(args){
text = args.data.text;
text = text.split("=");
text = text[1];
if(text != "status" && text != "dummytext"){
//receiveUpdates(id, serial_number, args.data.text);
var update = eval('(' + args.data.text + ')');
}
}
});
This error occurs when WebSync is using the JSON-P protocol for transfers. This is mostly just for IE, cross domain environments. Meaning websync is on a different domain than your webpage is being served from. So IE doesn't want do make regular XHR requests for security reasons.
JSON-P basically encodes the up-stream data (your 9 channel subscriptions) as a URL encoded string that is tacked onto a regular request to the server. The server is supposed to interpret that URL-encoded string and send back the response as a JavaScript block that gets executed by the page.
This works fine, except that IE also has a limit on the overall request URL for an HTTP request of roughly 2kb. So if you pack too much into a single request to WebSync you might exceed this 2kb upstream limit.
The easiest solution is to either split up your WebSync requests into small pieces (ie: subscribe to only a few channels at a time in JavaScript), or to subscribe to one "master channel" and then program a WebSync BeforeSubscribe event that watches for that channel and re-writes the subscription channel list.
I suspect because you have a key in you example source above, you are using WebSync On-Demand? If that's the case, the only way to make a BeforeSubscribe event handler is to create a WebSync proxy.
So for the moment, since everyone else is stumped by this question as well, I put a trap in my PHP to not even load this Javascript script if the browser is Internet Destroyer (uhh, I mean Internet Explorer). Maybe a solution will come in the future though.

XDomainRequest POST with XML...what am I doing wrong?

This is (hopefully) an easy question. I have to submit a request to a web service via POST with XDomainRequest. I have found sparse documentation for this across the internet, but I refuse to believe that nobody has figured this out.
Here is my XDomainRequest code:
var testURL = 'http://localhost:4989/testendpoint';
//let us check to see if the browser is ie. If it is not, let's
if ($.browser.msie && window.XDomainRequest) {
var xdr2 = new XDomainRequest();
xdr2.open("POST", testURL);
xdr2.timeout = 5000;
xdr2.onerror = function () {
alert('we had an error!');
}
xdr2.onprogress = function () {
alert('we have some progress!');
};
xdr2.onload = function () {
alert('we load the xdr!');
var xml2 = new ActiveXObject("Microsoft.XMLDOM");
xml2.async = true;
xml2.loadXML(xdr2.responseText);
};
//what form should my request take to be sending a string for a POST request?
xdr2.send("thisisastring");
}
My web service (WCF) takes a single parameter according to the web service's help page, that looks like this:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">String content</string>
I've gotten this to work via other http clients (mobile and desktop APIs, fiddler) by building a string that concatenates the parameter I am trying to pass to the web service with the rest of the string serialization. For example, I have tried:
xdr2.send("thisisastring");
xdr2.send("<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">thisisastring</string>");
but the onerror handler is always tripped. I don't think it has anything to do with the WCF because:
The WCF is always successful in every other client I call it from,
and
If it was the service, the onerror method would never get tripped.
It would return garbage, but it would be returning something.
When i use the console (in the dev tools in ie9) to log the responseText, it says:
LOG:undefined
So I am fairly sure that the issue is in how I use the XDomainRequest.
If anybody comes across this, I ended up converting my web services to return JSON-formatted data. Using JSON negates the need for XDomainRequest, allowing me to use the conventional ajax jquery tools instead.

Categories