Making synchoronous XHR request with chrome.webRequest.onBeforeRequest - javascript

I'm looking to make a Chrome extension that hooks in to chrome.webRequest.onBeforeRequest to determine whether or not to block the current page request. As a result, I need to make a request to an API to determine it.
Is there a good way to make the checkUrl request synchronous to satisfy the requirements of chrome.webRequest.onBeforeRequest?
function checkUrl(url, callback) {
let api = 'http://localhost:9000/filter';
let data = {
url: url,
};
let json = JSON.stringify(data);
let xhr = new XMLHttpRequest();
xhr.open('POST', api, true);
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
xhr.setRequestHeader('X-Bark-Email', email);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.response);
}
}
xhr.send(json);
}
function onBeforeRequestHandler(details) {
let url = new URL(details.url);
console.log(details.type, ": ", url.host)
checkUrl(url, function(resp) {
let status = resp.status;
let redirectUrl = resp.redirect_url;
if (status == "allowed") {
return { cancel: false }; // <<<<< This doesn't work b/c of the callback
} else {
return { redirectUrl: redirectUrl };
}
});
}
chrome.webRequest.onBeforeRequest.addListener(onBeforeRequestHandler,
{
urls: ["<all_urls>"],
types: ["sub_frame", "main_frame", "xmlhttprequest"]
},
["blocking"]
);

I swapped:
xhr.open('POST', api, true);
for
xhr.open('POST', api, false);
and that makes the request synchronous. Then returned the result from the xhr request and use that inline:
return JSON.parse(xhr.response);

Related

How can i apply callback to get the http response in a method

I am attempting to write a method so that i pass the url and application name and it return the response. I read that I can apply callback to resolve this but I am not able to resolve the issue. Any help would be appreciated.
Please find below my code snippet.
var response = getResponse(url,applicationName)
console.log("response from getResponse \n" +response);
function getResponse(url,applicationName){
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
"application": applicationName
}));
xhr.onload = function() {
console.log(this.responseText);
}
return xhr.responseText;
}
You can use the onreadystatechange method to handle XHR responses, try this:
//XHR POST
const xhr = new XMLHttpRequest; // creates new object
const url = 'https://api-to-call.com/endpoint';
const data = JSON.stringify({"application": applicationName}); // converts data to a string
xhr.responseType = 'json';
xhr.onreadystatechange = () => {
if(xhr.readyState === XMLHttpRequest.DONE) {
return xhr.response;
}
}
xhr.open('POST', url); // opens request
xhr.send(data); // sends object
you should use promise instead of callback and do something like that.
const url = "https://httpbin.org/post";
const applicationName = "test";
getResponse(url, applicationName)
.then(response => {
//work here, not outside
console.log(response);
})
.catch(error => {
console.log(error);
})
function getResponse(url, applicationName) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
"application": applicationName
}));
xhr.onload = function() {
// print JSON response
if (xhr.status >= 200 && xhr.status < 300) { // if valid
// work here
const response = JSON.parse(xhr.response.replace(/"/g, '"'));
const data = JSON.parse(response.data.replace(/"/g, '"'));
resolve(data);
}
reject(xhr.response); // reject and return the response if not valid
}
})
}
If you want to learn more about asynchronous https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Concepts, I invite you to go to this website to learn a little more about the promise.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises
The callback is executed after the code returned xhr.responseText. So that means xhr.responseText returns null.
I would recommend using the fetch API opposed to the older XMLHttpRequest you are using now. The fetch API is basically a Promise based XMLHttpRequest.
Your function would look something like:
async function getResponse( url, applicationName ) {
const json = JSON.stringify({
"application": applicationName
});
return fetch( url, {method: 'POST', headers: { 'Content-Type':'application/json'}, body: json} );
}
// access like this
getResponse( url, applicationName)
.then( response => { console.log(response) });
async function someFunction( url, applicationName ) {
// or pause the code while the request is fetched by using await, note that you need to be in a function that is declared async to use this approach.
const response = await getResponse( url, applicationName );
}
Fetch documentation can be found at MDN: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Request to IP camera Javascript

i'm trying to make a request into an IP camera, but the camera needs Basic authentication, i need to get this request and show in an Iframe or img, but i don't know how to get that, i see how the request to the camera stays always waiting to finish an send some data, but i don't know how to get it and pass to the Iframe, thank's for any help.
Code Example:
function makeRequest(method, url, data) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.setRequestHeader(
"Authorization",
"Basic " + btoa("user:password")
);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText,
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText,
});
};
if (method == "POST" && data) {
xhr.send(data);
} else {
xhr.send();
}
});
}
//GET example
makeRequest("GET", "http://ip_camera_url").then(
function (data) {
var results = JSON.parse(data);
console.log(results);//Never come here
}
);
UPDATE:
First the request return status 200
then keeps sending data
but the request never ends and i can't get the result or the images the ip camera returns.
this is the message in the tab timing into the network option.

