So I'm trying to make a problem for a ctf, and for a problem, I need to send data from a python script to the javascript. Can anyone tell me how?
My html code is:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1 class="text">text</h1>
<script>
$.get("[website]/cgi-bin/challenge.py",
function(data) {
$(".text").html(data);
});
</script>
</body>
</html>
I replaced the website with [website].
The python code is like this:
#!/usr/bin/python
import json
print "Content-type: text/html\n\n"
json.dumps("It works!")
#!/usr/bin/python
import json
text = json.dumps("It works!")
print "Content-Type: application/json\n"
print text
you can try: https://www.zerorpc.io/ , zerorpc is a communication between server-side processes that lets you transfer data from a server to a client.
in your situation, if you want to transfer data from python to node.js you cand do it like this:
in your python file as a server do:
import zerorpc
class HelloRPC(object):
def hello(self, name):
return "Hello, %s" % name
s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()
and in your node.js code as a client:
var zerorpc = require("zerorpc");
var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
client.invoke("hello", "RPC", function(error, res, more) {
console.log(res);
});
this will print "hello RPC" on the console.
Related
I would like to understand better how flask path interact with JS code , specifically fetch api
#app.route('/submit', methods=['POST'])
def submit():
return render_template("apology.html") #test line of code
try:
with limiter.limit("1/10second"):
if request.method == "POST":
logging.info("msg sended")
data = request.json
user_id = session["user_id"]
if not data:
logging.info("DATA IS MISSION")
return render_template("apology.html")
if not session.get("user_id"):
logging.critical("This is a critical message")
logging.info("SESSION IS MISSSION")
return render_template("apology.html")
db.execute("INSERT INTO user_messages_2 (user_id, user_message) VALUES (?,?)", user_id, data)
return render_template("apology.html")
except RateLimitExceeded:
return "Too many requests, please try again later"
async function frontend_msg(){
const value_message = document.getElementById("chat_message").value
const response = await fetch("/submit", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(value_message) //message or data in here and make it a string
});
if (response.status != 200) {
console.log('Error: Response status is not 200');
await new Promise(resolve => setTimeout(resolve, 6000));
// you can call the function again to retry sending the message
frontend_msg();}
//document.getElementById('bad_form_design').reset();
document.getElementById('chat_message').value = ""
}
in this example I am sending "post" request to my flask app with the value of what user typed in inputform
and as you can see I added this line of code
return render_template("apology.html") #test line of code
and I was expecting this to happen when someone sends "post" request to my flask app
post request gets send to the "/submit" path
the page instantly renders return render_template("apology.html") #test line of code
instead the code below "return render_template("apology.html") #test line of code" just does not run which it makes sense I guess
context matters here and it looks like that "/submit" returns "render_template("apology.html")" to javascript and javascript has no idea what "render_template("apology.html")" means so it just does nothing
so I was wondering am I correct in this theory or is something else happening , and how else can I change the page after someone types in that input field and sends json data to flask
}
The Fetch-API is to be used if you want to send or load data without having to reload the entire page. Basically, the call initially does nothing other than send a request.
If a response from the server is expected and should be processed, this must be specified in the code. The browser does not do this by itself. Either a then block is used or the response was awaited and then something is done with the response.
In your example, however, the response data is ignored and therefore nothing is done.
If the template rendered and sent by the server is to be inserted into the page, the data must first be read from the stream. The data obtained can then be added to the page.
The following simple example shows you one possible use of the Fetch-API in conjunction with render_template.
./app.py
from flask import (
Flask,
render_template
)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.post('/data')
def index_data():
return render_template('index_data.html')
./templates/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
</head>
<body>
<button id="btn-demo">Click Me</button>
<output id="value"></output>
<script type="text/javascript">
(function() {
const outValue = document.getElementById('value');
const btnDemo = document.getElementById('btn-demo');
btnDemo.addEventListener('click', async () => {
const data = await fetch('/data', { method: 'post' })
.then(resp => resp.ok && resp.text());
if (data) {
outValue.innerHTML = data;
}
});
})();
</script>
</body>
</html>
./templates/index_data.html
<p>Hello World</p>
I thought it was a quirk of the framework I was using, so I tested with another framework, but the result is the same: sending a burst of requests will process them asynchronously as expected when the urls are different, but will queue the requests with the same url and process them synchronously.
Why are some requests processed synchronously and some asynchronously?
Below the code to test with both Flask and CherryPy. Visiting localhost:5000 with Flask and localhost:8080 with CherryPy will load a page with JavaScript that will send a burst of 16 requests. The requests have an unused parameter in the query string which can have 4 different values, so the server will receive 4 different requests, each 4 times, for a total of 16 requests.
The server starts processing the first 4 requests for each parameter value, after finishing them will start processing the next 4 requests, etc.
Why aren't all 16 requests processed at the same time?
Flask
import flask
import time
import threading
import datetime
app = flask.Flask(__name__)
def log(txt):
print(' {} {:6d} {}'.format(datetime.datetime.now().strftime('%H:%M:%S.%f'),
threading.current_thread().ident,
txt))
#app.route('/')
def index():
log('index')
return """<!DOCTYPE HTML>
<html>
<head>
<script>
setTimeout(function(){{
for(i=0; i<16; i++) {{
xhttp = new XMLHttpRequest();
xhttp.open("GET", "test/" + i%4, true);
xhttp.send();
}}
}}, 2000);
</script>
</head>
<body>
hello
</body>
</html>"""
#app.route('/test/<x>')
def test(x):
log('test{}'.format(x))
time.sleep(3)
log(' test{}'.format(x))
return 'OK'
app.run(threaded=True)
CherryPy
import cherrypy
import time
import datetime
import threading
def log(txt):
print(' {} {:6d} {}'.format(datetime.datetime.now().strftime('%H:%M:%S.%f'),
threading.current_thread().ident,
txt))
class Root:
#cherrypy.expose
def index(self):
log('index')
return """<!DOCTYPE HTML>
<html>
<head>
<script>
setTimeout(function(){{
for(i=0; i<16; i++) {{
xhttp = new XMLHttpRequest();
xhttp.open("GET", "test?x=" + i%4, true);
xhttp.send();
}}
}}, 2000);
</script>
</head>
<body>
hello
</body>
</html>"""
#cherrypy.expose
def test(self, x):
log('test{}'.format(x))
time.sleep(3)
log(' test{}'.format(x))
return 'OK'
if __name__ == '__main__':
cherrypy.quickstart(Root())
I'm trying to get Server Sent Events to work from Python, so I found a little demo code and to my surprise, it only partly works and I can't figure out why. I got the code from here and put in just a couple little changes so I could see what was working (I included a print statement, an import statement which they clearly forgot, and cleaned up their HTML to something I could read a little easier). It now looks like this:
# Bottle requires gevent.monkey.patch_all() even if you don't like it.
from gevent import monkey; monkey.patch_all()
from gevent import sleep
from bottle import get, post, request, response
from bottle import GeventServer, run
import time
sse_test_page = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js "></script>
<script>
var es = new EventSource("/stream");
es.onmessage = function(e) {
document.getElementById("log").innerHTML = e.data;
}
</script>
</head>
<body>
<h1>Server Sent Events Demo</h1>
<p id="log">Response Area</p>
</body>
</html>
"""
#get('/')
def index():
return sse_test_page
#get('/stream')
def stream():
# "Using server-sent events"
# https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events
# "Stream updates with server-sent events"
# http://www.html5rocks.com/en/tutorials/eventsource/basics/
response.content_type = 'text/event-stream'
response.cache_control = 'no-cache'
# Set client-side auto-reconnect timeout, ms.
yield 'retry: 100\n\n'
n = 1
# Keep connection alive no more then... (s)
end = time.time() + 60
while time.time() < end:
yield 'data: %i\n\n' % n
print n
n += 1
sleep(1)
if __name__ == '__main__':
run(server=GeventServer, port = 21000)
So here's what ends up happening: I can see the original header and paragraph on the website, but response area never changes. On the python side, it prints n once per second, but I never see that change on the web page. I get the feeling that I just lack a fundamental understanding of what I'm trying to do but I can't find anything missing.
I'm running Python 2.7, windows 7, chrome 43.0.2357.81 m.
EDIT: I got rid of the extra quotation mark. Now it only seems to update when it gets to 60 (which I guess is better than not at all...)
Why would it wait until the end of the function to send the event?
You've got 2 sets of quotes after p id="log""
I am trying to get (the latest) Web.py and AJAX to play nice with each other, but so far I haven't had much luck.
Long story short, I am running both the server-side (Web.py) and the client side (Javascript) on my local development computer, but somehow all my AJAX GET requests are showing up as OPTION requests. From what I've read, this is typical is cases of cross domain requests, but since I'm running this on localhost I am not sure what's going on.
Here's the server-side code:
import web
import json
def make_text(string):
return string
urls = ('/', 'mainScreen',
'/update', 'update'
)
app = web.application(urls, globals())
global content
content = {'key1': 'value1', 'key2': 'value2'}
def getPayload():
return content
class mainScreen:
def GET(self):
web.header('Content-Type', 'application/json')
web.header('Access-Control-Allow-Origin', '*')
web.header('Access-Control-Allow-Credentials', 'true')
return getPayload()
def OPTIONS(self):
web.header('Content-Type', 'application/json')
web.header('Access-Control-Allow-Origin', '*')
web.header('Access-Control-Allow-Credentials', 'true')
return getPayload()
class update:
def POST(self):
global content
content = web.input(_method='post')
return "DONE."
if __name__ == '__main__':
app.run()
Here's the client-side code:
<html>
<head>
<title>WTF</title>
<script type="text/javascript" src="../static/jquery.js"></script>
<script type="text/javascript">
function dial()
{
console.log("Fire in the hole!");
$.ajax({
url: 'http://0.0.0.0:8080',
contentType: 'application/jsonp',
timeout : 5000,
cache: false,
success: function (data) {
console.log('[ajax] Connection successful! ' + JSON.stringify(data));
},
error:function (jqXHR, textStatus, errorThrown){
console.log(JSON.stringify(jqXHR) + ' ' + textStatus +' '+errorThrown );
}
});
console.log("Done.");
}
$(function() {
dial();
});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
This is Firebug's output:
Fire in the hole! index.html (line 9) DONE.
index.html (line 24) [ajax] Connection successful! ""
index.html (line 17)
Notice that the "" indicate that the request got empty data.
This is what Firebug's network panel shows:
If i open the page that Firebug indicates the data's there alright but if I, quite simply open http://0.0.0.0:8080/ on any browser, the data is displayed as expected! What is happening here?
Finally, here's Web.py's log:
hal#ubuntu:~/Desktop/tut$ python app.py
http://0.0.0.0:8080/
127.0.0.1:43796 - - [26/Jul/2013 11:14:59] "HTTP/1.1 OPTIONS /" - 200 OK
I'm coding in Ubuntu 12.04 LTS by the way.
PS: I also tried changing the response header inside Web.py to:
web.header('Content-Type', 'text/plain')
but it didn't work.
PS2: Changing the server address on the client-side script to "127.0.0.1:8080" or "localhost:8080" didn't help either.
Nailed it.
The issue was on the client-side code. I remove the contentType from the request itself and it worked perfectly.
I'm having some issues getting AJAX communication working using the Bottle framework. This is my first time using AJAX, so it's likely I just have the basics wrong. Hopefully a Bottle/AJAX guru can point this novice in the right direction. Here is the code I'm using:
#!/usr/bin/env python
from bottle import route, request, run, get
# Form constructor route
#route('/form')
def construct_form():
return '''
<html>
<head>
<script type="text/javascript">
function loadXMLDoc()
{
xmlhttp = new XMLHTTPRequest();
xmlhttp.onReadyStateChange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
document.getElementById("responseDiv").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("GET", "/ajax", true);
xmlhttp.send();
}
</script>
</head>
<body>
<form>
<input name="username" type="text"/>
<input type="button" value="Submit" onclick="loadXMLDoc()"/>
</form>
<div id="responseDiv">Change this text to what you type in the box above.</div>
</body>
</html>
'''
# Server response generator
#route('/ajax', method='GET')
def ajaxtest():
inputname = request.forms.username
if inputname:
return 'You typed %s.' % (inputname)
return "You didn't type anything."
run(host = 'localhost', port = '8080')
There are a few issues here.
Javascript is case sensitive. XMLHTTPRequest should be XMLHttpRequest. You should have seen an error about this in your Javascript console.
onReadyStateChange should be onreadystatechange.
If you fix the above two issues your AJAX call will work, but you will only ever get the 'You didn't type anything.' response. This is because you are using GET. You need to change your code so the form values are posted using the POST method.
Also, why aren't you using jQuery to do AJAX? It would make your life much easier. :)