mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-27 02:24:18 +00:00
Merge pull request #34 from mitmproxy/netlib-http1-refactor
Adjust to netlib changes
This commit is contained in:
commit
a7291a7e78
@ -1,6 +1,7 @@
|
|||||||
import pyparsing as pp
|
import pyparsing as pp
|
||||||
|
|
||||||
from netlib.http import user_agents, semantics, Headers
|
from netlib import http
|
||||||
|
from netlib.http import user_agents, Headers
|
||||||
from . import base, message
|
from . import base, message
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -184,7 +185,7 @@ class Response(_HTTP2Message):
|
|||||||
if body:
|
if body:
|
||||||
body = body.string()
|
body = body.string()
|
||||||
|
|
||||||
resp = semantics.Response(
|
resp = http.Response(
|
||||||
(2, 0),
|
(2, 0),
|
||||||
self.code.string(),
|
self.code.string(),
|
||||||
'',
|
'',
|
||||||
@ -267,7 +268,7 @@ class Request(_HTTP2Message):
|
|||||||
if body:
|
if body:
|
||||||
body = body.string()
|
body = body.string()
|
||||||
|
|
||||||
req = semantics.Request(
|
req = http.Request(
|
||||||
'',
|
'',
|
||||||
self.method.string(),
|
self.method.string(),
|
||||||
'',
|
'',
|
||||||
|
@ -63,7 +63,7 @@ class LogCtx(object):
|
|||||||
for line in netlib.utils.hexdump(data):
|
for line in netlib.utils.hexdump(data):
|
||||||
self("\t%s %s %s" % line)
|
self("\t%s %s %s" % line)
|
||||||
else:
|
else:
|
||||||
for i in netlib.utils.cleanBin(data).split("\n"):
|
for i in netlib.utils.clean_bin(data).split("\n"):
|
||||||
self("\t%s" % i)
|
self("\t%s" % i)
|
||||||
|
|
||||||
def __call__(self, line):
|
def __call__(self, line):
|
||||||
|
@ -10,8 +10,10 @@ import time
|
|||||||
import threading
|
import threading
|
||||||
|
|
||||||
import OpenSSL.crypto
|
import OpenSSL.crypto
|
||||||
|
import six
|
||||||
|
|
||||||
from netlib import tcp, http, certutils, websockets, socks
|
from netlib import tcp, http, certutils, websockets, socks
|
||||||
|
from netlib.exceptions import HttpException
|
||||||
from netlib.http import http1, http2
|
from netlib.http import http1, http2
|
||||||
|
|
||||||
import language.http
|
import language.http
|
||||||
@ -19,7 +21,7 @@ import language.websockets
|
|||||||
from . import utils, log
|
from . import utils, log
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from netlib.http.http1 import HTTP1Protocol
|
from netlib.tutils import treq
|
||||||
|
|
||||||
logging.getLogger("hpack").setLevel(logging.WARNING)
|
logging.getLogger("hpack").setLevel(logging.WARNING)
|
||||||
|
|
||||||
@ -213,7 +215,7 @@ class Pathoc(tcp.TCPClient):
|
|||||||
)
|
)
|
||||||
self.protocol = http2.HTTP2Protocol(self, dump_frames=self.http2_framedump)
|
self.protocol = http2.HTTP2Protocol(self, dump_frames=self.http2_framedump)
|
||||||
else:
|
else:
|
||||||
self.protocol = http1.HTTP1Protocol(self)
|
self.protocol = http1
|
||||||
|
|
||||||
self.settings = language.Settings(
|
self.settings = language.Settings(
|
||||||
is_client=True,
|
is_client=True,
|
||||||
@ -229,15 +231,14 @@ class Pathoc(tcp.TCPClient):
|
|||||||
'\r\n'
|
'\r\n'
|
||||||
)
|
)
|
||||||
self.wfile.flush()
|
self.wfile.flush()
|
||||||
l = self.rfile.readline()
|
try:
|
||||||
if not l:
|
resp = self.protocol.read_response(self.rfile, treq(method="CONNECT"))
|
||||||
raise PathocError("Proxy CONNECT failed")
|
if resp.status_code != 200:
|
||||||
parsed = self.protocol.parse_response_line(l)
|
raise HttpException("Unexpected status code: %s" % resp.status_code)
|
||||||
if not parsed[1] == 200:
|
except HttpException as e:
|
||||||
raise PathocError(
|
six.reraise(PathocError, PathocError(
|
||||||
"Proxy CONNECT failed: %s - %s" % (parsed[1], parsed[2])
|
"Proxy CONNECT failed: %s" % repr(e)
|
||||||
)
|
))
|
||||||
self.protocol.read_headers()
|
|
||||||
|
|
||||||
def socks_connect(self, connect_to):
|
def socks_connect(self, connect_to):
|
||||||
try:
|
try:
|
||||||
@ -288,9 +289,9 @@ class Pathoc(tcp.TCPClient):
|
|||||||
self.sslinfo = None
|
self.sslinfo = None
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
try:
|
try:
|
||||||
alpn_protos = [HTTP1Protocol.ALPN_PROTO_HTTP1]
|
alpn_protos = [http.ALPN_PROTO_HTTP1]
|
||||||
if self.use_http2:
|
if self.use_http2:
|
||||||
alpn_protos.append(http2.HTTP2Protocol.ALPN_PROTO_H2)
|
alpn_protos.append(http.ALPN_PROTO_H2)
|
||||||
|
|
||||||
self.convert_to_ssl(
|
self.convert_to_ssl(
|
||||||
sni=self.sni,
|
sni=self.sni,
|
||||||
@ -408,9 +409,9 @@ class Pathoc(tcp.TCPClient):
|
|||||||
req = language.serve(r, self.wfile, self.settings)
|
req = language.serve(r, self.wfile, self.settings)
|
||||||
self.wfile.flush()
|
self.wfile.flush()
|
||||||
|
|
||||||
resp = self.protocol.read_response(req["method"], None)
|
resp = self.protocol.read_response(self.rfile, treq(method=req["method"]))
|
||||||
resp.sslinfo = self.sslinfo
|
resp.sslinfo = self.sslinfo
|
||||||
except http.HttpError as v:
|
except HttpException as v:
|
||||||
lg("Invalid server response: %s" % v)
|
lg("Invalid server response: %s" % v)
|
||||||
raise
|
raise
|
||||||
except tcp.NetLibTimeout:
|
except tcp.NetLibTimeout:
|
||||||
|
@ -6,7 +6,8 @@ import threading
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
from netlib import tcp, http, certutils, websockets
|
from netlib import tcp, http, certutils, websockets
|
||||||
from netlib.http import http1, http2
|
from netlib.exceptions import HttpException, HttpReadDisconnect
|
||||||
|
from netlib.http import ALPN_PROTO_HTTP1, ALPN_PROTO_H2
|
||||||
|
|
||||||
from . import version, app, language, utils, log, protocols
|
from . import version, app, language, utils, log, protocols
|
||||||
import language.http
|
import language.http
|
||||||
@ -40,7 +41,7 @@ class SSLOptions(object):
|
|||||||
ssl_options=tcp.SSL_DEFAULT_OPTIONS,
|
ssl_options=tcp.SSL_DEFAULT_OPTIONS,
|
||||||
ciphers=None,
|
ciphers=None,
|
||||||
certs=None,
|
certs=None,
|
||||||
alpn_select=http2.HTTP2Protocol.ALPN_PROTO_H2,
|
alpn_select=ALPN_PROTO_H2,
|
||||||
):
|
):
|
||||||
self.confdir = confdir
|
self.confdir = confdir
|
||||||
self.cn = cn
|
self.cn = cn
|
||||||
@ -124,15 +125,14 @@ class PathodHandler(tcp.BaseHandler):
|
|||||||
"""
|
"""
|
||||||
with logger.ctx() as lg:
|
with logger.ctx() as lg:
|
||||||
try:
|
try:
|
||||||
req = self.protocol.read_request()
|
req = self.protocol.read_request(self.rfile)
|
||||||
except http.HttpError as s:
|
except HttpReadDisconnect:
|
||||||
|
return None, None
|
||||||
|
except HttpException as s:
|
||||||
s = str(s)
|
s = str(s)
|
||||||
lg(s)
|
lg(s)
|
||||||
return None, dict(type="error", msg=s)
|
return None, dict(type="error", msg=s)
|
||||||
|
|
||||||
if isinstance(req, http.EmptyRequest):
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
if req.method == 'CONNECT':
|
if req.method == 'CONNECT':
|
||||||
return self.protocol.handle_http_connect([req.host, req.port, req.httpversion], lg)
|
return self.protocol.handle_http_connect([req.host, req.port, req.httpversion], lg)
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ class PathodHandler(tcp.BaseHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
alp = self.get_alpn_proto_negotiated()
|
alp = self.get_alpn_proto_negotiated()
|
||||||
if alp == http2.HTTP2Protocol.ALPN_PROTO_H2:
|
if alp == ALPN_PROTO_H2:
|
||||||
self.protocol = protocols.http2.HTTP2Protocol(self)
|
self.protocol = protocols.http2.HTTP2Protocol(self)
|
||||||
self.use_http2 = True
|
self.use_http2 = True
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
from netlib import tcp, http, wsgi
|
from netlib import tcp, wsgi
|
||||||
from netlib.http import http1
|
from netlib.exceptions import HttpReadDisconnect
|
||||||
from .. import version, app, language, utils, log
|
from netlib.http import http1, Request
|
||||||
|
from .. import version, language
|
||||||
|
|
||||||
class HTTPProtocol:
|
|
||||||
|
|
||||||
|
class HTTPProtocol(object):
|
||||||
def __init__(self, pathod_handler):
|
def __init__(self, pathod_handler):
|
||||||
self.pathod_handler = pathod_handler
|
self.pathod_handler = pathod_handler
|
||||||
self.wire_protocol = http1.HTTP1Protocol(
|
|
||||||
self.pathod_handler
|
|
||||||
)
|
|
||||||
|
|
||||||
def make_error_response(self, reason, body):
|
def make_error_response(self, reason, body):
|
||||||
return language.http.make_error_response(reason, body)
|
return language.http.make_error_response(reason, body)
|
||||||
@ -70,4 +68,4 @@ class HTTPProtocol:
|
|||||||
return self.pathod_handler.handle_http_request, None
|
return self.pathod_handler.handle_http_request, None
|
||||||
|
|
||||||
def read_request(self, lg=None):
|
def read_request(self, lg=None):
|
||||||
return self.wire_protocol.read_request(allow_empty=True)
|
return http1.read_request(self.pathod_handler.rfile)
|
||||||
|
@ -14,7 +14,7 @@ class HTTP2Protocol:
|
|||||||
|
|
||||||
def read_request(self, lg=None):
|
def read_request(self, lg=None):
|
||||||
self.wire_protocol.perform_server_connection_preface()
|
self.wire_protocol.perform_server_connection_preface()
|
||||||
return self.wire_protocol.read_request()
|
return self.wire_protocol.read_request(self.pathod_handler.rfile)
|
||||||
|
|
||||||
def assemble(self, message):
|
def assemble(self, message):
|
||||||
return self.wire_protocol.assemble(message)
|
return self.wire_protocol.assemble(message)
|
||||||
|
@ -5,9 +5,11 @@ import OpenSSL
|
|||||||
from mock import Mock
|
from mock import Mock
|
||||||
|
|
||||||
from netlib import tcp, http, socks
|
from netlib import tcp, http, socks
|
||||||
|
from netlib.exceptions import HttpException
|
||||||
from netlib.http import http1, http2
|
from netlib.http import http1, http2
|
||||||
|
|
||||||
from libpathod import pathoc, test, version, pathod, language
|
from libpathod import pathoc, test, version, pathod, language
|
||||||
|
from netlib.tutils import raises
|
||||||
import tutils
|
import tutils
|
||||||
|
|
||||||
|
|
||||||
@ -82,7 +84,7 @@ class _TestDaemon:
|
|||||||
r = r.freeze(language.Settings())
|
r = r.freeze(language.Settings())
|
||||||
try:
|
try:
|
||||||
c.request(r)
|
c.request(r)
|
||||||
except (http.HttpError, tcp.NetLibError):
|
except (HttpException, tcp.NetLibError):
|
||||||
pass
|
pass
|
||||||
return s.getvalue()
|
return s.getvalue()
|
||||||
|
|
||||||
@ -92,7 +94,7 @@ class TestDaemonSSL(_TestDaemon):
|
|||||||
ssloptions = pathod.SSLOptions(
|
ssloptions = pathod.SSLOptions(
|
||||||
request_client_cert=True,
|
request_client_cert=True,
|
||||||
sans=["test1.com", "test2.com"],
|
sans=["test1.com", "test2.com"],
|
||||||
alpn_select=http2.HTTP2Protocol.ALPN_PROTO_H2,
|
alpn_select=http.ALPN_PROTO_H2,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_sni(self):
|
def test_sni(self):
|
||||||
@ -222,11 +224,13 @@ class TestDaemon(_TestDaemon):
|
|||||||
to = ("foobar", 80)
|
to = ("foobar", 80)
|
||||||
c = pathoc.Pathoc(("127.0.0.1", self.d.port), fp=None)
|
c = pathoc.Pathoc(("127.0.0.1", self.d.port), fp=None)
|
||||||
c.rfile, c.wfile = cStringIO.StringIO(), cStringIO.StringIO()
|
c.rfile, c.wfile = cStringIO.StringIO(), cStringIO.StringIO()
|
||||||
tutils.raises("connect failed", c.http_connect, to)
|
with raises("connect failed"):
|
||||||
|
c.http_connect(to)
|
||||||
c.rfile = cStringIO.StringIO(
|
c.rfile = cStringIO.StringIO(
|
||||||
"HTTP/1.1 500 OK\r\n"
|
"HTTP/1.1 500 OK\r\n"
|
||||||
)
|
)
|
||||||
tutils.raises("connect failed", c.http_connect, to)
|
with raises("connect failed"):
|
||||||
|
c.http_connect(to)
|
||||||
c.rfile = cStringIO.StringIO(
|
c.rfile = cStringIO.StringIO(
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
)
|
)
|
||||||
@ -273,7 +277,7 @@ class TestDaemonHTTP2(_TestDaemon):
|
|||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
("127.0.0.1", self.d.port),
|
("127.0.0.1", self.d.port),
|
||||||
)
|
)
|
||||||
assert isinstance(c.protocol, http1.HTTP1Protocol)
|
assert c.protocol == http1
|
||||||
|
|
||||||
def test_http2_alpn(self):
|
def test_http2_alpn(self):
|
||||||
c = pathoc.Pathoc(
|
c = pathoc.Pathoc(
|
||||||
|
@ -4,6 +4,7 @@ import OpenSSL
|
|||||||
|
|
||||||
from libpathod import pathod, version
|
from libpathod import pathod, version
|
||||||
from netlib import tcp, http
|
from netlib import tcp, http
|
||||||
|
from netlib.exceptions import HttpException
|
||||||
import tutils
|
import tutils
|
||||||
|
|
||||||
|
|
||||||
@ -180,16 +181,16 @@ class CommonTests(tutils.DaemonTests):
|
|||||||
|
|
||||||
def test_invalid_content_length(self):
|
def test_invalid_content_length(self):
|
||||||
tutils.raises(
|
tutils.raises(
|
||||||
http.HttpError,
|
HttpException,
|
||||||
self.pathoc,
|
self.pathoc,
|
||||||
["get:/:h'content-length'='foo'"]
|
["get:/:h'content-length'='foo'"]
|
||||||
)
|
)
|
||||||
l = self.d.last_log()
|
l = self.d.last_log()
|
||||||
assert l["type"] == "error"
|
assert l["type"] == "error"
|
||||||
assert "Content-Length unknown" in l["msg"]
|
assert "Unparseable Content Length" in l["msg"]
|
||||||
|
|
||||||
def test_invalid_headers(self):
|
def test_invalid_headers(self):
|
||||||
tutils.raises(http.HttpError, self.pathoc, ["get:/:h'\t'='foo'"])
|
tutils.raises(HttpException, self.pathoc, ["get:/:h'\t'='foo'"])
|
||||||
l = self.d.last_log()
|
l = self.d.last_log()
|
||||||
assert l["type"] == "error"
|
assert l["type"] == "error"
|
||||||
assert "Invalid headers" in l["msg"]
|
assert "Invalid headers" in l["msg"]
|
||||||
@ -247,7 +248,7 @@ class TestDaemon(CommonTests):
|
|||||||
|
|
||||||
def test_connect_err(self):
|
def test_connect_err(self):
|
||||||
tutils.raises(
|
tutils.raises(
|
||||||
http.HttpError,
|
HttpException,
|
||||||
self.pathoc,
|
self.pathoc,
|
||||||
[r"get:'http://foo.com/p/202':da"],
|
[r"get:'http://foo.com/p/202':da"],
|
||||||
connect_to=("localhost", self.d.port)
|
connect_to=("localhost", self.d.port)
|
||||||
|
Loading…
Reference in New Issue
Block a user