JS PayPal REST Error: MALFORMED_REQUEST

I try to integrate PayPal API to my app. When I try to make call to API in my script I got an error:
Incoming JSON request does not map to API request. This is the full object of error:
debug_id:"8280412cbada"
information_link:"https://developer.paypal.com/webapps/developer/docs/api/#MALFORMED_REQUEST"
message:"Incoming JSON request does not map to API request"
name:"MALFORMED_REQUEST"
But when I try to make call via EasyRest with the same parameters all is working OK.
This is the code which I used to make call:
function payPalStep3(gAccessToken, gPrice, gCurrency, gOrderNumber){ return new Promise((resolve, reject) => {
let newPayment = {
intent: 'sale',
redirect_urls: {
return_url: 'http://localhost:3000/success.html',
cancel_url: 'http://localhost:3000/reject.html'
},
payer: {
payment_method: 'paypal'
},
transactions: [{
amount: {
total: parseFloat(gPrice),
currency: gCurrency
}
}]
}
let req = new XMLHttpRequest();
let UrlReq = 'https://api.sandbox.paypal.com/v1/payments/payment';
req.open('POST', UrlReq, true);
req.setRequestHeader('Content-Type', 'application/json');
req.setRequestHeader('Authorization', 'Bearer '+gAccessToken);
req.onreadystatechange = function(){
if(req.readyState == 4){
let shopUserResponse = req.response;
shopUserResponse = JSON.parse(shopUserResponse);
resolve(shopUserResponse);
}
req.onerror = () => err(false);
}
req.send(newPayment) })}
Maybe somebody can help me, please.

JavaScript XMLHttpRequest with credentials to ASP.NET API

I am trying to do a post request withCredentials = true, but I get a CORS error on the console after sending the request.
This is the Controller I am trying to reach:
[RoutePrefix("Account")]
public class AccountController : ApiController;
This is the Action I am trying to reach:
[HttpPost]
[Route("Login")]
public IHttpActionResult Login(LoginDto dto);
I have added this line in WebApiConfig:
config.EnableCors(new EnableCorsAttribute("http://localhost", "*", "*"));
And here is what I use to do Post Requests with Javascript
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
if (xhr.withCredentials != undefined) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
function post(url, data) {
return new Promise(
function httpPromise (resolve, reject) {
var request = createCORSRequest("post", url);
if (request) {
request.setRequestHeader('Accept', 'application/json');
request.setRequestHeader('Content-Type', 'application/json');
request.onloadend = function (progress) {
var status = request.status;
var result = JSON.parse(request.response || "null");
if (status >= 200 && status < 300) resolve(result);
else reject(result ? result.Message || result : result);
};
request.send(data);
}
});
}
Below is the Error Message that appears in the console.
XMLHttpRequest cannot load http://localhost:54368/Account/Login. Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://localhost' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
You need to give specify SupportsCredentials = true in your config.EnableCors(…) call:
config.EnableCors(new EnableCorsAttribute("http://localhost", "*", "*")
{ SupportsCredentials = true });

Pure JavaScript Send POST Data Without a Form

