Why does my python HttpServer dump all received requests on close? - python

I have the following request handler:
class MyHandler(BaseHTTPRequestHandler):
def do_POST(self) -> None:
if self.path == "/myRoute":
self.handle_route()
def handle_route(self):
print("Handling /myRoute")
received_bytes = self.rfile.read(int(self.headers['Content-Length']))
data = json.loads(received_bytes.decode('utf8').replace("'", '"'))
logger.info(json.dumps(data, indent=4, sort_keys=True))
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(bytes("{\"Success\":true,\"Exception\":\"\"}", "utf-8"))
I am successfully handling POSTs to the route /myRoute. However, when I close after the following usage:
my_server = server.HTTPServer(("localhost", 8080), MyHandler)
my_thread = threading.Thread(target=my_server.serve_forever)
my_thread.daemon = True
my_thread.start()
# do some work
my_server.server_close()
I see a "dump" of all the POSTs received. This makes me think I am not properly flushing my response(s) back to the client:
127.0.0.1 - - [04/Aug/2020 12:01:58] "POST /myRoute HTTP/1.1" 200 -
127.0.0.1 - - [04/Aug/2020 12:02:35] "POST /myRoute HTTP/1.1" 200 -
127.0.0.1 - - [04/Aug/2020 12:03:11] "POST /myRoute HTTP/1.1" 200 -
.
.
.
What makes me think this even more is that it is the same number of requests I received during the execution of my application.
Am I properly sending my responses back to the client?

To fix this, I simply overrided the BaseHttpRequestHandler.log_message() to do nothing:
def log_message(self, format: str, *args: Any) -> None:
"""
Override of BaseHTTPRequestHandler to skip logging of messages.
Parameters
----------
format: str
The str format.
args: Any
The values to log.
"""
Then I only logged what I was interested in via the typical logger = logging.getLogger(__name__) in my route handling methods.

Related

FastAPI parallel requests not working in Python

from fastapi import FastAPI
import uvicorn
app = FastAPI()
#Some long processing code, with async declaration
async def doBTask():
print ("Request started")
#asyncio.sleep(20)
sum = 0
for n in range (1, 10000):
for m in range(1,10000):
if m%n ==0:
pass
else:
sum = sum + n
print ("Completed")
return sum
#app.get("/")
async def read_root():
result = await doBTask()
return {"Result": result}
uvicorn.run(app, host="0.0.0.0", port=7000)
When we call that URL in different tabs, the output is coming one after another (even print also). It is clearly single processing but not parallel request processing.
Can someone guide where is the mistake, and why FastAPI with async and await not working?
Edit
Here is the response I am getting if tried in different browsers and dummy params (you can see, it is processing one after another, even though I sent all at a time)
Request started
Completed
INFO: 127.0.0.1:58998 - "GET /?n=10 HTTP/1.1" 200 OK
Request started
Completed
INFO: 127.0.0.1:59012 - "GET /?m=30 HTTP/1.1" 200 OK
Request started
Completed
INFO: 127.0.0.1:59288 - "GET / HTTP/1.1" 200 OK

Cherrypy logingg POST body

I'am using default cherrypy logger.
I have log every access request to my server. For GET request i have full info, like
127.0.0.1 - - [06/Jul/2021:16:10:28] "GET /test/?contract_id=228322 HTTP/1.0" 200 33
But for POST request i can't log query params or body.
127.0.0.1 - - [06/Jul/2021:13:21:03] "POST /test HTTP/1.0" 201 169
So how can i log POST query's body?
You can create tool like
def response_logging():
cherrypy.log.access_log.info(
'[{time}] {ip} "{user_agent}" {request_line} "{query_params}" "{body}" "{status}" {response}'.format(
time=datetime.now().strftime("%d/%m/%Y:%H:%M:%S"),
ip=cherrypy.request.remote.ip,
user_agent=cherrypy.request.headers["User-Agent"],
request_line=cherrypy.request.request_line,
query_params=cherrypy.request.body.request_params or "",
body=cherrypy.request.json if hasattr(cherrypy.request, "json") else "",
status=cherrypy.response.status,
response=cherrypy.response.body
)
)
cherrypy.tools.response_logging = cherrypy.Tool('on_end_request', response_logging)
print(cherrypy.request.params) # Prints params on querystring
print(cherrypy.request.headers) # Prints received headers on request
print(cherrypy.request.body) # Prints Body received

Python 3.6 BaseHTTPRequestHandler not responding to requests

I have a simple python server script to conditionally respond to post requests. But is not sending responses
Have searched stack overflow and online to find examples of the same behaviour
from http.server import BaseHTTPRequestHandler
import json
verb_id = "http://id.tincanapi.com/verb/rated"
print('starting')
def respond(statement):
email = statement["actor"]["mbox"]
verb = statement["verb"]["id"]
response = statement["result"]["response"]
return ('Recieved statement from {email}, verb: {verb} with response: {response}'.format(email=email, verb=verb, response=response))
class RestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_len = int(self.headers.get('Content-Length'))
post_body = self.rfile.read(content_len)
parsed_body = json.loads(post_body)
verb = parsed_body["statement"]["verb"]["id"]
if (verb == verb_id):
response = respond(parsed_body["statement"])
self.wfile.write(response.encode("utf-8"))
else:
print('recieved statement without rated')
self.wfile.write("Not processed".encode("utf-8"))
self.send_response(200)
self.end_headers()
return
httpd = HTTPServer(('0.0.0.0', 8025 ), RestHTTPRequestHandler)
while True:
httpd.handle_request()
The log shows
127.0.0.1 - - [11/Apr/2019 15:56:03] "POST / HTTP/1.1" 200 -
After each request, but Postman gives me 'Could not get any response'
I would expect to be getting a 200 to all post requests and the status returned from the if statement (either the result of the respond function or "Not Processed")
I am using Python 3.6
Thanks in advance

