mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 18:18:25 +00:00
commit
698f7e2e17
@ -1,8 +1,43 @@
|
|||||||
import re
|
import re
|
||||||
|
import mimetypes
|
||||||
|
from urllib.parse import quote
|
||||||
from mitmproxy.net.http import headers
|
from mitmproxy.net.http import headers
|
||||||
|
|
||||||
|
|
||||||
|
def encode(head, l):
|
||||||
|
|
||||||
|
k = head.get("content-type")
|
||||||
|
if k:
|
||||||
|
k = headers.parse_content_type(k)
|
||||||
|
if k is not None:
|
||||||
|
try:
|
||||||
|
boundary = k[2]["boundary"].encode("ascii")
|
||||||
|
boundary = quote(boundary)
|
||||||
|
except (KeyError, UnicodeError):
|
||||||
|
return b""
|
||||||
|
hdrs = []
|
||||||
|
for key, value in l:
|
||||||
|
file_type = mimetypes.guess_type(str(key))[0] or "text/plain; charset=utf-8"
|
||||||
|
|
||||||
|
if key:
|
||||||
|
hdrs.append(b"--%b" % boundary.encode('utf-8'))
|
||||||
|
disposition = b'form-data; name="%b"' % key
|
||||||
|
hdrs.append(b"Content-Disposition: %b" % disposition)
|
||||||
|
hdrs.append(b"Content-Type: %b" % file_type.encode('utf-8'))
|
||||||
|
hdrs.append(b'')
|
||||||
|
hdrs.append(value)
|
||||||
|
hdrs.append(b'')
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
# If boundary is found in value then raise ValueError
|
||||||
|
if re.search(rb"^--%b$" % re.escape(boundary.encode('utf-8')), value):
|
||||||
|
raise ValueError(b"boundary found in encoded string")
|
||||||
|
|
||||||
|
hdrs.append(b"--%b--\r\n" % boundary.encode('utf-8'))
|
||||||
|
temp = b"\r\n".join(hdrs)
|
||||||
|
return temp
|
||||||
|
|
||||||
|
|
||||||
def decode(hdrs, content):
|
def decode(hdrs, content):
|
||||||
"""
|
"""
|
||||||
Takes a multipart boundary encoded string and returns list of (key, value) tuples.
|
Takes a multipart boundary encoded string and returns list of (key, value) tuples.
|
||||||
@ -19,7 +54,7 @@ def decode(hdrs, content):
|
|||||||
|
|
||||||
rx = re.compile(br'\bname="([^"]+)"')
|
rx = re.compile(br'\bname="([^"]+)"')
|
||||||
r = []
|
r = []
|
||||||
|
if content is not None:
|
||||||
for i in content.split(b"--" + boundary):
|
for i in content.split(b"--" + boundary):
|
||||||
parts = i.splitlines()
|
parts = i.splitlines()
|
||||||
if len(parts) > 1 and parts[0][0:2] != b"--":
|
if len(parts) > 1 and parts[0][0:2] != b"--":
|
||||||
|
@ -472,7 +472,8 @@ class Request(message.Message):
|
|||||||
return ()
|
return ()
|
||||||
|
|
||||||
def _set_multipart_form(self, value):
|
def _set_multipart_form(self, value):
|
||||||
raise NotImplementedError()
|
self.content = mitmproxy.net.http.multipart.encode(self.headers, value)
|
||||||
|
self.headers["content-type"] = "multipart/form-data"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def multipart_form(self):
|
def multipart_form(self):
|
||||||
|
@ -381,7 +381,8 @@ class ConsoleAddon:
|
|||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
"cookies",
|
"cookies",
|
||||||
"form",
|
"urlencoded form",
|
||||||
|
"multipart form",
|
||||||
"path",
|
"path",
|
||||||
"method",
|
"method",
|
||||||
"query",
|
"query",
|
||||||
@ -416,8 +417,10 @@ class ConsoleAddon:
|
|||||||
flow.response = http.HTTPResponse.make()
|
flow.response = http.HTTPResponse.make()
|
||||||
if part == "cookies":
|
if part == "cookies":
|
||||||
self.master.switch_view("edit_focus_cookies")
|
self.master.switch_view("edit_focus_cookies")
|
||||||
elif part == "form":
|
elif part == "urlencoded form":
|
||||||
self.master.switch_view("edit_focus_form")
|
self.master.switch_view("edit_focus_urlencoded_form")
|
||||||
|
elif part == "multipart form":
|
||||||
|
self.master.switch_view("edit_focus_multipart_form")
|
||||||
elif part == "path":
|
elif part == "path":
|
||||||
self.master.switch_view("edit_focus_path")
|
self.master.switch_view("edit_focus_path")
|
||||||
elif part == "query":
|
elif part == "query":
|
||||||
|
@ -53,14 +53,30 @@ class ResponseHeaderEditor(HeaderEditor):
|
|||||||
flow.response.headers = Headers(vals)
|
flow.response.headers = Headers(vals)
|
||||||
|
|
||||||
|
|
||||||
class RequestFormEditor(base.FocusEditor):
|
class RequestMultipartEditor(base.FocusEditor):
|
||||||
title = "Edit URL-encoded Form"
|
title = "Edit Multipart Form"
|
||||||
columns = [
|
columns = [
|
||||||
col_text.Column("Key"),
|
col_text.Column("Key"),
|
||||||
col_text.Column("Value")
|
col_text.Column("Value")
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_data(self, flow):
|
def get_data(self, flow):
|
||||||
|
|
||||||
|
return flow.request.multipart_form.items(multi=True)
|
||||||
|
|
||||||
|
def set_data(self, vals, flow):
|
||||||
|
flow.request.multipart_form = vals
|
||||||
|
|
||||||
|
|
||||||
|
class RequestUrlEncodedEditor(base.FocusEditor):
|
||||||
|
title = "Edit UrlEncoded Form"
|
||||||
|
columns = [
|
||||||
|
col_text.Column("Key"),
|
||||||
|
col_text.Column("Value")
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_data(self, flow):
|
||||||
|
|
||||||
return flow.request.urlencoded_form.items(multi=True)
|
return flow.request.urlencoded_form.items(multi=True)
|
||||||
|
|
||||||
def set_data(self, vals, flow):
|
def set_data(self, vals, flow):
|
||||||
|
@ -64,7 +64,8 @@ class WindowStack:
|
|||||||
edit_focus_cookies = grideditor.CookieEditor(master),
|
edit_focus_cookies = grideditor.CookieEditor(master),
|
||||||
edit_focus_setcookies = grideditor.SetCookieEditor(master),
|
edit_focus_setcookies = grideditor.SetCookieEditor(master),
|
||||||
edit_focus_setcookie_attrs = grideditor.CookieAttributeEditor(master),
|
edit_focus_setcookie_attrs = grideditor.CookieAttributeEditor(master),
|
||||||
edit_focus_form = grideditor.RequestFormEditor(master),
|
edit_focus_multipart_form=grideditor.RequestMultipartEditor(master),
|
||||||
|
edit_focus_urlencoded_form=grideditor.RequestUrlEncodedEditor(master),
|
||||||
edit_focus_path = grideditor.PathEditor(master),
|
edit_focus_path = grideditor.PathEditor(master),
|
||||||
edit_focus_request_headers = grideditor.RequestHeaderEditor(master),
|
edit_focus_request_headers = grideditor.RequestHeaderEditor(master),
|
||||||
edit_focus_response_headers = grideditor.ResponseHeaderEditor(master),
|
edit_focus_response_headers = grideditor.ResponseHeaderEditor(master),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from mitmproxy.net.http import Headers
|
from mitmproxy.net.http import Headers
|
||||||
from mitmproxy.net.http import multipart
|
from mitmproxy.net.http import multipart
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
def test_decode():
|
def test_decode():
|
||||||
@ -22,3 +23,39 @@ def test_decode():
|
|||||||
assert len(form) == 2
|
assert len(form) == 2
|
||||||
assert form[0] == (b"field1", b"value1")
|
assert form[0] == (b"field1", b"value1")
|
||||||
assert form[1] == (b"field2", b"value2")
|
assert form[1] == (b"field2", b"value2")
|
||||||
|
|
||||||
|
boundary = 'boundary茅莽'
|
||||||
|
headers = Headers(
|
||||||
|
content_type='multipart/form-data; boundary=' + boundary
|
||||||
|
)
|
||||||
|
result = multipart.decode(headers, content)
|
||||||
|
assert result == []
|
||||||
|
|
||||||
|
headers = Headers(
|
||||||
|
content_type=''
|
||||||
|
)
|
||||||
|
assert multipart.decode(headers, content) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_encode():
|
||||||
|
data = [("file".encode('utf-8'), "shell.jpg".encode('utf-8')),
|
||||||
|
("file_size".encode('utf-8'), "1000".encode('utf-8'))]
|
||||||
|
headers = Headers(
|
||||||
|
content_type='multipart/form-data; boundary=127824672498'
|
||||||
|
)
|
||||||
|
content = multipart.encode(headers, data)
|
||||||
|
|
||||||
|
assert b'Content-Disposition: form-data; name="file"' in content
|
||||||
|
assert b'Content-Type: text/plain; charset=utf-8\r\n\r\nshell.jpg\r\n\r\n--127824672498\r\n' in content
|
||||||
|
assert b'1000\r\n\r\n--127824672498--\r\n'
|
||||||
|
assert len(content) == 252
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match=r"boundary found in encoded string"):
|
||||||
|
multipart.encode(headers, [("key".encode('utf-8'), "--127824672498".encode('utf-8'))])
|
||||||
|
|
||||||
|
boundary = 'boundary茅莽'
|
||||||
|
headers = Headers(
|
||||||
|
content_type='multipart/form-data; boundary=' + boundary
|
||||||
|
)
|
||||||
|
result = multipart.encode(headers, data)
|
||||||
|
assert result == b''
|
||||||
|
@ -371,6 +371,7 @@ class TestRequestUtils:
|
|||||||
assert list(request.multipart_form.items()) == []
|
assert list(request.multipart_form.items()) == []
|
||||||
|
|
||||||
def test_set_multipart_form(self):
|
def test_set_multipart_form(self):
|
||||||
request = treq(content=b"foobar")
|
request = treq()
|
||||||
with pytest.raises(NotImplementedError):
|
request.multipart_form = [("file", "shell.jpg"), ("file_size", "1000")]
|
||||||
request.multipart_form = "foobar"
|
assert request.headers["Content-Type"] == 'multipart/form-data'
|
||||||
|
assert request.content is None
|
||||||
|
Loading…
Reference in New Issue
Block a user