Override post requests - javascript

I have this code that I put in my console:
XMLHttpRequest.prototype.send = function(body) {
// modifies inputted request
newBody = JSON.parse(body);
newBody.points = 417;
// sends modified request
this.realSend(JSON.stringify(newBody));
}
It is supposed to make the points 417 every time it sends a request, but when I look at the request body, it still says the original amount of points. Any help?

Try to add an alert() or console.log() into your modified XMLHttpRequest.prototype.send to check if it actually works. There is a way to prevent this kind of modifications silently.

As others have noted, the error you are experiencing is hard to diagnose exactly without seeing how you created this.realSend.
However, this code will work:
const send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (body) {
const newBody = JSON.parse(body);
newBody.points = 417;
send.call(this, JSON.stringify(newBody));
};
Note that instead of storing the original send method on XMLHttpRequest.prototype, I've kept in a separate variable and simply invoked it with the correct this value through send.call(). This seems like a cleaner implementation with less chance for conflicts with other code.
See this codesandbox for a working example.

If your function is not being called, possible fetch is used to make ajax requests.
So you can wrap both functions, like this
const send = XMLHttpRequest.prototype.send;
const _fetch = window.fetch;
XMLHttpRequest.prototype.send = function (body) {
const newBody = JSON.parse(body);
newBody.points = 417;
send.call(this, JSON.stringify(newBody));
};
window.fetch = function(url, options){
let newBody;
if(options.body) {
newBody = JSON.parse(options.body);
newBody.points = 417;
options.body = JSON.stringify(newBody);
}
_fetch.call(this, url, options);
}

Related

Fetch vs Request

I'm consuming a JSON stream and am trying to use fetch to consume it. The stream emits some data every few seconds. Using fetch to consume the stream gives me access to the data only when the stream closes server side. For example:
var target; // the url.
var options = {
method: "POST",
body: bodyString,
}
var drain = function(response) {
// hit only when the stream is killed server side.
// response.body is always undefined. Can't use the reader it provides.
return response.text(); // or response.json();
};
var listenStream = fetch(target, options).then(drain).then(console.log).catch(console.log);
/*
returns a data to the console log with a 200 code only when the server stream has been killed.
*/
However, there have been several chunks of data already sent to the client.
Using a node inspired method in the browser like this works every single time an event is sent:
var request = require('request');
var JSONStream = require('JSONStream');
var es = require('event-stream');
request(options)
.pipe(JSONStream.parse('*'))
.pipe(es.map(function(message) { // Pipe catches each fully formed message.
console.log(message)
}));
What am I missing? My instinct tells me that fetch should be able to mimic the pipe or stream functionality.
response.body gives you access to the response as a stream. To read a stream:
fetch(url).then(response => {
const reader = response.body.getReader();
reader.read().then(function process(result) {
if (result.done) return;
console.log(`Received a ${result.value.length} byte chunk of data`);
return reader.read().then(process);
}).then(() => {
console.log('All done!');
});
});
Here's a working example of the above.
Fetch streams are more memory-efficient than XHR, as the full response doesn't buffer in memory, and result.value is a Uint8Array making it way more useful for binary data. If you want text, you can use TextDecoder:
fetch(url).then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder();
reader.read().then(function process(result) {
if (result.done) return;
const text = decoder.decode(result.value, {stream: true});
console.log(text);
return reader.read().then(process);
}).then(() => {
console.log('All done!');
});
});
Here's a working example of the above.
Soon TextDecoder will become a transform stream, allowing you to do response.body.pipeThrough(new TextDecoder()), which is much simpler and allows the browser to optimise.
As for your JSON case, streaming JSON parsers can be a little big and complicated. If you're in control of the data source, consider a format that's chunks of JSON separated by newlines. This is really easy to parse, and leans on the browser's JSON parser for most of the work. Here's a working demo, the benefits can be seen at slower connection speeds.
I've also written an intro to web streams, which includes their use from within a service worker. You may also be interested in a fun hack that uses JavaScript template literals to create streaming templates.
Turns out I could get XHR to work - which doesn't really answer the request vs. fetch question. It took a few tries and the right ordering of operations to get it right. Here's the abstracted code. #jaromanda was right.
var _tryXhr = function(target, data) {
console.log(target, data);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
console.log("state change.. state: "+ this.readyState);
console.log(this.responseText);
if (this.readyState === 4) {
// gets hit on completion.
}
if (this.readyState === 3) {
// gets hit on new event
}
};
xhr.open("POST", target);
xhr.setRequestHeader("cache-control", "no-cache");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
};

Firefox add-on get the DOM window which made an HTTP request

I'm capturing the HTTP requests in a Firefox Add-on SDK extension. I need to get the DOM window associated with the request. However, I'm getting an NS_NOINTERFACE error.
Here is my code:
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpRequest = subject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = subject.URI.host;
var domWin;
var assWindow;
console.log('URL: ', requestUrl);
try {
domWin = httpRequest.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
assWindow = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext)
.associatedWindow;
console.log(domWin);
} catch (e) {
console.log(e);
}
// console.log('TAB: ', tabsLib.getTabForWindow(domWin.top));
var hostName = wn.domWindow.getBrowser().selectedBrowser.contentWindow.location.host;
console.log('HOST: ', hostName);
},
get observerService() {
return Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
},
register: function () {
this.observerService.addObserver(this, 'http-on-modify-request', false);
},
unregister: function () {
this.observerService.removeObserver(this, 'http-on-modify-request');
}
};
httpRequestObserver.register();
I've tried both nsIDOMWindow and nsILoadContext, but NS_NOINTERFACE error always appears on an attempt to get the window object.
I have finally managed to get the data I need via
httpRequest.notificationCallbacks.getInterface(Ci.nsILoadContext).topFrameElement
For example, to get url of the document which started the request, I used
httpRequest.notificationCallbacks.getInterface(Ci.nsILoadContext).topFrameElement._documentURI.href
Since you already found how to get the <browser> from the request you can do the following to get back to SDK APIs:
let browser = ....topFrameElement
let xulTab = browser.ownerDocument.defaultView.gBrowser.getTabForBrowser(browser)
let sdkTab = modelFor(xulTab)
modelFor() is documented in the tabs module.