Why does Flask redirect to "GET /? HTTP/1.1"

I'm writing a simple Flask application in which I want to send some data from the front-end to the Flask app, have it perform some operations, and return new data to the front-end for display. I have made similar applications before, and by returning the POST response object, instead of render_template(), I'm able to simply return the data and do what I want with it on the front-end. However, this time I'm having problems.
I make a POST request from the Jquery in the front-end. Everything seems to work fine, I can see the data being returned in the browser console, except the page reloads before I can display the new data. It reloads to http://xxx.x.x.x:5000/?.
I can see the get request for /? in the Flask console. I'd like to know why it is doing this, and how I can get it to stop.
(I've found this difficult to research because most search engines will silently ignore any question marks in a query.)
Flask app:
import json
from flask import Flask, Response, render_template, request
from src.simple_lookup import analogy_lookup
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route('/')
def hello_world():
return render_template('index.html', results=['a', 'b'])
#app.route('/get_words_simple', methods=['POST'])
def get_words_simple():
print('request.form:', request.form.keys)
data = analogy_lookup(request.form['keyword'], request.form['base'], request.form['goal'])
resp = Response(json.dumps(data), status=200, mimetype='application/json')
print('data:', data)
print('resp:', resp)
return resp
if __name__ == "__main__":
app.run()
Jquery:
$.post('get_words_simple?', data, function(json, status) {
console.log('response:', json);
if (json.hasOwnProperty('error')) {
$('.results').append('<p>' + json.error);
return;
}
var words = json.words;
$.each(words, function(i, text) {
var p = $("<p>");
p.append(text);
$('.results').append(p);
});
});
Flask console:
127.0.0.1 - - [27/Dec/2018 11:12:21] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [27/Dec/2018 11:12:21] "GET /static/js/main.js HTTP/1.1" 200 -
request.form: <bound method MultiDict.keys of ImmutableMultiDict([('keyword', ''), ('base', ''), ('goal', '')])>
127.0.0.1 - - [27/Dec/2018 11:12:23] "GET /? HTTP/1.1" 200 -
127.0.0.1 - - [27/Dec/2018 11:12:23] "GET /static/js/main.js HTTP/1.1" 200 -
data: ['obtuvo', 'takata', 'stadshypotek', 'kriwet', 'shafiee', 'martorell', 'collum', '29,400', 'muteesa', 'patzek']
resp: <Response 111 bytes [200 OK]>
127.0.0.1 - - [27/Dec/2018 11:12:23] "POST /get_words_simple? HTTP/1.1" 200 -
Problem was that Bootstrap overrides type="submit" button functionality if it's in a form group. So my Jquery was doing everything right, but something about the html of the button was screwing everything up and trying to make a post request in a different way

spin up a simple web server that prints post data to console

I've found a number of simple web servers in python that will spin up a quick server and respond to requests simply. What I need is a server that won't just print the IP address, timestamp, method, and response code of each request (127.0.0.1 - - [28/Aug/2017 10:42:11] "POST / HTTP/1.1" 200 -), but also, if a POST request, I need it to print out the POST data.
So for example, if I send a POST request with {"foo":"bar"} in the body of the message, I want the server to print 127.0.0.1 - - [28/Aug/2017 10:42:11] "POST / HTTP/1.1" 200 - {"foo":"bar"} to the console before responding.
I'm not sure how to modify any of the linked options above to do this. If there's another simple option, that would work as well.
To just print out whatever JSON gets sent to a server, build yourself a basic catch-all endpoint and just print the JSON from it. In flask, this looks like the following:
import logging
from flask import Flask, request
app = Flask(__name__)
#app.route('/', methods=['POST', 'GET'], defaults={'path': ''})
#app.route('/<path:path>', methods=['POST', 'GET'])
def index(path):
print("HTTP {} to URL /{} received JSON {}".format(request.method, path, request.get_json()))
return "True"
Here's my calls to the server:
In [15]: requests.post('http://localhost:5000/', json={'a': 1})
Out[15]: <Response [200]>
In [16]: requests.post('http://localhost:5000/some/endpoint', json={'a': 1})
Out[16]: <Response [200]>
In [17]: requests.get('http://localhost:5000/', json={'a': 1})
Out[17]: <Response [200]>
Here's the server output:
In [7]: app.run(host='0.0.0.0')
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
HTTP POST to URL / received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:49] "POST / HTTP/1.1" 200 -
HTTP POST to URL /some/endpoint received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:51] "POST /some/endpoint HTTP/1.1" 200 -
HTTP GET to URL / received JSON {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:57:55] "GET / HTTP/1.1" 200 -
Original Answer
A simple decorator should do the trick:
from flask import Flask, request
app = Flask(__name__)
def print_if_post(*args, **kwargs):
def inner_decorator(f):
def inner(*args, **kwargs):
if request.method == 'POST':
json = request.get_json()
print("JSON Data: {}".format(json))
return f(*args, **kwargs)
return app.route(*args, **kwargs)(inner)
return inner_decorator
This decorator will function exactly like app.route, but will print any JSON data sent to its endpoint:
#print_if_post('/', methods=['POST', 'GET'])
def index():
return "True"
Called with the following code:
In [4]: requests.get('http://localhost:5000/')
Out[4]: <Response [200]>
In [5]: requests.post('http://localhost:5000/', json={'a': 1})
Out[5]: <Response [200]>
Server outputs:
In [2]: app.run(host='0.0.0.0')
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Aug/2017 11:03:11] "GET / HTTP/1.1" 200 -
JSON Data: {'a': 1}
127.0.0.1 - - [28/Aug/2017 11:03:23] "POST / HTTP/1.1" 200 -

Categories