0

I'm using python to host a simple LAN web page using HTTPRequestHandler:

from http import server # Our http server handler for http requests
import socketserver # Establish the TCP Socket connections
import json
 
PORT = 9000

messages = []
headers = []

class HTTPRequestHandler(server.BaseHTTPRequestHandler):
    def do_HEAD(self):
        self.send_response(200)
        
    def do_GET(self):
        self.send_response(200)

        if self.path != '/':
            return None
        self.send_header("Content-Type", "text/html")
        self.send_header("Connection", "Stop")
        self.end_headers()
        
        response_html = """
<html>
    <head>
        <title>
            Testa
        </title>
    </head>
    
    <body id="body">
        <h1 style="color:blue">
            Test
        </h1>


        <p>
        
                <input type="text" id="message" placeholder="Your message">

                <button onclick="sendMessage()">Send Message</button>

            <p class="result" style="color:blue">

        </p>

        <script language="javascript" type="text/javascript">
        function sendMessage(){
        
            let messagebox = document.querySelector('#message');
              
            // Creating an XHR object
            let xhr = new XMLHttpRequest();
            let url = "/message";
       
            // open a connection
            xhr.open("POST", url, true);
 
            // Set the request header i.e. which type of content you are sending
            xhr.setRequestHeader("Content-Type", "application/json");
 
            // Converting JSON data to string
            var data = JSON.stringify({ "message": messagebox.value});
 
            // Sending data with the request
            xhr.send(data);

            // Clearing the messagebox
            messagebox.value = ""
        }
        </script>
</html>
"""
        self.wfile.write(response_html.encode("utf-8"))
        return

    def do_POST(self):
        self.send_response(200)
        
        length = int(self.headers['content-length'])
        message = json.loads(self.rfile.read(length).decode("utf-8"))
        print(message)
        messages.append(message)
        headers.append([self.headers, self.command])
        
 
Handler = HTTPRequestHandler
 
with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("HTTP server started at:", PORT)
    httpd.serve_forever()

In essence, it creates this page:

website

And adds a function to the button, so that a POST request is sent to the server containing whatever was in the box. This part works fine.

My issue is that every time this POST request is sent, it is paired with another identical one:

HTTP server started at: 9000
127.0.0.1 - - [14/Sep/2022 17:23:18] "POST /message HTTP/1.1" 200 -
{'message': 'Hello World!!'}
127.0.0.1 - - [14/Sep/2022 17:23:39] "POST /message HTTP/1.1" 200 -
{'message': 'Goodbye World!!'}
127.0.0.1 - - [14/Sep/2022 17:23:39] "POST /message HTTP/1.1" 200 -
{'message': 'Goodbye World!!'}
127.0.0.1 - - [14/Sep/2022 17:23:52] "POST /message HTTP/1.1" 200 -
{'message': 'In-the-middle World!!'}
127.0.0.1 - - [14/Sep/2022 17:23:52] "POST /message HTTP/1.1" 200 -
{'message': 'In-the-middle World!!'}
127.0.0.1 - - [14/Sep/2022 17:24:05] "POST /message HTTP/1.1" 200 -
{'message': 'Possibly World!!'}
127.0.0.1 - - [14/Sep/2022 17:24:05] "POST /message HTTP/1.1" 200 -
{'message': 'Possibly World!!'}

With the occasional solo POST on the first send.

I've looked into it, and this is usually because

  1. Something redirects, or errs, causing the code to be restarted, and activated twice. While I am completely new to HTTP, JS, PHP, etc. (the web languages), I cannot see that happening here
  2. A PreFlight operation happens, where the server sends a preliminary request to see if the main request can be sent (question). I looked into that, and I do not think that is the case, as the headers are identical in both requests:
