proxy.py/proxy/http/inspector/transformer.py

166 lines
5.8 KiB
Python

# -*- coding: utf-8 -*-
"""
proxy.py
~~~~~~~~
⚡⚡⚡ Fast, Lightweight, Pluggable, TLS interception capable proxy server focused on
Network monitoring, controls & Application development, testing, debugging.
:copyright: (c) 2013-present by Abhinav Singh and contributors.
:license: BSD, see LICENSE for more details.
"""
import json
import time
from typing import TYPE_CHECKING, Any, Dict
from ..websocket import WebsocketFrame
from ...core.event import eventNames
from ...common.utils import bytes_
from ...common.constants import (
PROXY_PY_START_TIME, DEFAULT_DEVTOOLS_DOC_URL, DEFAULT_DEVTOOLS_FRAME_ID,
DEFAULT_DEVTOOLS_LOADER_ID,
)
if TYPE_CHECKING: # pragma: no cover
from ..connection import HttpClientConnection
class CoreEventsToDevtoolsProtocol:
"""Open in Chrome
``devtools://devtools/bundled/inspector.html?ws=localhost:8899/devtools``
"""
RESPONSES: Dict[str, bytes] = {}
@staticmethod
def transformer(
client: 'HttpClientConnection',
event: Dict[str, Any],
) -> None:
event_name = event['event_name']
if event_name == eventNames.REQUEST_COMPLETE:
data = CoreEventsToDevtoolsProtocol.request_complete(event)
elif event_name == eventNames.RESPONSE_HEADERS_COMPLETE:
data = CoreEventsToDevtoolsProtocol.response_headers_complete(
event,
)
elif event_name == eventNames.RESPONSE_CHUNK_RECEIVED:
data = CoreEventsToDevtoolsProtocol.response_chunk_received(event)
elif event_name == eventNames.RESPONSE_COMPLETE:
data = CoreEventsToDevtoolsProtocol.response_complete(event)
else:
# drop core events unrelated to Devtools
return
client.queue(
memoryview(
WebsocketFrame.text(
bytes_(
json.dumps(data),
),
),
),
)
@staticmethod
def request_complete(event: Dict[str, Any]) -> Dict[str, Any]:
now = time.time()
return {
'method': 'Network.requestWillBeSent',
'params': {
'requestId': event['request_id'],
'frameId': DEFAULT_DEVTOOLS_FRAME_ID,
'loaderId': DEFAULT_DEVTOOLS_LOADER_ID,
'documentURL': DEFAULT_DEVTOOLS_DOC_URL,
'timestamp': now - PROXY_PY_START_TIME,
'wallTime': now,
'hasUserGesture': False,
'type': event['event_payload']['headers']['content-type']
if 'content-type' in event['event_payload']['headers']
else 'Other',
'request': {
'url': event['event_payload']['url'],
'method': event['event_payload']['method'],
'headers': event['event_payload']['headers'],
'postData': event['event_payload']['body'],
'initialPriority': 'High',
'urlFragment': '',
'mixedContentType': 'none',
},
'initiator': {
'type': 'other',
},
},
}
@staticmethod
def response_headers_complete(event: Dict[str, Any]) -> Dict[str, Any]:
return {
'method': 'Network.responseReceived',
'params': {
'requestId': event['request_id'],
'frameId': DEFAULT_DEVTOOLS_FRAME_ID,
'loaderId': DEFAULT_DEVTOOLS_LOADER_ID,
'timestamp': time.time(),
'type': event['event_payload']['headers']['content-type']
if event['event_payload']['headers'].has_header('content-type')
else 'Other',
'response': {
'url': '',
'status': '',
'statusText': '',
'headers': '',
'headersText': '',
'mimeType': '',
'connectionReused': True,
'connectionId': '',
'encodedDataLength': '',
'fromDiskCache': False,
'fromServiceWorker': False,
'timing': {
'requestTime': '',
'proxyStart': -1,
'proxyEnd': -1,
'dnsStart': -1,
'dnsEnd': -1,
'connectStart': -1,
'connectEnd': -1,
'sslStart': -1,
'sslEnd': -1,
'workerStart': -1,
'workerReady': -1,
'sendStart': 0,
'sendEnd': 0,
'receiveHeadersEnd': 0,
},
'requestHeaders': '',
'remoteIPAddress': '',
'remotePort': '',
},
},
}
@staticmethod
def response_chunk_received(event: Dict[str, Any]) -> Dict[str, Any]:
return {
'method': 'Network.dataReceived',
'params': {
'requestId': event['request_id'],
'timestamp': time.time(),
'dataLength': event['event_payload']['chunk_size'],
'encodedDataLength': event['event_payload']['encoded_chunk_size'],
},
}
@staticmethod
def response_complete(event: Dict[str, Any]) -> Dict[str, Any]:
return {
'method': 'Network.loadingFinished',
'params': {
'requestId': event['request_id'],
'timestamp': time.time(),
'encodedDataLength': event['event_payload']['encoded_response_size'],
'shouldReportCorbBlocking': False,
},
}