Python Tornado: how do I set WebSocket headers? - javascript

I'm new to web development so let me explain:
I want my Python Tornado server to communicate with a web page. My web page uses WebSockets and the onmessage function to print what it should receive from the Tornado server. Basically, here is the HTML JavaScript part:
$(document).ready(function() {
var myURL = "http://localhost:8888";
var source = new EventSource(myURL, { withCredentials: true }); // Access-Control-Allow-Origin
...
source.onmessage = function(event) {
console.log("received new event!");
};
...
}); // ready()
I'm setting the withCredentials parameter to true so CORS are enabled.
On the Tornado side, I have a WebSocket class which is supposed to answer back, but I don't know how to set the header to have Access-Control-Allow-Origin enabled. Here is the tornado code:
class EchoWebSocket(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def on_message(self, message):
self.write_message(u"Received message: " + message)
def make_app():
return tornado.web.Application([ ('/', EchoWebSocket), ])
if __name__ == '__main__':
app = make_app()
app.listen(8888)
print 'listening on port 8888...'
# start main loop
tornado.ioloop.IOLoop.current().start()
I'm stuck with the following error in my browser!
GET http://localhost:8888/ [HTTP/1.1 400 Bad Request 1ms]
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8888/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
What am I missing???

Your javascript is using EventSource but your server is serving WebSockets. These are two completely different things. You need to change one of those to match the other.

Related

How to bypass CORS policy when sending get/post request from React JS?

From my React JS app , I need to fetch data from servers in other domains.
However, I am prevented by CORS policy and not able to fetch the data.
Let us assume that my React app is running on localhost:3000 during the development.
I want to make get/post call to another server running on http://myserver.com
The URL through which I want to fetch the data is http://ext-server.com/data/records?name=xyz
I have installed http-proxy-middleware thru npm and using it in my react app.
Created a setupProxy.js file under src folder with below content :
const { createProxyMiddleware} = require("http-proxy-middleware")
module.exports = app => {
app.use(
createProxyMiddleware('/data/records' , {
target:'http://ext-server.com',
changeOrigin: true
})
)
}
On the landing page of my react app (firstpage.js) when http://localhost:3000 is hit , I have added below piece of code to the button event that makes the get call to the http://ext-server.com
getTheData() {
let url = "http://ext-server.com/data/records?name=" + encodeURIComponent(this.state.name);
axios.get(url,
{
headers: {
"Content-Type":"application/json;charset=UTL-8",
"Access-Control-Allow-Origin": "*",
Accept: "application/json",
},
baseURL: 'http://ext-server.com'
}
).then((response) => {
console.log(response["access_token"]);
}).catch(error) => {
console.log("Error: ", error)
}).then(function () {
console.log("always call it")
});
}
In the package.json , I have added :
"proxy": "http://ext-server.com",
"homepage":"http://localhost:3000",
But I am still getting below error:
Access to XMLHttpRequest at 'http://ext-server.com/data/records?name= ' from origin 'http://localhost:3000' has been blocked by CORS policy.
Is there anything that I am missing here ? what is the correct way to use this http-proxy-middleware?
Any help will be very useful!
Thanks
As you can see from MDN the "Access-Control-Allow-Origin": "*" header is a response type header, this means that it should go to in your server response. Also I advise you to not use the * symbol, instead I would rather match it with the origin header in your Request.
The CORS policy is one and only administered by the web server and its settings. To allow CORS requests it has to be implemented on server side. No chance to do it from your client application.
Basically its just a header setting (below example for NodeJS):
res.header("Access-Control-Allow-Origin", "*")
Sending that header will allow requests from every domain.

building a local web server and respond data to javascript