Request Stream Get + Post edited JSON body in Node.js

I'm new to Node.js and am working on a project and I'd like to use Request to stream from one endpoint to another. My goal is to use Request to get and post an edited JSON body using a pipe stream. I know that when doing so, content-type and content-length will be preserved in the POST headers. However, I would like to apply .forEach to all JSON objects in the body from the first url, and post them to the second url.
I'm not sure about the correct format, and I'd appreciate some clarification.
I know the basic syntax is this:
request.get('URL').pipe(request.post('URL'));
And so far my best guess is something like this:
request('FIRST_URL', function (error, response, body) {
body = JSON.parse(body);
body.forEach( function(arg) {
//return edited body
});
}).pipe(request.post('SECOND_URL'));
Am I missing something? Is there a better way to do this?
You could write your own transform stream. For example:
var Transform = require('stream').Transform;
var inherits = require('util').inherits;
function JSONTransform() {
Transform.call(this);
this._bufffer = '';
}
inherits(JSONTransform, Transform);
JSONTransform.prototype._transform = function(chunk, enc, cb) {
this._buffer += chunk;
cb();
});
JSONTransform.prototype._flush = function(cb) {
try {
var result = JSON.parse(this._buffer);
this._buffer = null;
// Do whatever transformations
// ...
this.push(JSON.stringify(result));
cb();
} catch (ex) {
cb(ex);
}
});
// Then just pipe
request.get('FIRST_URL')
.pipe(new JSONTransform())
.pipe(request.post('SECOND_URL'));
One other slightly different solution that may be worth considering would be to use a third-party streaming JSON parser module, which may or may not work for your use case.

Node.js - Asynchronous JSON Query

I apologize if this is a stupid question, but I am new to Javascript and Node.js really hurts my head because it is asynchronous.
My goal is to query for a JSON object from an API and be able to work with it. I have tried to look for questions and answers on what I should be doing but none of it really makes sense to me, so I am hoping to learn by just seeing proper code.
var request = require('request');
var url = 'url here';
var temp;
var done = false;
request(url, function (error, response, body) {
if (!error) {
temp = body;
done = true;
console.log(temp);
} else {
console.log(error);
}
});
if (done){
console.log(temp);
}
Can someone please walk me through the proper way to restructure my code?
The function you are creating with the line
request(url, function (error, response, body) {
is not executed until the response is received. The rest of your code continues to run. Think of the flow something like this:
var request = require('request');
var url = 'url here';
var temp;
var done = false;
request(url, XXX);
if (done){
console.log(temp);
then when the response is received (perhaps much later on) the function XXX is executed.
As you can see, done will always be false when the line
if (done){
is executed.

Catch Facebook Access token on demand, but how?

I build a Firefox Extension and i'm using the graph api. At the moment i catch the access token of each user while starting the browser like:
https://stackoverflow.com/questions/10301146/facebook-login-within-a-firefox-add-on
This works fine but kind of stupid, because nobody will use the extension in each firefox session. So what i'm trying to do is, catch the access token or more accurately call the methode Wladimir Palant recommends on demand. My code looks like this, while getAccessToken() is the mentioned method.
onLoad: function (){
var NoteHandler = window.arguments[0];
var sjcl = NoteHandler.sjcl;
NoteHandler.getAccessToken();
decryptionDialog.noteHandler = NoteHandler;
decryptionDialog.sjcl = sjcl;
var currID = decryptionDialog.getID();
if(currID==""){
window.close();
return false;
}else{
http_request = new XMLHttpRequest();
http_request.open('Get', 'https://graph.facebook.com/'+currID+'/notes?access_token='+NoteHandler.token, false);
http_request.overrideMimeType("text/json");
http_request.send(null);
decryptionDialog.value = decryptionDialog.ResponseToArray(http_request.responseText);
....
But the problem is while getAccessToken() is still waiting for the access token, the onLoad()-Method won't wait and goes on. Therefore the NoteHandler.token is null while the request is send. Does anyone have an idea, because i'm relatively new to javascript.
You should rewrite this code to be asynchronous - it shouldn't assume that getAccessToken() will get the result immediately, there should be rather a callback parameter, a function to be called when the operation is done (can be a closure function). Something along these lines:
onLoad: function (){
var NoteHandler = window.arguments[0];
var sjcl = NoteHandler.sjcl;
NoteHandler.getAccessToken(function()
{
decryptionDialog.noteHandler = NoteHandler;
decryptionDialog.sjcl = sjcl;
...
http_request.open('Get', 'https://graph.facebook.com/'+currID+'/notes?access_token='+NoteHandler.token, false);
...
});
}
...
getAccessToken: function(callback) {
...
// All done - call the callback
callback();
}

Categories

Resources