I want to handle some malicious request by not sending any kind of response in Flask.
In a route like:
#app.route("/something", methods=['POST'])
def thing():
return
Still returns an INTERNAL SERVER ERROR with View function did not return a response.
How do I formally send NO RESPONSE back to a client, i.e from an ajax call like so?
$.ajax({
url: "/something/",
method: "POST",
data: JSON.stringify({
"foo": "abc",
"bar": "123"
}),
success: function(resp) {
console.log(resp);
},
error: function(error) {
console.log(error); // this still gets called. I want it to hang.
}
})
... I want it to hang.
What you probably want is to close the connection on the server side (since you need to free the resources) but don't want the client to realize that the connection is closed. You cannot do this from flask or any other web application since any close of the connection on the server will cause the OS kernel to send the FIN to the client and thus the client knows about the closing too.
I suggest instead that you issue a redirect to the client to a URL where the client just hangs: for example have some iptables DROP rule on port 8080 and then redirect the client to http://your.host:8080/. Many clients will blindly follow such redirects and then hang (until they timeout) while trying to connect to this dead drop URL.
Related
Trying to learn Groovy, and it's been a fun and only slightly confusing adventure so far. What I'm currently trying to do is stand up a server, make a wget request to it and when that request is received, have a certain action be executed - in this case, just creating a new file:
import java.net.http.HttpResponse
class ServerLogic {
static def holdupServer() {
println('Standing up server..\n')
def socketServer = new ServerSocket(5000)
// server is up
socketServer.accept { socket ->
// the lines below only execute when a connection is made to the server
socket.withStreams { input, output ->
println("[${new Date()}] HELLO\n")
def newFile = new File("/home/nick/IdeaProjects/groovy_learning/resources/new.txt")
newFile.createNewFile()
newFile.text = 'Hello!!!'
println("NEW FILE SHOULD HAVE BEEN CREATED.")
println ">> READ: ${input.newReader().readLine()}"
}
}
return HttpResponse
}
}
ServerLogic.holdupServer()
With the above code, when I execute a wget http://localhost:5000, it "works" in the sense that the file is created like I want it to be, but the wget output is unhappy:
--2021-07-17 15:42:32-- http://localhost:5000/
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... connected.
HTTP request sent, awaiting response... No data received.
Retrying.
--2021-07-17 15:42:33-- (try: 2) http://localhost:5000/
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:5000... failed: Connection refused.
// these occur because the server has shut down after the last println call, when the `return HttpResponse` triggers
So from that, we can reason out that there isn't a proper response being returned, even though I have the return HttpResponse after the sockerServer.accept ... logic. My thought on how to solve the problem (primarily because I come from a Python background) would be to somehow mimic yielding a response in Python (basically, return a response without breaking out of the holdupServer() logic and thus breaking the server connection). Is there a way to achieve this in Groovy, or is there a different approach I could use to essentially return a valid HttpResponse without exiting the holdupServer() block?
Explanation
You can use a function callback, which in Groovy translates to a closure callback. Basically, you pass the value you want to return to another function/method defering the stack on the current method. This approach works essentially on all languages. In java (the versions which don't support lambda), for instance, you would have to pass an object in which you would call a method later.
Example
import java.net.http.HttpResponse
class ServerLogic {
static def holdupServer(Closure closure) {
(0..2).each {
closure.call(HttpResponse)
}
}
}
ServerLogic.holdupServer { httpResponse ->
println httpResponse
}
Output
interface java.net.http.HttpResponse
interface java.net.http.HttpResponse
interface java.net.http.HttpResponse
Addressing OP's comment
You have to provide some headers. At least Content-Type and Content-Length should've been provided along with the data and HTTP status (HTTP/1.1 200, in this case) properly formatted. Also, you should've wrapped the ServerSocket.accept calls in a while loop.
See the MDN Overview on HTTP.
Code
class ServerLogic {
static HEADERS = [
"HTTP/1.1 200",
"Content-Type: text/html; charset=utf-8",
"Connection: Keep-Alive",
"Keep-Alive: timeout=5, max=1000",
"Content-Length: %d\r\n",
"%s"
].join("\r\n")
static def holdupServer(Closure callback) {
println('Standing up server..\n')
def socketServer = new ServerSocket(5000)
// server is up
while(true) { // Continue to accept connections
socketServer.accept { socket ->
// the lines below only execute when a connection is made to the server
callback.call(socket) // call function
}
}
}
}
ServerLogic.holdupServer { Socket socket ->
String data = "RESPONSE <--\n"
def response = String.format(ServerLogic.HEADERS, data.size(), data)
println response
socket << response
}
Client output
RESPONSE <--
I cannot understand how send function works in flask-socketio.
For example, I am using flask-socketio as server and socket.io as client:
server:
#socketio.on("test")
def handle_test():
send("Wow")
client:
socket.emit('test', "", (data) => {
console.log(data);
});
I think I can get data from server side, but I'm wrong. I just get nothing.
I understand I can build a structure based on event. But I cannot understand how send works. Will it send response to client? If it will, how could I get that response? If it won't, what does it do?
First, I suggest you use emit() instead of send().
To send from client to server, use this:
socket.emit('test', {data: 'my data'});
On the server, you can receive the event and then emit back to the client:
#socketio.on('test')
def handle_test():
emit('wow');
To receive this second emit on the client, do this:
socket.on('wow', function(data) {
console.log(data);
});
I'm trying to get the FB messenger API working using Python's Flask, adapting the following instructions: https://developers.facebook.com/docs/messenger-platform/quickstart
So far, things have been going pretty well. I have verified my callback and am able to receive the messages I send using Messenger on my page, as in the logs in my heroku server indicate the appropriate packets of data are being received by my server. Right now I'm struggling a bit to send responses to the client messenging my app. In particular, I am not sure how to perform the following segment from the tutorial in Flask:
var token = "<page_access_token>";
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
So far, I have this bit in my server-side Flask module:
#app.route('/', methods=["GET", "POST"])
def chatbot_response():
data = json.loads(req_data)
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
url = "https://graph.facebook.com/v2.6/me/messages"
qs_value = {"access_token": TOKEN_OMITTED}
json_response = {"recipient": {"id": sender_id}, "message": "this is a test response message"}
response = ("my response text", 200, {"url": url, "qs": qs_value, "method": "POST", "json": json_response})
return response
However, running this, I find that while I can process what someone send my Page, it does not send a response back (i.e. nothing shows up in the messenger chat box). I'm new to Flask so any help would be greatly appreciated in doing the equivalent of the Javascript bit above in Flask.
Thanks!
This is the code that works for me:
data = json.loads(request.data)['entry'][0]['messaging']
for m in data:
resp_id = m['sender']['id']
resp_mess = {
'recipient': {
'id': resp_id,
},
'message': {
'text': m['message']['text'],
}
}
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(resp_mess),
headers = {'content-type': 'application/json'})
key differences:
message needs a text key for the actual response message, and you need to add the application/json content-type header.
Without the content-type header you get the The parameter recipient is required error response, and without the text key under message you get the param message must be non-empty error response.
This is the Flask example using fbmq library that works for me:
echo example :
from flask import Flask, request
from fbmq import Page
page = fbmq.Page(PAGE_ACCESS_TOKEN)
#app.route('/webhook', methods=['POST'])
def webhook():
page.handle_webhook(request.get_data(as_text=True))
return "ok"
#page.handle_message
def message_handler(event):
page.send(event.sender_id, event.message_text)
In that scenario in your tutorial, the node.js application is sending an HTTP POST request back to Facebook's servers, which then forwards the content on to the client.
So far, sounds like your Flask app is only receiving (AKA serving) HTTP requests. The reason is that that's what the Flask library is all about, and it's the only thing that Flask does.
To send an HTTP request back to Facebook, you can use any Python HTTP client library you like. There is one called urllib in the standard library, but it's a bit clunky to use... try the Requests library.
Since your request handler is delegating to an outgoing HTTP call, you need to look at the response to this sub-request also, to make sure everything went as planned.
Your handler may end up looking something like
import json
import os
from flask import app, request
# confusingly similar name, keep these straight in your head
import requests
FB_MESSAGES_ENDPOINT = "https://graph.facebook.com/v2.6/me/messages"
# good practice: don't keep secrets in files, one day you'll accidentally
# commit it and push it to github and then you'll be sad. in bash:
# $ export FB_ACCESS_TOKEN=my-secret-fb-token
FB_TOKEN = os.environ['FB_ACCESS_TOKEN']
#app.route('/', method="POST")
def chatbot_response():
data = request.json() # flasks's request object
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
send_back_to_fb = {
"recipient": {
"id": sender_id,
},
"message": "this is a test response message"
}
# the big change: use another library to send an HTTP request back to FB
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN},
data=json.dumps(send_back_to_fb))
# handle the response to the subrequest you made
if not fb_response.ok:
# log some useful info for yourself, for debugging
print 'jeepers. %s: %s' % (fb_response.status_code, fb_response.text)
# always return 200 to Facebook's original POST request so they know you
# handled their request
return "OK", 200
When doing responses in Flask, you have to be careful. Simply doing a return statement won't return anything to the requester.
In your case, you might want to look at jsonify(). It will take a Python dictionary and return it to your browser as a JSON object.
from flask import jsonify
return jsonify({"url": url, "qs": qs_value, "method": "POST", "json": json_response})
If you want more control over the responses, like setting codes, take a look at make_response()
I'm trying to use django-websocket-redis and I didn't understand how it works even reading the doc..
The part client (javascript/template) was easy to understand but I want to send data messages from one client to other and i'm blocking here..
Connecting each client :
var ws = new WebSocket('ws://localhost:8000/ws/foobar?subscribe-group');
ws.onopen = function(e) {
console.log("websocket connected");
};
ws.onclose = function(e) {
console.log("connection closed");
};
How manage my views.py to create a link between them ?
With NodeJS I was using this code to link the clients together :
io.sockets.on('connection', function (socket) {
var data={"action": "connexion", "session_id": socket.id,};
socket.emit('message',data);
socket.on('message', function(socket){
if (socket.action == "test")
{
io.sockets.socket(socket.code).emit('message',{"action": "move"});
//the socket.code is the session_id of the client one transmitted by a form
}
});
});
Thanks you.
The link between your Django view.py and the Websocket loop is the Redis message queue. Imagine to have two separate main loops on the server: One which handles HTTP-requests using the normal Django request handler. The other loop handles the Websockets, with their long living connections. Since you can't mix both loops within the normal Django request handler, you need message queuing, so that they can communicate to each other.
Therefore, in your Django view.py, send the data to the websocket using something like:
def __init__(self):
self.redis_publisher = RedisPublisher(facility='foo', broadcast=True)
def get(self, request):
data_for_websocket = json.dumps({'some': 'data'})
self.redis_publisher.publish_message(RedisMessage(data_for_websocket))
This will publish data_for_websocket on all Websockets subscribed (=listening) using the URL:
ws://example.com/ws/foo?subscribe-broadcast
I am trying to send a request to call a python method in my python script.
Server Side:
I am using flask ,so the server is running on port 5000.It has a file called helloflask.py which look like
#helloflas.py
from flask import Flask
app = Flask(__name__)
#app.route("/hello",methods=['GET','POST'])
def hello():
return "Comming Here"
if __name__ == "__main__":
app.run(port=5000,debug=True)
Client Side:
Independent HTML outside of flask which is sending the ajax request.
<!--ajax call-->
<script>
function findAppartment() {
$.ajax({
url: "https://127.0.0.1:5000/hello/",
type: "get",
contentType: "application/xml; charset=utf-8",
success: function (response) {
// $('#blurg').html(response).fadeIn(1500);
}
});
}
</script>
when the request is made,I get the following error.It hits the server and gives the following error:
Error : code 400, message Bad request syntax ('\x16\x03\x01\x00\xa1\x01\x00\x00\x9d\x03\x02Q\xd8\xc0O+\x8f\xa6\x16F\x9a\x94\x90|$\x11\xd3\xd8\x15\x04$\xe4\xb4>\xc0\x0e\xe3\xa0h\xea\x07\x00\xc5\x00\x00H\xc0')
I tried many things but things don't seem to be working.Could any one help???Any help is highly appreciated.