Count HTTP connections when using BaseHTTPRequestHandler

Question:

I have an HTTP Server like this

from http.server import BaseHTTPRequestHandler, HTTPServer
from datetime import datetime
import datetime as dt

numberOfTests = 1
timestamp = datetime.now()




class S(BaseHTTPRequestHandler):
    
    
    def formatResponse(self, vhod):
        global numberOfTests, timestamp
        timestamp = datetime.now()  
        if (numberOfTests == 1):
            print("Test "+str(numberOfTests)+" has started")
            numberOfTests =+ 1
            return          
        
        if (numberOfTests > 1):
            print("Test "+str(numberOfTests)+" has started")
            numberOfTests =+ 1
            

    def log_message(self, format, *args): #Silence internal log output
        return 

    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_POST(self):
        content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
        post_data = self.rfile.read(content_length) # <--- Gets the data itself

        self.formatResponse(post_data.decode('utf-8'))

        self._set_response()

def run(server_class=HTTPServer, handler_class=S, port=8080):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()

I would like that every time a connection is made I would like increment a counter

the problem is that my counter always resets after a new connection is made (like that BaseHTTPRequestHandler is initiated again) so I cannot realy count

ultimatly I would like to mesure time between POST requests and if time is x do something (but I need to figure out how to persist a variable between requests first (as would like to use time.time() as my stopwatch, since time never stops)

if anyone has any idea how to persist a variable between POST requests (to counte them for instance), please let me know

Thanks for Anwsering and Best Regards

Asked By: Hojzerice

||

Answers:

You could decorate do_POST and do_GET counting the requests in a class variable.

from http.server import BaseHTTPRequestHandler, HTTPServer
from datetime import datetime
import datetime as dt
from functools import wraps


def count(fn):
    @wraps(fn)
    def wrapper(*args, **kw):
        cls = args[0]
        _http_method = fn.__name__[3:]  # Format method

        # Count via HTTP method
        if _http_method not in cls.counts:
            cls.counts[_http_method] = 0
        cls.counts[_http_method] += 1
        return fn(*args, **kw)

    return wrapper


class S(BaseHTTPRequestHandler):
    counts = {}

    def formatResponse(self, vhod):
        print(f"Counter: {self.counts}")

    def log_message(self, format, *args):  #Silence internal log output
        return

    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    @count
    def do_POST(self):
        content_length = int(
            self.headers['Content-Length']
        )  # <--- Gets the size of data
        post_data = self.rfile.read(content_length)  # <--- Gets the data itself

        self.formatResponse(post_data.decode('utf-8'))

        self._set_response()

    @count
    def do_GET(self):
        self.formatResponse('123')
        self._set_response()


def run(server_class=HTTPServer, handler_class=S, port=8080):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()
    httpd.server_close()


run()

Out:

Counter: {'GET': 1}
Counter: {'GET': 2}
Counter: {'GET': 3}
Counter: {'GET': 4}
....
Answered By: Maurice Meyer

When the HTTP server receives a new request it creates a new instance of handler, so an instance variable would always reset. You can configure a class variable, then increment it every time the do_GET or do_POST is invoked. Class variables would change in every instance so it won’t reset.

from http.server import BaseHTTPRequestHandler, HTTPServer
from datetime import datetime
import datetime as dt

numberOfTests = 1
timestamp = datetime.now()




class S(BaseHTTPRequestHandler):
    counter = 0 #class variable here
    
    def formatResponse(self, vhod):
        global numberOfTests, timestamp
        timestamp = datetime.now()  
        if (numberOfTests == 1):
            print("Test "+str(numberOfTests)+" has started")
            numberOfTests =+ 1
            return          
        
        if (numberOfTests > 1):
            print("Test "+str(numberOfTests)+" has started")
            numberOfTests =+ 1
            

    def log_message(self, format, *args): #Silence internal log output
        return 

    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_POST(self):
        S.counter +=1
        content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
        post_data = self.rfile.read(content_length) # <--- Gets the data itself

        self.formatResponse(post_data.decode('utf-8'))

        self._set_response()

def run(server_class=HTTPServer, handler_class=S, port=8080):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()
Answered By: Jinghui Zhu
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.