Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I tried to make a web server on port 4460 but when i type "http://127.0.0.1:4460/" in the browser address bar the browser says ERR_INVALID_HTTP_RESONSE.(Google Chrome).Browser is latest version. The code did not raise any errors and did not send any bad_gateway requests.it did not access the .ico file. Python ver:3.8.10 my code:

import socket
from socket import AF_INET,SOCK_STREAM
from threading import Lock
from pprint import pprint
from threadtools import threaded
from email.utils import format_datetime as fmd
import datetime
from deflate import gzip_compress
ms = (lambda x:x/1000)
socket.setdefaulttimeout(ms(700))
ol = Lock()
plok = Lock()
ENCODINGS = "utf-8 utf-16 cp936 latin-1".split()
response_header = b"""\
200 OK
Content-Type: text/html
Content-Length: $$CTXLN$$
Content-Encoding: gzip
Connection: close
Date: $$DATE$$
Keep-Alive: timeout=2, max=2
$$CTX$$"""
bad_gateway = b"""\
502 Bad Gateway
Content-type:text/html
Content-legth:0"""
def decode(x,verbose=False):
    for enc in ENCODINGS:
        flag = False
            return x.decode(enc)
        except:
            flag = True
        finally:
            print("Decoded in:"+enc) if(not flag)and verbose else None
    return ""
def startswithany(a,lis):
    for x in lis:
        if a.startswith(x):
            return True
    return False
def is_newline(x):
    return x in ("\r\n","\n")
def load_rsrc(acpt):
    if "text/html" in acpt or "text/*" in acpt or "*/*" in acpt:
        return open("response.html","rb").read()
    elif "image/ico" in acpt or "image/*" in acpt:
        return open("response.ico","rb").read()
    else:
        return b""
def handle_connection(cnct,addr):
    global pending
    with plok:
        pending += 1
        if pending > 20:#Too many connections!!!
            cnct.send(bad_gateway)
        with ol:
            print(f"----------------\nConnection from:{addr}\n")
        has_ln = True
        data = b""
        ctx = ""
        headers = {"Unknown-Lines":[]}
        while True:
            data = b""
            while not decode(data).endswith("\n"):#\r\n ends with \n
                    data += cnct.recv(1)
                except:#timeout
                    has_ln = False
                    break
            if not has_ln:
                break
            assert len(data)
            data = decode(data).strip(" ")
            assert not data.startswith(" ")
            if is_newline(data):#empty line
                continue
            if startswithany(data,("GET","POST","PUT")):
                headers["Request-Type"] = data.strip()
            else:
                dsp = data.split(":",1)
                if len(dsp)!=2:
                    print(f"Unknown header:{data}")
                    headers["Unknown-Lines"].append(data)
                else:
                    a,b = data.split(":",1)
                    b = b.strip()
                    headers[a] = b
        with ol:
            print(f"Headers:")
            for k,v in headers.items():
                print(f"{k}:{v}")
        accept = headers.get("Accept","text/html")
        accept = accept.split(",")
        q = []
        for i,x in enumerate(accept):
            if ";q=" in x:
                a,b = x.split(";q=")
                b = float(b)
                accept[i] = a
                q.append(b)
        rt = tuple(map(str.strip,headers.get("Request-Type","GET/HTTP/1.0").split("/")))
        req = rt[0]#GET/POST/PUT
        protocol = rt[1]#HTTP;NO SECURE SERVER FOR NOW
        ver = rt[2]#version
        assert ver in ("1.0","1.1")
        now = datetime.datetime.now(datetime.timezone.utc)
        datestr = fmd(now,True).encode()
        ctx = load_rsrc(accept)
        ln = str(len(ctx)+1).encode()
        response = response_header.replace(b"$$CTXLN$$",ln)\
                                  .replace(b"$$CTX$$",ctx)\
                                  .replace(b"$$DATE$$",datestr)
        response_cmpr = gzip_compress(response)
        cnct.send(response_cmpr)
        print("Sent:")
        print(response.decode())
        if headers.get("Connection","Keep-alive") == "Keep-alive":
            import time
            time.sleep(2)
    finally:
        cnct.close()
        with plok:
            pending -= 1
skt = socket.socket(AF_INET,SOCK_STREAM)
skt.bind(("",4460))
skt.listen(3)
skt.settimeout(None)
pending = 0
while True:
    cn,ad = skt.accept()
    handle_connection(cn,ad)
                Why are you using low level interface for HTTP server? Can Flask be used to solve your problem? Or do you want to stick to the Python Standard Library? It seems your are reinventing the wheel...
– jlandercy
                Sep 19, 2021 at 5:06
                Still not working.If I use port 80 and visit 127.0.0.1/,the browser will keep loading and the program will not print anything.(I used Microsoft Edge but no luck)
– user16829600
                Sep 19, 2021 at 9:30

You are close to your goal. Making slight adjustments I got your snippet working. The main issue is in the HTTP response formatting, it should be defined as follow:

HTTP/1.1 200 OK                 <--- Missing HTTP/1.1 prefix
Content-Type: text/html
Keep-Alive: timeout=2, max=2
                                <--- Mind the extra newline here which is mandatory