>>> pprint.pprint(dict(h1))
{'Accept': '*/*',
 'Accept-Encoding': 'gzip, deflate, br',
 'Accept-Language': 'en-US,en;q=0.9',
 'Connection': 'keep-alive',
 'Content-Length': '18',
 'Content-Type': 'application/json',
 'Host': 'localhost:9000',
 'Origin': 'http://localhost:9000',
 'Referer': 'http://localhost:9000/',
 'Sec-Fetch-Dest': 'empty',
 'Sec-Fetch-Mode': 'cors',
 'Sec-Fetch-Site': 'same-origin',
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
               '(KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 '
               'Edg/105.0.1343.33',
 'sec-ch-ua': '"Microsoft Edge";v="105", " Not;A Brand";v="99", '
              '"Chromium";v="105"',
 'sec-ch-ua-mobile': '?0',
 'sec-ch-ua-platform': '"Windows"',
 'sec-gpc': '1'}
>>> pprint.pprint(dict(h2))
{'Accept': '*/*',
 'Accept-Encoding': 'gzip, deflate, br',
 'Accept-Language': 'en-US,en;q=0.9',
 'Connection': 'keep-alive',
 'Content-Length': '18',
 'Content-Type': 'application/json',
 'Host': 'localhost:9000',
 'Origin': 'http://localhost:9000',
 'Referer': 'http://localhost:9000/',
 'Sec-Fetch-Dest': 'empty',
 'Sec-Fetch-Mode': 'cors',
 'Sec-Fetch-Site': 'same-origin',
 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
               '(KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 '
               'Edg/105.0.1343.33',
 'sec-ch-ua': '"Microsoft Edge";v="105", " Not;A Brand";v="99", '
              '"Chromium";v="105"',
 'sec-ch-ua-mobile': '?0',
 'sec-ch-ua-platform': '"Windows"',
 'sec-gpc': '1'}

And both contain the main message content

  1. The JavaScript is somehow being loaded twice, causing two functions to run simultaneously (question). As the JavaScript function I've written clears the input box immediately after sending it, and there is always some lag or latency, I doubt this is the case, but I don't know enough to disprove it

Regardless, I am now stuck. Everything I seem to try has no effect on cancelling this unpredictable (Sometimes the first message doesn't fire, sometimes it does) double POST, and cancelling it is mildly important to the messaging application I'm trying to shape this into. On top of using double the processing power, it is just incredibly inconvenient. Is there a way to stop this?

User 12692182
  • 927
  • 5
  • 16
  • If your question is about `XMLHttpRequest` you might want to fix your tags to include JavaScript and remove python – SitiSchu Sep 14 '22 at 22:25
  • normally if function is assigned to button in `
    ` then it needs extra function at the end to `stop propagate` even. If you don't stop it then it may run your code with `XMLHttpRequest` which sends first requests, and later it send event to standard function assigned to `
    ` and it sends another request (and reload paga). But it seems you don't have it in `
    ` so it shouldn't send it twice.
    – furas Sep 15 '22 at 01:34
  • BTW: JavaScript has modern `fetch(url)` instead very old `XMLHttpRequest` – furas Sep 15 '22 at 01:36
  • Code works for me without problem. In console server always shows one request, and in DevTools browser also always shows only one request. Tested with Firefox on Linux. Maybe problem makes browser. – furas Sep 15 '22 at 01:47
  • Probably is then. I used Edge v. 12 with Linux, and I know edge is finnicky sometimes – User 12692182 Sep 15 '22 at 13:26
  • If you are calling a different domain it is doing a preflight it is CORS, it knocks to ask if it can make the call. So working as designed. If it is same domain, are you sure you did not bind the event multiple times? – epascarello Sep 15 '22 at 20:49

1 Answers1

0

After doing some experimentation, I discovered that the problem resides in the browser itself.

Microsoft edge will always repeat the request unless you send back a response after the POST request. In this server code, all that is necessary is:

self.end_headers()

If this is your problem, open the console in Devtools (Inspect mode), and you should see something like this: problem

User 12692182
  • 927
  • 5
  • 16