I am trying to learn to build a web application, and that application needs data generated from a python script. After googling around. I found this link and it seems that I need to:
write a server side application in Python. Define a URL(route) that runs your script.
in my Javascript code, make an HTTP request to the URL defined in Step 1.
In my java script, I have the following ajax call, I'm not too sure what goes in the url field:
$.ajax({
type: "get",
url: "http://localhost:5000",
cache: false,
async: "asynchronous",
dataType: "text",
success: function (data) {
//console.log(JSON.stringify(data));
console.log("---->" + data);
},
error: function (request, status, error) {
console.log("Error: " + error);
},
});
As for my web server side, I wanted to write it from sockets since I want to learn some socket programing as well, so following another post I wrote my server below, in this server, my goal is to just return a simple string to prove that this works, but ultimately I want to be able to return a json object :
import socket
import threading
import json
import pdb
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 5000))
sock.listen(1)
print("Listening at------>>> ", sock.getsockname())
connections = []
# Reply as HTTP/1.1 server, saying "HTTP OK" (code 200).
response_proto = 'HTTP/1.1'
response_status = '200'
response_status_text = 'OK' # this can be random
res_status = "{} {} {}".format(response_proto, response_status,
response_status_text)
response_body_raw = "hello world"
# Clearly state that connection will be closed after this response,
# and specify length of response body
response_headers = {
'Content-Type': 'text; encoding=utf8',
'Content-Length': len(response_body_raw),
'Connection': 'close',
}
response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in
response_headers.items())
def handler(c, a):
global connections
while True:
data = c.recv(1024)
print(data)
for connection in connections:
# sending all this stuff
connection.sendall(res_status.encode('utf-8'))
connection.sendall('\n'.encode('utf-8'))
connection.sendall(response_headers_raw.encode('utf-8'))
# to separate headers from body
connection.sendall('\n'.encode('utf-8'))
connection.sendall(response_body_raw.encode('utf-8'))
if not data:
connections.remove(c)
c.close()
break
while True:
c, a = sock.accept()
print("Connected by------->>>", a)
cThread = threading.Thread(target=handler, args=(c, a))
cThread.daemon = True
cThread.start()
connections.append(c)
when I run my website using VS code live server extension, I get the following errors:
Access to XMLHttpRequest at 'http://localhost:5000/?_=1586356660223' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
GET http://localhost:5000/?_=1586356660223 net::ERR_FAILED
I looked into the No 'Access-Control-Allow-Origin' error, and it seems that I cannot provide url as localhost in my ajax call. if not, then what should I put in the url field if I want to talk to my local server?
Add a Access-Control-Allow-Origin to your response header:
response_headers = {
'Access-Control-Allow-Origin': '*',
...
}
So, as already mentioned in my Comment, I used a Flask server to process the POST-Data sent with Ajax.
Basically, you can set up the server like this:
from flask import Flask, requests
app = Flask(__name__)
#app.route("/", methods=['POST', 'GET'])
def main_page():
return "200"
if __name__ == "__main__":
app.run(debug=True, host='192.169.178.62')
with the host='192.169.178.62', you can specify the IP you want to run your Flask app.
I would suggest you find out your Computers IP, and either use that one to run Flask or use an IP in the same network.
In your AJAX, you need to enter this URL to send the request to.
If anything is not working as it should, feel free to contact me.

Access to IBM Weather API with PHP works, but with JS it does not work

I access to IBM Weather API in my application.
When I try to access with PHP:
$auth = base64_encode("<username>:<password>");
$context = stream_context_create([
"http" => [
"header" => "Authorization: Basic $auth"
]]);
$homepage = file_get_contents("https://twcservice.eu-gb.mybluemix.net/api/weather/v1/geocode/49.14/15.00/forecast/daily/3day.json?language=en-US&units=m", false, $context );
echo($homepage);
It works.
But when I try to access with Javascript:
let headers = new Headers();
headers.append("Content-Type", "application/json");
headers.append("Authorization", "Basic " + btoa("<username>" + ":" + "<password>"));
fetch("https://twcservice.eu-gb.mybluemix.net/api/weather/v1/geocode/"+lat.toFixed(2)+"/"+lng.toFixed(2)+"/forecast/daily/3day.json?language=en-US&units=m", {headers: headers})
.then(function(response) {
console.log(response);
return response.json();
})
.then(function(json) {
for(let i = 0; i <= 3; i++) {
console.log(json['forecasts'][i]['dow']+" - "+json['forecasts'][i]['narrative']);
}
});
It gives me the CORS error message.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://twcservice.eu-gb.mybluemix.net/api/weather/v1/geocode/49.14/15.00/forecast/daily/3day.json?language=en-US&units=m. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘https://*.ibm.com, https://*.ibmcloud.com’).
I don't understand why.
Thanks for help!
If the IBM Weather API is scared about stealing its content, why does it work with PHP?
I don't get it.
#John Doe
This is CORS issue. Servers can be configured to not allow browsers to make requests from different domains. The Mozilla document about CORS is a great read if you're unfamiliar with the topic.
Note that you'll only hit CORS errors if you're doing something through a browser. So attempting to redo the same API call in a terminal with curl will often still work. Making things even more confusing!
Was your PHP script run locally, through a terminal?
If you're tinkering around, there are proxy services that bypass CORS, like CORS-anywhere. Try hitting https://cors-anywhere.herokuapp.com/https://twcservice.eu-gb.mybluemix.net instead of the API you currently have. Note that this isn't meant for anything production worthy. Just trying to help you get a little farther along.

Connect from Zendesk(javascript) to Acumatica(IIS)

