打开我的网络服务器时,浏览器显示 ERR_INVALID_HTTP_RESPONSE
When opening my web server the browser says ERR_INVALID_HTTP_RESPONSE
我试图在端口 4460 上创建一个网络服务器,但是当我在浏览器中输入“http://127.0.0.1:4460/”时
地址栏浏览器显示 ERR_INVALID_HTTP_RESONSE.(Google Chrome)。浏览器是最新版本。
代码没有引发任何错误,也没有发送任何错误 bad_gateway requests.it 没有访问 .ico 文件。
Python ver:3.8.10
我的代码:
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
try:
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
try:
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
try:
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)
您离目标很近了。稍作调整后,您的代码段就可以正常工作了。主要问题出在 HTTP 响应格式上,应该定义如下:
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
我已经调整了您提供的 MCVE,请在下面找到适用于最新 Edge 和 Firefox 浏览器的工作版本。
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
try:
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
try:
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
try:
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)
我试图在端口 4460 上创建一个网络服务器,但是当我在浏览器中输入“http://127.0.0.1:4460/”时
地址栏浏览器显示 ERR_INVALID_HTTP_RESONSE.(Google Chrome)。浏览器是最新版本。
代码没有引发任何错误,也没有发送任何错误 bad_gateway requests.it 没有访问 .ico 文件。
Python ver:3.8.10
我的代码:
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
try:
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
try:
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
try:
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)
您离目标很近了。稍作调整后,您的代码段就可以正常工作了。主要问题出在 HTTP 响应格式上,应该定义如下:
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
我已经调整了您提供的 MCVE,请在下面找到适用于最新 Edge 和 Firefox 浏览器的工作版本。
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
try:
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
try:
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
try:
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)