Ejemplo n.º 1
0
    def validate_request(self, request):
        if request.form_in == "absolute" and request.scheme != "http":
            raise HttpException("Invalid request scheme: %s" % request.scheme)

        expected_request_forms = {
            "regular": ("authority", "absolute",),
            "upstream": ("authority", "absolute"),
            "transparent": ("relative",)
        }

        allowed_request_forms = expected_request_forms[self.mode]
        if request.form_in not in allowed_request_forms:
            err_message = "Invalid HTTP request form (expected: %s, got: %s)" % (
                " or ".join(allowed_request_forms), request.form_in
            )
            raise HttpException(err_message)

        if self.mode == "regular" and request.form_in == "absolute":
            request.form_out = "relative"
Ejemplo n.º 2
0
 def http_connect(self, connect_to):
     self.wfile.write('CONNECT %s:%s HTTP/1.1\r\n' % tuple(connect_to) +
                      '\r\n')
     self.wfile.flush()
     try:
         resp = self.protocol.read_response(self.rfile,
                                            treq(method="CONNECT"))
         if resp.status_code != 200:
             raise HttpException("Unexpected status code: %s" %
                                 resp.status_code)
     except HttpException as e:
         six.reraise(PathocError,
                     PathocError("Proxy CONNECT failed: %s" % repr(e)))
Ejemplo n.º 3
0
 def read_body(io, expected_size):
     """
     Read a (malformed) HTTP body.
     Returns:
         A (body: bytes, is_malformed: bool) tuple.
     """
     body_start = io.tell()
     try:
         content = b"".join(http1.read_body(io, expected_size, None))
         if io.read():  # leftover?
             raise HttpException()
         return content, False
     except HttpException:
         io.seek(body_start)
         return io.read(), True
Ejemplo n.º 4
0
 def send_response(self, response):
     if response.content == CONTENT_MISSING:
         raise HttpException("Cannot assemble flow with CONTENT_MISSING")
     self.send_response_headers(response)
     self.send_response_body(response, [response.content])
Ejemplo n.º 5
0
    def _handle_event(self, event, source_conn, other_conn, is_server):
        self.log(
            "HTTP2 Event from {}".format("server" if is_server else "client"),
            "debug",
            [repr(event)]
        )

        if hasattr(event, 'stream_id'):
            if is_server and event.stream_id % 2 == 1:
                eid = self.server_to_client_stream_ids[event.stream_id]
            else:
                eid = event.stream_id

        if isinstance(event, events.RequestReceived):
            headers = Headers([[k, v] for k, v in event.headers])
            self.streams[eid] = Http2SingleStreamLayer(self, eid, headers)
            self.streams[eid].timestamp_start = time.time()
            self.streams[eid].start()
        elif isinstance(event, events.ResponseReceived):
            headers = Headers([[k, v] for k, v in event.headers])
            self.streams[eid].queued_data_length = 0
            self.streams[eid].timestamp_start = time.time()
            self.streams[eid].response_headers = headers
            self.streams[eid].response_arrived.set()
        elif isinstance(event, events.DataReceived):
            if self.config.body_size_limit and self.streams[eid].queued_data_length > self.config.body_size_limit:
                raise HttpException("HTTP body too large. Limit is {}.".format(self.config.body_size_limit))
            self.streams[eid].data_queue.put(event.data)
            self.streams[eid].queued_data_length += len(event.data)
            source_conn.h2.safe_increment_flow_control(event.stream_id, event.flow_controlled_length)
        elif isinstance(event, events.StreamEnded):
            self.streams[eid].timestamp_end = time.time()
            self.streams[eid].data_finished.set()
        elif isinstance(event, events.StreamReset):
            self.streams[eid].zombie = time.time()
            if eid in self.streams and event.error_code == 0x8:
                if is_server:
                    other_stream_id = self.streams[eid].client_stream_id
                else:
                    other_stream_id = self.streams[eid].server_stream_id
                if other_stream_id is not None:
                    other_conn.h2.safe_reset_stream(other_stream_id, event.error_code)
        elif isinstance(event, events.RemoteSettingsChanged):
            new_settings = dict([(id, cs.new_value) for (id, cs) in six.iteritems(event.changed_settings)])
            other_conn.h2.safe_update_settings(new_settings)
        elif isinstance(event, events.ConnectionTerminated):
            # Do not immediately terminate the other connection.
            # Some streams might be still sending data to the client.
            return False
        elif isinstance(event, events.PushedStreamReceived):
            # pushed stream ids should be unique and not dependent on race conditions
            # only the parent stream id must be looked up first
            parent_eid = self.server_to_client_stream_ids[event.parent_stream_id]
            with self.client_conn.h2.lock:
                self.client_conn.h2.push_stream(parent_eid, event.pushed_stream_id, event.headers)
                self.client_conn.send(self.client_conn.h2.data_to_send())

            headers = Headers([[str(k), str(v)] for k, v in event.headers])
            headers['x-mitmproxy-pushed'] = 'true'
            self.streams[event.pushed_stream_id] = Http2SingleStreamLayer(self, event.pushed_stream_id, headers)
            self.streams[event.pushed_stream_id].timestamp_start = time.time()
            self.streams[event.pushed_stream_id].pushed = True
            self.streams[event.pushed_stream_id].parent_stream_id = parent_eid
            self.streams[event.pushed_stream_id].timestamp_end = time.time()
            self.streams[event.pushed_stream_id].request_data_finished.set()
            self.streams[event.pushed_stream_id].start()
        elif isinstance(event, events.PriorityUpdated):
            stream_id = event.stream_id
            if stream_id in self.streams.keys() and self.streams[stream_id].server_stream_id:
                stream_id = self.streams[stream_id].server_stream_id

            depends_on = event.depends_on
            if depends_on in self.streams.keys() and self.streams[depends_on].server_stream_id:
                depends_on = self.streams[depends_on].server_stream_id

            # weight is between 1 and 256 (inclusive), but represented as uint8 (0 to 255)
            frame = PriorityFrame(stream_id, depends_on, event.weight - 1, event.exclusive)
            self.server_conn.send(frame.serialize())
        elif isinstance(event, events.TrailersReceived):
            raise NotImplementedError()

        return True