I am trying to connect from Javascript to Acumatica with following code:
var xmlhttp = new XMLHttpRequest();
URL = "h ttps://demo.mytestwebsite.com/entity/auth/login/";
xmlhttp.open("POST", URL, false);
xmlhttp.setRequestHeader("Authorization", "Basic " + btoa("Admin:hgfjk"));
xmlhttp.send();
And getting error:
VM2372:7 OPTIONS https ://demo.mytestwebsite.com/entity/auth/login/ 405 (Method Not Allowed)
connect # VM2372:7
(anonymous) # VM2374:1
VM2372:7 XMLHttpRequest cannot load http s://demo.mytestwebsite.com/entity/auth/login/. Response for preflight has invalid HTTP status code 405
connect # VM2372:7
(anonymous) # VM2374:1
VM2372:7 Uncaught DOMException: Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'http s://demo.mytestwebsite.com/entity/auth/login/'.
at connect (:7:15)
at :1:1
This issue is caused by CORS, i.e. the web browser does not get the necessary response from IIS hosting Acumatica, to satisfy CORS. CORS is a mechanism of increasing security in browsers.
When encountering this issue you can also run into these sorts of errors:
Response for preflight has invalid HTTP status code 500
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource
As of Acumatica Version 6.10.0945, this is how you configure IIS to make it CORS compatible for Acumatica for this type of requirement.
Add the following HTTP Response Headers within IIS.
Name: Access-Control-Allow-Origin Value: http://5.5.5.5 (IP Address or URL of the site that will connect to Acumatica - eg. https://mycompany.zendesk.com)
Name: Access-Control-Allow-Headers Value: Content-Type, cache-control
Name: Access-Control-Allow-Credentials Value: true
When values are added from Internet Information Services (IIS) Manager, they also appear in the web.config file in the Acumatica application folder as Custom Headers. For example - C:\Program Files (x86)\Acumatica ERP\MainAcumatica\web.config
I experienced issues adding the entries directly to web.config so suggest it is done through IIS.
Secondly, an entry needs to be made into the Global.asax file located in the same directory as web.config
This is the complete file with the function to insert being Application_BeginRequest():
<%# Application Language="C#" Inherits="PX.Web.PXApplication" %>
<script RunAt="server">
protected override void MergeAdditionalAssemblyResources()
{
PX.Web.UI.AssemblyResourceProvider.MergeAssemblyResourcesIntoWebsite<PX.Web.Controls.PXResPanelEditor>();
}
protected override void Initialization_ProcessApplication()
{
Initialization.ProcessApplication();
}
protected void Application_BeginRequest() {
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") {
Response.Flush();
}
}
</script>
The function Application_BeginRequest() in this file is flushing the response generated by the application for CORS OPTIONS requests, and letting IIS handle it with its header configuration.
OPTIONS requests are made by the CORS mechanism in the web browser, referred to as ‘pre-flight’, in order to confirm that the target server for the request is CORS compliant.
These settings will resolve the issue reported.
Instead of using basic authentication, try to pass username, password, company, branch, and locale (company, branch, and locale are optional) as request body following the sample below:
URL = "http://10.211.55.3/StackOverflow/entity/auth/login"; //Your URL
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", URL, false);
xmlhttp.setRequestHeader("Content-Type", "application/json");
var params = "{ name: '<username>', password: '<password>' }";
xmlhttp.send(params);

No 'Access-Control-Allow-Origin' but still processing

I have two different servers and each have their own domain. I'm running an ajax script from one server to the other server. I am receiving the "No 'Access-Control-Allow-Origin'" error, BUT my server side script is still processing the request.
Is there a reason my server side script is processing the ajax request even though it is a CORS violation?
Update: Here is my code
var init,
yourname,
youremail,
friendname,
friendemail,
message,
url,
data,
request;
init = function() {
yourname = $('input[name=yourName]').val();
youremail = $('input[name=yourEmail]').val();
friendname = $('input[name=friendName]').val();
friendemail = $('input[name=friendEmail]').val();
message = $('textarea[name=comments]').val();
url = window.location.href;
data ='yourName=' + yourname + '&yourEmail=' + youremail + '&friendName=' + friendname + '&friendEmail=' + friendemail + '&comments=' + message + '&url=' + url;
request = $.ajax({
type: 'POST',
url: features.captureForm.processing,
data: data,
cache: false
});
request.done(function() {
$('#form').css({'height':'0','overflow':'hidden'});
$('#formHeader').find('h2').html('Thank you!');
setTimeout(function(){
HideShowForm.init();
$('#form').css({'height':'auto'});
$('#formHeader').find('h2').html('Send to a friend!');
},3000);
});
request.fail(function() {
console.log('Something went wrong');
});
};
The request is sent and your server will process it as usual. Only its response will not be available for the client script. That is the point where CORS allows or denies anything, not when sending the request.
This is a simple misunderstanding of CORS on your part.
If the request is a "simple" cross-origin request (GET, POST, HEAD), it is no different than any cross-origin browser-based request that your server could have received before the CORS spec was drafted and implemented. The CORS spec wasn't designed to protect your server from such requests: it never was protected by default. If you want to discard such requests, you can look at the origin in your server code and simply not perform the requested operation if you prefer.
Non-simple cross-origin requests, such as PUT or DELETE requests, will invoke a "preflight" (OPTIONS) request by the browser, essentially asking your server "Is it ok to send this request?" Only if your server properly acknowledges will the underlying request will be sent. These types of non-simple cross-origin browser-based requests were not possible before the CORS spec, hence the additional layer of protection for older servers or those that don't want to opt-in to these new cross-origin requests.
Note that there are other factors that make a cross-origin request simple or not.

Categories

Resources