$$CTX$$                         <--- Browser will expect HTML here

I have adapted the MCVE your provided, please find below a working version for latest Edge and Firefox browsers.

import socket
from socket import AF_INET,SOCK_STREAM
from threading import Lock
from pprint import pprint
#from threadtools import threaded
from email.utils import format_datetime as fmd
import datetime
#from deflate import gzip_compress
ms = (lambda x:x/1000)
socket.setdefaulttimeout(ms(700))
ol = Lock()
plok = Lock()
ENCODINGS = "utf-8 utf-16 cp936 latin-1".split()
response_header = b"""\
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: $$CTXLN$$
Connection: close
Date: $$DATE$$
Keep-Alive: timeout=2, max=2
$$CTX$$"""
# Missing HTTP/1.1 Prefix
# The extra new line is required
bad_gateway = b"""\
HTTP/1.1 502 Bad Gateway
Content-type:text/html
Content-legth:0
def decode(x,verbose=False):
    for enc in ENCODINGS:
        flag = False
            return x.decode(enc)
        except:
            flag = True
        finally:
            print("Decoded in:"+enc) if(not flag)and verbose else None
    return ""
def startswithany(a,lis):
    for x in lis:
        if a.startswith(x):
            return True
    return False
def is_newline(x):
    return x in ("\r\n","\n")
def load_rsrc(acpt):
    if "text/html" in acpt or "text/*" in acpt or "*/*" in acpt:
        #return open("response.html","rb").read()
        return b"hello"
    elif "image/ico" in acpt or "image/*" in acpt:
        return b"icon"
    else:
        return b""
def handle_connection(cnct,addr):
    global pending
    with plok:
        pending += 1
        if pending > 20:#Too many connections!!!
            cnct.send(bad_gateway)
        with ol:
            print(f"----------------\nConnection from:{addr}\n")
        has_ln = True
        data = b""
        ctx = ""
        headers = {"Unknown-Lines":[]}
        while True:
            data = b""
            while not decode(data).endswith("\n"):#\r\n ends with \n
                    data += cnct.recv(1)
                except:#timeout
                    has_ln = False
                    break
            if not has_ln:
                break
            assert len(data)
            data = decode(data).strip(" ")
            assert not data.startswith(" ")
            if is_newline(data):#empty line
                continue
            if startswithany(data,("GET","POST","PUT")):
                headers["Request-Type"] = data.strip()
            else:
                dsp = data.split(":",1)
                if len(dsp)!=2:
                    print(f"Unknown header:{data}")
                    headers["Unknown-Lines"].append(data)
                else:
                    a,b = data.split(":",1)
                    b = b.strip()
                    headers[a] = b
        with ol:
            print(f"Headers:")
            for k,v in headers.items():
                print(f"{k}:{v}")
        accept = headers.get("Accept","text/html")
        accept = accept.split(",")
        q = []
        for i,x in enumerate(accept):
            if ";q=" in x:
                a,b = x.split(";q=")
                b = float(b)
                accept[i] = a
                q.append(b)
        rt = tuple(map(str.strip,headers.get("Request-Type","GET/HTTP/1.0").split("/")))
        req = rt[0]#GET/POST/PUT
        protocol = rt[1]#HTTP;NO SECURE SERVER FOR NOW
        ver = rt[2]#version
        assert ver in ("1.0","1.1")
        now = datetime.datetime.now(datetime.timezone.utc)
        datestr = fmd(now,True).encode()
        ctx = load_rsrc(accept)
        ln = str(len(ctx)+1).encode()
        response = response_header.replace(b"$$CTXLN$$",ln)\
                                  .replace(b"$$CTX$$",ctx)\
                                  .replace(b"$$DATE$$",datestr)
        #response_cmpr = gzip_compress(response)
        cnct.send(response)
        print("Sent:")
        print(response.decode())
        if headers.get("Connection","Keep-alive") == "Keep-alive":
            import time
            time.sleep(2)
    finally:
        cnct.close()
        with plok:
            pending -= 1
skt = socket.socket(AF_INET,SOCK_STREAM)
skt.bind(("",8080))
skt.listen(3)
skt.settimeout(None)
pending = 0
while True:
    cn,ad = skt.accept()
    handle_connection(cn,ad)
                Wait--The browser can't connect(Connection timed out) when trying to use the 80 port and adjusted to skt.bind(("",80)). Also,the modified program still results in a ERR_HTTP_INVALID_RESPONSE when using the 8080 port.No exceptions raised.
– user16829600
                Sep 20, 2021 at 5:14
                > Also,the modified program still results in a ERR_HTTP_INVALID_RESPONSE when using the 8080 port.No exceptions raised.
– user16829600
                Sep 20, 2021 at 5:18
                Are you sure you are running the piece of code I sent (copy paste it in a new fresh file). Your program does not exist gracefully so first make sure you have stopped the previous version and are running this one. If you still have an error you will need to add more context on your issue because it runs on python 3.7+ and major browsers. So the problem can stand elsewhere. You can use whatever port you like, 80 is already taken on my test instance thus the 8080
– jlandercy
                Sep 20, 2021 at 5:22
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.