Ejemplo n.º 6
0
    def _handle_event(self, event, source_conn, other_conn, is_server):
        if hasattr(event, 'stream_id'):
            if is_server and event.stream_id % 2 == 1:
                eid = self.server_to_client_stream_ids[event.stream_id]
            else:
                eid = event.stream_id

        if isinstance(event, RequestReceived):
            headers = Headers([[str(k), str(v)] for k, v in event.headers])
            self.streams[eid] = Http2SingleStreamLayer(self, eid, headers)
            self.streams[eid].timestamp_start = time.time()
            self.streams[eid].start()
        elif isinstance(event, ResponseReceived):
            headers = Headers([[str(k), str(v)] for k, v in event.headers])
            self.streams[eid].queued_data_length = 0
            self.streams[eid].timestamp_start = time.time()
            self.streams[eid].response_headers = headers
            self.streams[eid].response_arrived.set()
        elif isinstance(event, DataReceived):
            if self.config.body_size_limit and self.streams[
                    eid].queued_data_length > self.config.body_size_limit:
                raise HttpException("HTTP body too large. Limit is {}.".format(
                    self.config.body_size_limit))
            self.streams[eid].data_queue.put(event.data)
            self.streams[eid].queued_data_length += len(event.data)
            source_conn.h2.safe_increment_flow_control(
                event.stream_id, event.flow_controlled_length)
        elif isinstance(event, StreamEnded):
            self.streams[eid].timestamp_end = time.time()
            self.streams[eid].data_finished.set()
        elif isinstance(event, StreamReset):
            self.streams[eid].zombie = time.time()
            if eid in self.streams and event.error_code == 0x8:
                if is_server:
                    other_stream_id = self.streams[eid].client_stream_id
                else:
                    other_stream_id = self.streams[eid].server_stream_id
                if other_stream_id is not None:
                    other_conn.h2.safe_reset_stream(other_stream_id,
                                                    event.error_code)
        elif isinstance(event, RemoteSettingsChanged):
            new_settings = dict([
                (id, cs.new_value)
                for (id, cs) in event.changed_settings.iteritems()
            ])
            other_conn.h2.safe_update_settings(new_settings)
        elif isinstance(event, ConnectionTerminated):
            # Do not immediately terminate the other connection.
            # Some streams might be still sending data to the client.
            return False
        elif isinstance(event, PushedStreamReceived):
            # pushed stream ids should be uniq and not dependent on race conditions
            # only the parent stream id must be looked up first
            parent_eid = self.server_to_client_stream_ids[
                event.parent_stream_id]
            with self.client_conn.h2.lock:
                self.client_conn.h2.push_stream(parent_eid,
                                                event.pushed_stream_id,
                                                event.headers)

            headers = Headers([[str(k), str(v)] for k, v in event.headers])
            headers['x-mitmproxy-pushed'] = 'true'
            self.streams[event.pushed_stream_id] = Http2SingleStreamLayer(
                self, event.pushed_stream_id, headers)
            self.streams[event.pushed_stream_id].timestamp_start = time.time()
            self.streams[event.pushed_stream_id].pushed = True
            self.streams[event.pushed_stream_id].parent_stream_id = parent_eid
            self.streams[event.pushed_stream_id].timestamp_end = time.time()
            self.streams[event.pushed_stream_id].request_data_finished.set()
            self.streams[event.pushed_stream_id].start()
        elif isinstance(event, TrailersReceived):
            raise NotImplementedError()

        return True
Ejemplo n.º 7
0
 def send_response(self, response):
     if response.content is None:
         raise HttpException("Cannot assemble flow with missing content")
     self.send_response_headers(response)
     self.send_response_body(response, [response.content])