Is there a way to send data using the POST method without a form and without refreshing the page using only pure JavaScript (not jQuery $.post())? Maybe httprequest or something else (just can't find it now)?
You can send it and insert the data to the body:
var xhr = new XMLHttpRequest();
xhr.open("POST", yourUrl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
value: value
}));
By the way, for get request:
var xhr = new XMLHttpRequest();
// we defined the xhr
xhr.onreadystatechange = function () {
if (this.readyState != 4) return;
if (this.status == 200) {
var data = JSON.parse(this.responseText);
// we get the returned data
}
// end of state change: it can be after some time (async)
};
xhr.open('GET', yourUrl, true);
xhr.send();
The Fetch API is intended to make GET requests easy, but it is able to POST as well.
let data = {element: "barium"};
fetch("/post/data/here", {
method: "POST",
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).then(res => {
console.log("Request complete! response:", res);
});
If you are as lazy as me (or just prefer a shortcut/helper):
window.post = function(url, data) {
return fetch(url, {method: "POST", headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)});
}
// ...
post("post/data/here", {element: "osmium"});
You can use the XMLHttpRequest object as follows:
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.send(someStuff);
That code would post someStuff to url. Just make sure that when you create your XMLHttpRequest object, it will be cross-browser compatible. There are endless examples out there of how to do that.
Also, RESTful lets you get data back from a POST request.
JS (put in static/hello.html to serve via Python):
<html><head><meta charset="utf-8"/></head><body>
Hello.
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "/postman", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
value: 'value'
}));
xhr.onload = function() {
console.log("HELLO")
console.log(this.responseText);
var data = JSON.parse(this.responseText);
console.log(data);
}
</script></body></html>
Python server (for testing):
import time, threading, socket, SocketServer, BaseHTTPServer
import os, traceback, sys, json
log_lock = threading.Lock()
log_next_thread_id = 0
# Local log functiondef
def Log(module, msg):
with log_lock:
thread = threading.current_thread().__name__
msg = "%s %s: %s" % (module, thread, msg)
sys.stderr.write(msg + '\n')
def Log_Traceback():
t = traceback.format_exc().strip('\n').split('\n')
if ', in ' in t[-3]:
t[-3] = t[-3].replace(', in','\n***\n*** In') + '(...):'
t[-2] += '\n***'
err = '\n*** '.join(t[-3:]).replace('"','').replace(' File ', '')
err = err.replace(', line',':')
Log("Traceback", '\n'.join(t[:-3]) + '\n\n\n***\n*** ' + err + '\n***\n\n')
os._exit(4)
def Set_Thread_Label(s):
global log_next_thread_id
with log_lock:
threading.current_thread().__name__ = "%d%s" \
% (log_next_thread_id, s)
log_next_thread_id += 1
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
Set_Thread_Label(self.path + "[get]")
try:
Log("HTTP", "PATH='%s'" % self.path)
with open('static' + self.path) as f:
data = f.read()
Log("Static", "DATA='%s'" % data)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(data)
except:
Log_Traceback()
def do_POST(self):
Set_Thread_Label(self.path + "[post]")
try:
length = int(self.headers.getheader('content-length'))
req = self.rfile.read(length)
Log("HTTP", "PATH='%s'" % self.path)
Log("URL", "request data = %s" % req)
req = json.loads(req)
response = {'req': req}
response = json.dumps(response)
Log("URL", "response data = %s" % response)
self.send_response(200)
self.send_header("Content-type", "application/json")
self.send_header("content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
except:
Log_Traceback()
# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)
# Launch 100 listener threads.
class Thread(threading.Thread):
def __init__(self, i):
threading.Thread.__init__(self)
self.i = i
self.daemon = True
self.start()
def run(self):
httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)
# Prevent the HTTP server from re-binding every handler.
# https://stackoverflow.com/questions/46210672/
httpd.socket = sock
httpd.server_bind = self.server_close = lambda self: None
httpd.serve_forever()
[Thread(i) for i in range(10)]
time.sleep(9e9)
Console log (chrome):
HELLO
hello.html:14 {"req": {"value": "value"}}
hello.html:16
{req: {…}}
req
:
{value: "value"}
__proto__
:
Object
Console log (firefox):
GET
http://XXXXX:8000/hello.html [HTTP/1.0 200 OK 0ms]
POST
XHR
http://XXXXX:8000/postman [HTTP/1.0 200 OK 0ms]
HELLO hello.html:13:3
{"req": {"value": "value"}} hello.html:14:3
Object { req: Object }
Console log (Edge):
HTML1300: Navigation occurred.
hello.html
HTML1527: DOCTYPE expected. Consider adding a valid HTML5 doctype: "<!DOCTYPE html>".
hello.html (1,1)
Current window: XXXXX/hello.html
HELLO
hello.html (13,3)
{"req": {"value": "value"}}
hello.html (14,3)
[object Object]
hello.html (16,3)
{
[functions]: ,
__proto__: { },
req: {
[functions]: ,
__proto__: { },
value: "value"
}
}
Python log:
HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}
You can use XMLHttpRequest, fetch API, ...
If you want to use XMLHttpRequest you can do the following
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
name: "Deska",
email: "deska#gmail.com",
phone: "342234553"
}));
xhr.onload = function() {
var data = JSON.parse(this.responseText);
console.log(data);
};
Or if you want to use fetch API
fetch(url, {
method:"POST",
body: JSON.stringify({
name: "Deska",
email: "deska#gmail.com",
phone: "342234553"
})
}).then(result => {
// do something with the result
console.log("Completed with result:", result);
}).catch(err => {
// if any error occured, then catch it here
console.error(err);
});
There is an easy method to wrap your data and send it to server as if you were sending an HTML form using POST.
you can do that using FormData object as following:
data = new FormData()
data.set('Foo',1)
data.set('Bar','boo')
let request = new XMLHttpRequest();
request.open("POST", 'some_url/', true);
request.send(data)
now you can handle the data on the server-side just like the way you deal with reugular HTML Forms.
Additional Info
It is advised that you must not set Content-Type header when sending FormData since the browser will take care of that.
Did you know that JavaScript has it's built-in methods and libs to create forms and submit them?
I am seeing a lot of replies here all asking to use a 3rd party library which I think is an overkill.
I would do the following in pure Javascript:
<script>
function launchMyForm()
{
var myForm = document.createElement("FORM");
myForm.setAttribute("id","TestForm");
document.body.appendChild(myForm);
// this will create a new FORM which is mapped to the Java Object of myForm, with an id of TestForm. Equivalent to: <form id="TestForm"></form>
var myInput = document.createElement("INPUT");
myInput.setAttribute("id","MyInput");
myInput.setAttribute("type","text");
myInput.setAttribute("value","Heider");
document.getElementById("TestForm").appendChild(myInput);
// To submit the form:
myForm.method = "POST";
myForm.action = "whatever.aspx"; // or "response.php"
myForm.submit();
// This will create an INPUT equivalent to: <INPUT id="MyInput" type="text" value="Heider" /> and then assign it to be inside the TestForm tags.
}
</script>
This way (A) you don't need to rely on 3rd parties to do the job. (B) It's all built-in to all browsers, (C) faster, (D) it works, feel free to try it out.
I hope this helps.
H
navigator.sendBeacon()
If you simply need to POST data and do not require a response from the server, the shortest solution would be to use navigator.sendBeacon():
const data = JSON.stringify({
example_1: 123,
example_2: 'Hello, world!',
});
navigator.sendBeacon('example.php', data);
The most popular answers here do not show how to get data back from the POST. Also, the popular "fetch" solutions do not work in the latest version of Chrome when sending data to the latest version of NodeJS unless you pass headers and also unwrap the response.json() promise. Also, the popular answers do not use async/await.
Here is the cleanest and most complete solution I could come up with that works.
async function postJsonData(jsonObject) {
const response = await fetch("/echo", {
method: "POST",
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(jsonObject)
});
const actualResponse = await response.json();
}
Here is a nice function you (or anyone else) could use in their code:
function post(url, data) {
return new Promise((res, rej) => {
let stringified = "";
for (const [key, value] of Object.entries(data))
stringified += `${stringified != '' ? '&' : ''}${key}=${value}`
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState == 4)
if (xhr.status == 200)
res(xhr.responseText)
else
rej({ code: xhr.status, text: xhr.responseText })
}
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(stringified);
})
}
const data = { username: 'example' };
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
' Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
You can also use this: https://github.com/floscodes/JS/blob/master/Requests.js
You can easily send a http-Request. Just use:
HttpRequest("https://example.com", method="post", data="yourkey=yourdata");
That's it! It should even work if the site is CSRF-protected.
Or just send a GET-Request by using
HttpRequest("https://example.com", method="get");
use this func of jbezz library
var makeHttpObject = function () {
try {return new XMLHttpRequest();}
catch (error) {}
try {return new ActiveXObject("Msxml2.XMLHTTP");}
catch (error) {}
try {return new ActiveXObject("Microsoft.XMLHTTP");}
catch (error) {}
throw new Error("Could not create HTTP request object.");
}
function SendData(data){
let type = (data.type ? data.type : "GET")
let DataS = data.data;
let url = data.url;
let func = (data.success ? data.success : function(){})
let funcE =(data.error ? data.error : function(){})
let a_syne = (data.asyne ? data.asyne : false);
let u = null;
try{u = new URLSearchParams(DataS).toString();}catch(e){u = Object.keys(DataS).map(function(k) {return encodeURIComponent(k) + '=' + encodeURIComponent(DataS[k])}).join('&')}
if(type == "GET"){url +="?"+u}
const xhttp = makeHttpObject();
xhttp.onload = function(){func(this.responseText)}
xmlHttp.onreadystatechange = function() {if (xmlHttp.readyState == 4)
{if(xmlHttp.status !== 200){funcE(xmlHttp.statusText)}}}
xhttp.open(type,url,a_syne);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(u);
}
use this to run :
SendData({
url:"YOUR_URL",
asyne:true,
type:"POST", // or GET
data:{
username:"ali",
password:"mypass" // Your Data
},
success:function(Result){
console.log(Result)
},
error:function(e){
console.log("We Have Some Error")
}
});
Or
download jbezz and add to your page.
download link : github.com
use :
$$.api({
url:"YOUR_URL",
asyne:true,
type:"POST", // or GET
data:{
username:"ali",
password:"mypass" // Your Data
},
success:function(Result){
console.log(Result)
},
error:function(e){
console.log("We Have Some Error")
}
});

Categories