示例#1
0
    def __call__(self, addr):
        '''Since an instance of HttpServer is passed to the Service
        class (with appropriate request_handler established during
        initialization), this __call__ method is what's actually
        invoked by diesel.
        '''
        data = None
        while True:
            try:
                h = HttpParser()
                body = []
                while True:
                    if data:
                        used = h.execute(data, len(data))
                        if h.is_headers_complete():
                            body.append(h.recv_body())
                        if h.is_message_complete():
                            data = data[used:]
                            break
                    data = receive()

                env = h.get_wsgi_environ()
                if 'HTTP_CONTENT_LENGTH' in env:
                    env['CONTENT_LENGTH'] = env.pop("HTTP_CONTENT_LENGTH")
                if 'HTTP_CONTENT_TYPE' in env:
                    env['CONTENT_TYPE'] = env.pop("HTTP_CONTENT_TYPE")

                env.update({
                    'wsgi.version': (1, 0),
                    'wsgi.url_scheme': 'http',  # XXX incomplete
                    'wsgi.input': cStringIO.StringIO(''.join(body)),
                    'wsgi.errors': FileLikeErrorLogger(hlog),
                    'wsgi.multithread': False,
                    'wsgi.multiprocess': False,
                    'wsgi.run_once': False,
                    'REMOTE_ADDR': addr[0],
                    'SERVER_NAME': HOSTNAME,
                    'SERVER_PORT': str(self.port),
                })
                req = Request(env)

                resp = self.request_handler(req)
                if 'Server' not in resp.headers:
                    resp.headers.add('Server', SERVER_TAG)
                if 'Date' not in resp.headers:
                    resp.headers.add(
                        'Date',
                        utcnow().strftime("%a, %d %b %Y %H:%M:%S UTC"))

                assert resp, "HTTP request handler _must_ return a response"

                self.send_response(resp, version=h.get_version())

                if (not h.should_keep_alive()) or \
                    resp.headers.get('Connection', '').lower() == "close" or \
                    resp.headers.get('Content-Length') == None:
                    return

            except ConnectionClosed:
                break
示例#2
0
def get_headers_data(data):
    """ """
    parser = HttpParser()
    parser.execute(data, len(data))
    url = parser.get_url()
    method = parser.get_method()
    if method == 'CONNECT':
        host, _, port = url.partition(":")
    else:
        url = urlparse(url)
        host, _, port = url.netloc.partition(":")
    port = port and port.isdigit() and int(port) or 80
    return (host, port), method, parser.get_version()
示例#3
0
文件: http.py 项目: HVF/diesel
    def __call__(self, addr):
        '''Since an instance of HttpServer is passed to the Service
        class (with appropriate request_handler established during
        initialization), this __call__ method is what's actually
        invoked by diesel.
        '''
        data = None
        while True:
            try:
                h = HttpParser()
                body = []
                while True:
                    if data:
                        used = h.execute(data, len(data))
                        if h.is_headers_complete():
                            body.append(h.recv_body())
                        if h.is_message_complete():
                            data = data[used:]
                            break
                    data = receive()

                env = h.get_wsgi_environ()

                env.update({
                    'wsgi.version' : (1,0),
                    'wsgi.url_scheme' : 'http', # XXX incomplete
                    'wsgi.input' : cStringIO.StringIO(''.join(body)),
                    'wsgi.errors' : FileLikeErrorLogger(hlog),
                    'wsgi.multithread' : False,
                    'wsgi.multiprocess' : False,
                    'wsgi.run_once' : False,
                    })
                req = Request(env)

                resp = self.request_handler(req)
                if 'Server' not in resp.headers:
                    resp.headers.add('Server', SERVER_TAG)
                if 'Date' not in resp.headers:
                    resp.headers.add('Date', utcnow().strftime("%a, %d %b %Y %H:%M:%S UTC"))

                assert resp, "HTTP request handler _must_ return a response"

                self.send_response(resp, version=h.get_version())

                if (not h.should_keep_alive()) or \
                    resp.headers.get('Connection', '').lower() == "close" or \
                    resp.headers.get('Content-Length') == None:
                    return

            except ConnectionClosed:
                break
示例#4
0
class HttpStream(object):
    """ An HTTP parser providing higher-level access to a readable,
    sequential io.RawIOBase object. You can use implementions of
    http_parser.reader (IterReader, StringReader, SocketReader) or
    create your own.
    """

    def __init__(self, stream, kind=HTTP_BOTH, decompress=False):
        """ constructor of HttpStream.

        :attr stream: an io.RawIOBase object
        :attr kind: Int,  could be 0 to parseonly requests,
        1 to parse only responses or 2 if we want to let
        the parser detect the type.
        """
        self.parser = HttpParser(kind=kind, decompress=decompress)
        self.stream = stream

    def _check_headers_complete(self):
        if self.parser.is_headers_complete():
            return

        while True:
            try:
                next(self)
            except StopIteration:
                if self.parser.is_headers_complete():
                    return
                raise NoMoreData("Can't parse headers")

            if self.parser.is_headers_complete():
                return


    def _wait_status_line(self, cond):
        if self.parser.is_headers_complete():
            return True

        data = []
        if not cond():
            while True:
                try:
                    d = next(self)
                    data.append(d)
                except StopIteration:
                    if self.parser.is_headers_complete():
                        return True
                    raise BadStatusLine(b"".join(data))
                if cond():
                    return True
        return True

    def _wait_on_url(self):
        return self._wait_status_line(self.parser.get_url)

    def _wait_on_status(self):
        return self._wait_status_line(self.parser.get_status_code)

    def url(self):
        """ get full url of the request """
        self._wait_on_url()
        return self.parser.get_url()

    def path(self):
        """ get path of the request (url without query string and
        fragment """
        self._wait_on_url()
        return self.parser.get_path()

    def query_string(self):
        """ get query string of the url """
        self._wait_on_url()
        return self.parser.get_query_string()

    def fragment(self):
        """ get fragment of the url """
        self._wait_on_url()
        return self.parser.get_fragment()

    def version(self):
        self._wait_on_status()
        return self.parser.get_version()

    def status_code(self):
        """ get status code of a response as integer """
        self._wait_on_status()
        return self.parser.get_status_code()

    def status(self):
        """ return complete status with reason """
        status_code = self.status_code()
        reason = status_reasons.get(int(status_code), 'unknown')
        return "%s %s" % (status_code, reason)


    def method(self):
        """ get HTTP method as string"""
        self._wait_on_status()
        return self.parser.get_method()

    def headers(self):
        """ get request/response headers, headers are returned in a
        OrderedDict that allows you to get value using insensitive
        keys."""
        self._check_headers_complete()
        return self.parser.get_headers()

    def should_keep_alive(self):
        """ return True if the connection should be kept alive
        """
        self._check_headers_complete()
        return self.parser.should_keep_alive()

    def is_chunked(self):
        """ return True if Transfer-Encoding header value is chunked"""
        self._check_headers_complete()
        return self.parser.is_chunked()

    def wsgi_environ(self, initial=None):
        """ get WSGI environ based on the current request.

        :attr initial: dict, initial values to fill in environ.
        """
        self._check_headers_complete()
        return self.parser.get_wsgi_environ()

    def body_file(self, buffering=None, binary=True, encoding=None,
            errors=None, newline=None):
        """ return the body as a buffered stream object. If binary is
        true an io.BufferedReader will be returned, else an
        io.TextIOWrapper.
        """
        self._check_headers_complete()

        if buffering is None:
            buffering = -1
        if buffering < 0:
            buffering = DEFAULT_BUFFER_SIZE

        raw = HttpBodyReader(self)
        buf = BufferedReader(raw, buffering)
        if binary:
            return buf
        text = TextIOWrapper(buf, encoding, errors, newline)
        return text

    def body_string(self, binary=True, encoding=None, errors=None,
            newline=None):
        """ return body as string """
        return self.body_file(binary=binary, encoding=encoding,
                newline=newline).read()

    def __iter__(self):
        return self

    def __next__(self):
        if self.parser.is_message_complete():
            raise StopIteration

        # fetch data
        b = bytearray(DEFAULT_BUFFER_SIZE)
        recved = self.stream.readinto(b)
        if recved is None:
            raise NoMoreData("no more data")

        del b[recved:]
        to_parse = bytes(b)
        # parse data
        nparsed = self.parser.execute(to_parse, recved)
        if nparsed != recved and not self.parser.is_message_complete():
            raise ParserError("nparsed != recved (%s != %s) [%s]" % (nparsed,
                recved, bytes_to_str(to_parse)))

        if recved == 0:
            raise StopIteration

        return to_parse

    next = __next__
示例#5
0
文件: core.py 项目: 1angxi/diesel
    def __call__(self, addr):
        '''Since an instance of HttpServer is passed to the Service
        class (with appropriate request_handler established during
        initialization), this __call__ method is what's actually
        invoked by diesel.
        '''
        data = None
        while True:
            try:
                h = HttpParser()
                body = []
                while True:
                    if data:
                        used = h.execute(data, len(data))
                        if h.is_headers_complete():
                            body.append(h.recv_body())
                        if h.is_message_complete():
                            data = data[used:]
                            break
                    data = receive()

                env = h.get_wsgi_environ()
                if 'HTTP_CONTENT_LENGTH' in env:
                    env['CONTENT_LENGTH'] = env.pop("HTTP_CONTENT_LENGTH")
                if 'HTTP_CONTENT_TYPE' in env:
                    env['CONTENT_TYPE'] = env.pop("HTTP_CONTENT_TYPE")

                env.update({
                    'wsgi.version' : (1,0),
                    'wsgi.url_scheme' : 'http', # XXX incomplete
                    'wsgi.input' : cStringIO.StringIO(''.join(body)),
                    'wsgi.errors' : FileLikeErrorLogger(hlog),
                    'wsgi.multithread' : False,
                    'wsgi.multiprocess' : False,
                    'wsgi.run_once' : False,
                    'REMOTE_ADDR' : addr[0],
                    'SERVER_NAME' : HOSTNAME,
                    'SERVER_PORT': str(self.port),
                    })
                req = Request(env)
                if req.headers.get('Connection', '').lower() == 'upgrade':
                    req.data = data

                resp = self.request_handler(req)
                if 'Server' not in resp.headers:
                    resp.headers.add('Server', SERVER_TAG)
                if 'Date' not in resp.headers:
                    resp.headers.add('Date', utcnow().strftime("%a, %d %b %Y %H:%M:%S UTC"))

                assert resp, "HTTP request handler _must_ return a response"

                self.send_response(resp, version=h.get_version())

                if (not h.should_keep_alive()) or \
                    resp.headers.get('Connection', '').lower() == "close" or \
                    resp.headers.get('Content-Length') == None:
                    return

                # Switching Protocols
                if resp.status_code == 101 and hasattr(resp, 'new_protocol'):
                    resp.new_protocol(req)
                    break

            except ConnectionClosed:
                break
示例#6
0
文件: protocol.py 项目: dstufft/stein
class HTTPProtocol(FlowControlMixin, asyncio.Protocol):

    def __init__(self, stream_reader, callback, loop=None):
        super().__init__(loop=loop)
        self._stream_reader = stream_reader
        self._stream_writer = None

        self._callback = callback
        self._task = None

        self._server = None

    def connection_made(self, transport):
        self._parser = HttpParser()

        self._stream_reader.set_transport(transport)
        self._stream_writer = asyncio.StreamWriter(
            transport,
            self,
            self._stream_reader,
            self._loop,
        )

        # Grab the name of our socket if we have it
        self._server = transport.get_extra_info("sockname")

    def connection_lost(self, exc):
        if exc is None:
            self._stream_reader.feed_eof()
        else:
            self._stream_reader.set_exception(exc)

        super().connection_lost(exc)

    def data_received(self, data):
        # Parse our incoming data with our HTTP parser
        self._parser.execute(data, len(data))

        # If we have not already handled the headers and we've gotten all of
        # them, then invoke the callback with the headers in them.
        if self._task is None and self._parser.is_headers_complete():
            coro = self.dispatch(
                {
                    "server": self._server,
                    "protocol": b"HTTP/" + b".".join(
                        str(x).encode("ascii")
                        for x in self._parser.get_version()
                    ),
                    "method": self._parser.get_method().encode("latin1"),
                    "path": self._parser.get_path().encode("latin1"),
                    "query": self._parser.get_query_string().encode("latin1"),
                    "headers": self._parser.get_headers(),
                },
                self._stream_reader,
                self._stream_writer,
            )
            self._task = asyncio.Task(coro, loop=self._loop)

        # Determine if we have any data in the body buffer and if so feed it
        # to our StreamReader
        if self._parser.is_partial_body():
            self._stream_reader.feed_data(self._parser.recv_body())

        # Determine if we've completed the end of the HTTP request, if we have
        # then we should close our stream reader because there is nothing more
        # to read.
        if self._parser.is_message_complete():
            self._stream_reader.feed_eof()

    def eof_received(self):
        # We've gotten an EOF from the client, so we'll propagate this to our
        # StreamReader
        self._stream_reader.feed_eof()

    @asyncio.coroutine
    def dispatch(self, request, request_body, response):
        # Get the status, headers, and body from the callback. The body must
        # be iterable, and each item can either be a bytes object, or an
        # asyncio coroutine, in which case we'll ``yield from`` on it to wait
        # for it's value.
        status, resp_headers, body = yield from self._callback(
            request,
            request_body,
        )

        # Write out the status line to the client for this request
        # TODO: We probably don't want to hard code HTTP/1.1 here
        response.write(b"HTTP/1.1 " + status + b"\r\n")

        # Write out the headers, taking special care to ensure that any
        # mandatory headers are added.
        # TODO: We need to handle some required headers
        for key, values in resp_headers.items():
            # In order to handle headers which need to have multiple values
            # like Set-Cookie, we allow the value of the header to be an
            # iterable instead of a bytes object, in which case we'll write
            # multiple header lines for this header.
            if isinstance(values, (bytes, bytearray)):
                values = [values]

            for value in values:
                response.write(key + b": " + value + b"\r\n")

        # Before we get to the body, we need to write a blank line to separate
        # the headers and the response body
        response.write(b"\r\n")

        for chunk in body:
            # If the chunk is a coroutine, then we want to wait for the result
            # before we write it.
            if asyncio.iscoroutine(chunk):
                chunk = yield from chunk

            # Write our chunk out to the connect client
            response.write(chunk)

        # We've written everything in our iterator, so we want to close the
        # connection.
        response.close()
示例#7
0
文件: http.py 项目: bjornua/dna
class HttpStream(object):
    """ An HTTP parser providing higher-level access to a readable,
    sequential io.RawIOBase object. You can use implementions of
    http_parser.reader (IterReader, StringReader, SocketReader) or 
    create your own.
    """
    def __init__(self, stream, kind=HTTP_BOTH, decompress=False):
        """ constructor of HttpStream. 

        :attr stream: an io.RawIOBase object
        :attr kind: Int,  could be 0 to parseonly requests, 
        1 to parse only responses or 2 if we want to let
        the parser detect the type.
        """
        self.parser = HttpParser(kind=kind, decompress=decompress)
        self.stream = stream

    def _check_headers_complete(self):
        if self.parser.is_headers_complete():
            return

        while True:
            try:
                data = self.next()
            except StopIteration:
                if self.parser.is_headers_complete():
                    return
                raise NoMoreData()

            if self.parser.is_headers_complete():
                return

    def url(self):
        """ get full url of the request """
        self._check_headers_complete()
        return self.parser.get_url()

    def path(self):
        """ get path of the request (url without query string and
        fragment """
        self._check_headers_complete()
        return self.parser.get_path()

    def query_string(self):
        """ get query string of the url """
        self._check_headers_complete()
        return self.parser.get_query_string()

    def fragment(self):
        """ get fragment of the url """
        self._check_headers_complete()
        return self.parser.get_fragment()

    def version(self):
        self._check_headers_complete()
        return self.parser.get_version()

    def status_code(self):
        """ get status code of a response as integer """
        self._check_headers_complete()
        return self.parser.get_status_code()

    def status(self):
        """ return complete status with reason """
        status_code = self.status_code()
        reason = status_reasons.get(int(status_code), 'unknown')
        return "%s %s" % (status_code, reason)

    def method(self):
        """ get HTTP method as string"""
        self._check_headers_complete()
        return self.parser.get_method()

    def headers(self):
        """ get request/response headers, headers are returned in a
        OrderedDict that allows you to get value using insensitive
        keys."""
        self._check_headers_complete()
        return self.parser.get_headers()

    def should_keep_alive(self):
        """ return True if the connection should be kept alive
        """
        self._check_headers_complete()
        return self.parser.should_keep_alive()

    def is_chunked(self):
        """ return True if Transfer-Encoding header value is chunked"""
        self._check_headers_complete()
        return self.parser.is_chunked()

    def wsgi_environ(self, initial=None):
        """ get WSGI environ based on the current request.
        
        :attr initial: dict, initial values to fill in environ.
        """
        self._check_headers_complete()
        return self.parser.get_wsgi_environ()

    def body_file(self,
                  buffering=None,
                  binary=True,
                  encoding=None,
                  errors=None,
                  newline=None):
        """ return the body as a buffered stream object. If binary is
        true an io.BufferedReader will be returned, else an
        io.TextIOWrapper.
        """
        self._check_headers_complete()

        if buffering is None:
            buffering = -1
        if buffering < 0:
            buffering = DEFAULT_BUFFER_SIZE

        raw = HttpBodyReader(self)
        buffer = BufferedReader(raw, buffering)
        if binary:
            return buffer
        text = TextIOWrapper(buffer, encoding, errors, newline)
        return text

    def body_string(self,
                    binary=True,
                    encoding=None,
                    errors=None,
                    newline=None):
        """ return body as string """
        return self.body_file(binary=binary,
                              encoding=encoding,
                              newline=newline).read()

    def __iter__(self):
        return self

    def next(self):
        if self.parser.is_message_complete():
            raise StopIteration

        # fetch data
        b = bytearray(DEFAULT_BUFFER_SIZE)
        recved = self.stream.readinto(b)
        if recved is None:
            raise NoMoreData("no more data")

        del b[recved:]

        # parse data
        nparsed = self.parser.execute(bytes(b), recved)
        if nparsed != recved and not self.parser.is_message_complete():
            raise ParserError("nparsed != recved")

        if recved == 0:
            raise StopIteration

        return bytes(b)
示例#8
0
文件: http.py 项目: arnaudsj/diesel
    def __call__(self, addr):
        """Since an instance of HttpServer is passed to the Service
        class (with appropriate request_handler established during
        initialization), this __call__ method is what's actually
        invoked by diesel.
        """
        data = None
        while True:
            try:
                h = HttpParser()
                body = []
                while True:
                    if data:
                        used = h.execute(data, len(data))
                        if h.is_headers_complete():
                            body.append(h.recv_body())
                        if h.is_message_complete():
                            data = data[used:]
                            break
                    data = receive()

                env = h.get_wsgi_environ()
                if "HTTP_CONTENT_LENGTH" in env:
                    env["CONTENT_LENGTH"] = env.pop("HTTP_CONTENT_LENGTH")
                if "HTTP_CONTENT_TYPE" in env:
                    env["CONTENT_TYPE"] = env.pop("HTTP_CONTENT_TYPE")

                env.update(
                    {
                        "wsgi.version": (1, 0),
                        "wsgi.url_scheme": "http",  # XXX incomplete
                        "wsgi.input": cStringIO.StringIO("".join(body)),
                        "wsgi.errors": FileLikeErrorLogger(hlog),
                        "wsgi.multithread": False,
                        "wsgi.multiprocess": False,
                        "wsgi.run_once": False,
                        "REMOTE_ADDR": addr[0],
                        "SERVER_NAME": HOSTNAME,
                        "SERVER_PORT": str(self.port),
                    }
                )
                req = Request(env)
                if req.headers.get("Connection", "").lower() == "upgrade":
                    req.data = data

                resp = self.request_handler(req)
                if "Server" not in resp.headers:
                    resp.headers.add("Server", SERVER_TAG)
                if "Date" not in resp.headers:
                    resp.headers.add("Date", utcnow().strftime("%a, %d %b %Y %H:%M:%S UTC"))

                assert resp, "HTTP request handler _must_ return a response"

                self.send_response(resp, version=h.get_version())

                if (
                    (not h.should_keep_alive())
                    or resp.headers.get("Connection", "").lower() == "close"
                    or resp.headers.get("Content-Length") == None
                ):
                    return

            except ConnectionClosed:
                break
示例#9
0
class HttpProxyProtocol(asyncio.Protocol):
    ''' Implement HTTP(S) proxy behavior. '''

    def __init__(self, loop, config, token_store):
        ''' Constructor. '''

        self._parser = HttpParser()
        self._body = b''
        self._config = config
        self._loop = loop
        self._mitm = None
        self._mitm_host = None
        self._token_store = token_store

        self._instagram = InstagramApi(
            client_id=config['Instagram']['ClientID'],
            client_secret=config['Instagram']['ClientSecret'],
        )

        self._twitter = TwitterApi(
            consumer_key=config['Twitter']['ConsumerKey'],
            consumer_secret=config['Twitter']['ConsumerSecret'],
            app_token=config['Twitter']['AppToken'],
            app_token_secret=config['Twitter']['AppTokenSecret'],
        )

    def connection_made(self, transport):
        ''' Save a reference to the transport so that we can send a reply. '''
        log.debug('Connection opened.')
        self._transport = transport

    def connection_lost(self, exc):
        log.debug('Connection closed.')

    def data_received(self, data):
        ''' Parse incoming HTTP request. '''

        log.debug('Data received: {}'.format(data))
        self._parser.execute(data, len(data))

        if self._parser.is_partial_body():
            self._body += self._parser.recv_body()

        if self._parser.is_message_complete():
            method = self._parser.get_method()
            uri = self._parser.get_url()
            version = self._parser.get_version()
            headers = self._parser.get_headers()
            content_type = headers.get('Content-type', '')
            charset = _get_charset(content_type)
            body = self._body.decode(charset)

            log.debug('Client charset: {}'.format(charset))
            log.debug('Client status: method={} uri={} version={}' \
                      .format(method, uri, version))
            log.debug('Client headers: {}'.format(headers))
            log.debug('Client body: {}...'.format(body[:1000]))

            if method == 'CONNECT':
                asyncio.async(self._start_mitm(uri, version))
                self._parser = HttpParser()
            else:
                asyncio.async(
                    self._request_upstream(
                        method,
                        uri,
                        version,
                        headers,
                        body
                    )
                )


    def start_tls(self, version):
        '''
        Initiate TLS session with the client.

        This part is completely hacky! We mess around with the
        transport's internals in order to wrap the current transport in TLS.
        Python doesn't have an official way to do this, although it *might*
        get fixed in 3.6: http://bugs.python.org/issue23749
        '''

        log.debug('The proxy is starting TLS with its client.')

        status_line = 'HTTP/{}.{} {} {}\r\n\r\n' \
                      .format(version[0], version[1], 200, 'OK')
        self._transport.write(status_line.encode('ascii'))

        ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
        ssl_context.set_ciphers('HIGH:!aNull:!eNull')
        ssl_context.load_cert_chain('ssl/server.crt', 'ssl/server.key')

        original_socket = self._transport._sock
        self._transport = self._loop._make_ssl_transport(
            original_socket,
            self,
            ssl_context,
            server_side=True
        )

    @asyncio.coroutine
    def _request_upstream(self, method, uri, version, headers, body):
        ''' Forward the request to the upstream server. '''

        try:
            yield from self._request_upstream_helper(
                method, uri, version, headers, body
            )
        except Exception:
            charset = _get_charset(headers.get('Content-type', ''))
            response = render_http_response(
                version,
                500,
                'PROXY ERROR',
                {'Content-type': 'text/plain; charset={}'.format(charset)},
                traceback.format_exc().encode(charset)
            )
            self._transport.write(response)
            self._transport.close()
            raise

    @asyncio.coroutine
    def _request_upstream_helper(self, method, uri, version, headers, body):
        ''' Forward the request to the upstream server. '''

        log.debug('_request_upstream(): method={}, uri={}' \
                  .format(method, uri))

        if self._mitm_host:
            parsed = urlparse(uri)
            url = 'https://{}{}'.format(self._mitm_host, parsed.path)
        else:
            url = uri

        token, remaining = self._token_store.dispense(url)
        log.debug('Signing request with {} token: {}.'
                  .format(token.site, token.public))

        if 'instagram' in url:
            qp = parse_qs(parsed.query)
            qp['access_token'] = token.public

            qp['sig'] = self._instagram.oauth_sign(
                method=method,
                url=url,
                token=token,
                query_params=qp,
                body_params=parse_qs(body)
            )

            params = ['{}={}'.format(quote(k.encode('utf8')), quote(v.encode('utf8'))) for k,v in qp.items()]
            uri = '{}?{}'.format(parsed.path, '&'.join(params))
            log.debug('Signed instagram URL: {}'.format(uri))
        elif 'twitter' in url:
            headers['Authorization'] = self._twitter.oauth_sign(
                method=method,
                url=url,
                token=token.public,
                token_secret=token.secret,
                query_params=parse_qs(parsed.query),
                body_params=parse_qs(body)
            )
        else:
            raise ValueError('No signing algorithm known for URL: {}'
                             .format(url))

        if self._mitm is None:
            url = urlparse(uri)
            host = url.hostname
            port = url.port

            if port is None:
                port = 80 if url.scheme == 'http' else 443

            log.debug('Connecting to upstream (plaintext).')
            upstream = yield from asyncio.open_connection(host, port)
            upstream_reader, upstream_writer = upstream
            request = render_http_request(method, uri, version, headers, body)
            upstream_writer.write(request)

            response = b''
            parser = HttpParser()

            while True:
                if not parser.is_headers_complete():
                    data = yield from upstream_reader.readline()
                else:
                    data = yield from upstream_reader.read(
                        int(parser.get_headers()['Content-Length'])
                    )

                log.debug('Received plaintext from upstream: {}'.format(data))
                parser.execute(data, len(data))

                if parser.is_partial_body():
                    body += parser.recv_body()

                if parser.is_message_complete():
                    version = self._parser.get_version()
                    status = self._parser.get_status_code()
                    reason = None # For some reason, the parser doesn't expose this :(
                    headers = self._parser.get_headers()

                    if status == 200:
                        self._token_store.update_rate_limit(url, headers)

                    log.debug('Plaintext upstream status: {}'.format(status))
                    log.debug('Plaintext upstream headers: {}'.format(headers))
                    log.debug('Plaintext upstream body: {}...'.format(body[:1000]))

                    response = render_http_response(
                        version, status, reason, headers, body
                    )

                    break

            upstream_writer.close()

        else:
            upstream_write = self._mitm.forward
            request = render_http_request(method, uri, version, headers, body)
            upstream_write(request)
            response = yield from self._mitm.receive()
            version, status, reason, headers, body = response

            if status == 200:
                self._token_store.update_rate_limit(token, url, headers)

            response = render_http_response(
                version, status, reason, headers, body
            )

        # Forward the upstream response to the client.
        self._transport.write(response)
        self._transport.close()

    def _set_header(self, key, value):
        ''' Set a header value. '''

        key = key.strip().upper()
        value = value.strip()
        self._headers[key] = value

    @asyncio.coroutine
    def _start_mitm(self, uri, version):
        ''' MITM a connection to the upstream server. '''

        log.debug('The proxy is starting an MITM connection.')
        host, port = uri.split(':')
        port = int(port)
        self._mitm_host = host

        _, self._mitm = yield from self._loop.create_connection(
            lambda: MitmProtocol(self._loop, version, self),
            host,
            port,
            ssl = ssl.create_default_context()
        )
示例#10
0
class MitmProtocol(asyncio.Protocol):
    ''' Handles details of MITMing a TLS connection. '''

    def __init__(self, loop, http_version, proxy):
        ''' Constructor. '''

        self._http_version = http_version
        self._loop = loop
        self._parser = HttpParser()
        self._proxy = proxy
        self._received = asyncio.Future()
        self._body = b''

    def connection_made(self, transport):
        ''' Save a reference to the transport. '''

        log.debug('MITM connection opened.')
        self._transport = transport
        cert = self._transport.get_extra_info('peercert')
        log.debug('MITM upstream certificate: {}'.format(cert))
        self._loop.call_soon(self._proxy.start_tls, self._http_version)

    def connection_lost(self, exc):
        log.debug('MITM connection closed.')
        self._received.cancel()

    def data_received(self, data):
        ''' Accumulate request data. '''

        log.debug('MITM data received: {}'.format(data))
        self._parser.execute(data, len(data))

        if self._parser.is_partial_body():
            self._body += self._parser.recv_body()

        if self._parser.is_message_complete():
            version = self._parser.get_version()
            status = self._parser.get_status_code()
            reason = None # For some reason, the parser doesn't expose this :(
            headers = self._parser.get_headers()

            log.debug('MITM upstream status: {}'.format(status))
            log.debug('MITM upstream headers: {}'.format(headers))
            log.debug('MITM upstream body: {}...'.format(self._body[:1000]))

            self._received.set_result(
                (version, status, reason, headers, self._body)
            )
            self._transport.close()

    def forward(self, data):
        ''' Forward data to upstream host. '''

        log.debug('MITM sending data: {}'.format(data))
        self._transport.write(data)

    @asyncio.coroutine
    def receive(self):
        ''' Read data received by this MITM instance. '''

        response = yield from self._received
        return response
    def parse(self):
        data = [{
            'label':
            '以太网帧头部 / Ethernet Headers',
            'value':
            '',
            'bold':
            True,
            'children': [{
                'label': '目的端 MAC 地址',
                'value': self.ethHeader.destMac
            }, {
                'label': '发送端 MAC 地址',
                'value': self.ethHeader.sourceMac
            }, {
                'label':
                '帧类型',
                'value':
                '%s (0x%s)' % (self.ethHeader.type, self.ethHeader.type_code)
            }]
        }]

        if self.protocol == 'ARP':
            data.append({
                'label':
                'ARP 消息 / Address Resolution Protocol',
                'value':
                '',
                'bold':
                True,
                'children': [{
                    'label':
                    '硬件类型',
                    'value':
                    '%s (%s)' % (self.arpBody.hardware_type,
                                 self.arpBody.hardware_type_code)
                }, {
                    'label':
                    '协议类型',
                    'value':
                    '%s (0x%s)' % (self.arpBody.protocol_type,
                                   self.arpBody.protocol_type_code)
                }, {
                    'label': '硬件地址长度',
                    'value': str(self.arpBody.hardware_size)
                }, {
                    'label': '协议地址长度',
                    'value': str(self.arpBody.protocol_size)
                }, {
                    'label':
                    '操作码',
                    'value':
                    '%s (%s)' %
                    (self.arpBody.operation, self.arpBody.operation_code)
                }, {
                    'label': '发送端 MAC 地址',
                    'value': self.arpBody.sender_mac_address
                }, {
                    'label': '发送端 IP 地址',
                    'value': self.arpBody.sender_ip_address
                }, {
                    'label': '目的端 MAC 地址',
                    'value': self.arpBody.target_mac_address
                }, {
                    'label': '目的端 IP 地址',
                    'value': self.arpBody.target_ip_address
                }]
            })
        else:

            if self.ipHeader.version == 4:
                self.ipHeader.verifyChecksum = verifyChecksum(
                    self.ipHeader.header_raw, [], '').verifyChecksum
                data.append({
                    'label':
                    'IPv4 头部 / IPv4 Header',
                    'value':
                    '',
                    'bold':
                    True,
                    'children': [{
                        'label': '协议版本',
                        'value': self.ipHeader.version
                    }, {
                        'label':
                        '头部长度',
                        'value':
                        str(self.ipHeader.header_length) + ' Bytes'
                    }, {
                        'label':
                        '服务类型',
                        'value':
                        '0x%s' % (self.ipHeader.differentiated_services)
                    }, {
                        'label': '来源 IP',
                        'value': self.ipHeader.source_ip
                    }, {
                        'label': '目标 IP',
                        'value': self.ipHeader.dest_ip
                    }, {
                        'label': '总长度',
                        'value': self.ipHeader.total_length
                    }, {
                        'label':
                        '标识',
                        'value':
                        '0x%s (%s)' % (self.ipHeader.identification,
                                       self.ipHeader.identification_int)
                    }, {
                        'label':
                        '标志',
                        'value':
                        '%s' % (self.ipHeader.flags.raw),
                        'children': [{
                            'label':
                            '保留位',
                            'value':
                            '%s | %s... .... .... ....' %
                            (self.ipHeader.flags.reserved,
                             int(self.ipHeader.flags.reserved))
                        }, {
                            'label':
                            'Don\'t fragment',
                            'value':
                            '%s | .%s.. .... .... ....' %
                            (self.ipHeader.flags.fragment,
                             int(self.ipHeader.flags.fragment))
                        }, {
                            'label':
                            'More fragments',
                            'value':
                            '%s | ..%s. .... .... ....' %
                            (self.ipHeader.flags.more_fragment,
                             int(self.ipHeader.flags.more_fragment))
                        }, {
                            'label':
                            '分段偏移',
                            'value':
                            '%s | ...%s' %
                            (self.ipHeader.flags.fragment_offset,
                             self.ipHeader.flags.fragment_offset_bin)
                        }]
                    }, {
                        'label': '生存期',
                        'value': self.ipHeader.time_to_live
                    }, {
                        'label':
                        '协议',
                        'value':
                        '%s (%s)' %
                        (self.ipHeader.protocol, self.ipHeader.protocol_code)
                    }, {
                        'label':
                        '校验和',
                        'value':
                        '0x%s (%s)' % (self.ipHeader.origin_checksum, '校验' + {
                            True: '通过',
                            False: '失败'
                        }[self.ipHeader.verifyChecksum])
                    }]
                })

            else:
                ipv6_header = {
                    'label':
                    'IPv6 头部 / IPv6 Header',
                    'value':
                    '',
                    'bold':
                    True,
                    'children': [{
                        'label': '协议版本',
                        'value': self.ipHeader.version
                    }, {
                        'label': '通信分类',
                        'value': '0x%s' % (self.ipHeader._class)
                    }, {
                        'label': '流标签',
                        'value': '0x%s' % (self.ipHeader.float_label)
                    }, {
                        'label': '有效载荷长度',
                        'value': self.ipHeader.payload_length
                    }, {
                        'label':
                        '下一头部类型',
                        'value':
                        '%s (%s)' % (self.ipHeader.next_header,
                                     self.ipHeader.next_header_code)
                    }, {
                        'label': '跳数限制',
                        'value': self.ipHeader.hop_limit
                    }, {
                        'label': '源 IP',
                        'value': self.ipHeader.source_ip
                    }, {
                        'label': '目的 IP',
                        'value': self.ipHeader.dest_ip
                    }]
                }

                for option in self.ipHeader.options:
                    ipv6_header['children'].append({
                        'label':
                        consts.protocol_types[str(option['code'])],
                        'value':
                        '0x' + option['value'],
                        'children': [{
                            'label':
                            '下一头部类型',
                            'value':
                            '%s (%s)' % (consts.protocol_types[str(
                                option['next_header'])], option['next_header'])
                        }]
                    })

                data.append(ipv6_header)

            if self.ipHeader.version == 4 and self.ipHeader.flags.more_fragment == True:
                # print('Waiting for more fragments.')
                ids = self.ip_ids[self.ipHeader.identification_int]
                slicing = {
                    'label': 'IP 分片',
                    'value': '共 %s 个数据包' % len(ids),
                    'bold': True,
                    'children': []
                }
                for id in ids:
                    slicing['children'].append({
                        'label':
                        '#%s' % id,
                        'value':
                        '%s Bytes' % (self.ip_packets[id].length / 8)
                    })
                data.append(slicing)
            else:
                if self.ipHeader.protocol == 'TCP':
                    self.ipBody.tcpHeader.verifyChecksum = verifyChecksum(
                        self.ipBody.parameters[0], self.ipBody.parameters[1],
                        self.ipHeader.protocol).verifyChecksum
                    self.ipBody.tcpHeader.options = tcpOptions(
                        BitArray(self.ipBodyRaw)
                        [160:self.ipBody.tcpHeader.header_length * 8]).options
                    tcp_header = {
                        'label':
                        'TCP 头部 / Transmission Control Protocol Header',
                        'value':
                        '',
                        'bold':
                        True,
                        'children': [{
                            'label': '源端口',
                            'value': self.ipBody.tcpHeader.source_port
                        }, {
                            'label':
                            '目的端口',
                            'value':
                            self.ipBody.tcpHeader.destination_port
                        }, {
                            'label':
                            '数据序号 (seq)',
                            'value':
                            self.ipBody.tcpHeader.sequence_number
                        }, {
                            'label':
                            '确认序号 (ack)',
                            'value':
                            self.ipBody.tcpHeader.acknowledge_number
                        }, {
                            'label':
                            '首部长度',
                            'value':
                            self.ipBody.tcpHeader.header_length
                        }, {
                            'label':
                            '标志位',
                            'value':
                            '0x' + self.ipBody.tcpHeader.flags_raw,
                            'children': [{
                                'label':
                                'Reserved',
                                'value':
                                '%s | %s. .... ....' %
                                (self.ipBody.tcpHeader.flags.reserved.uint,
                                 self.ipBody.tcpHeader.flags.reserved.bin)
                            }, {
                                'label':
                                'Nonce',
                                'value':
                                '%s | ...%d .... ....' %
                                (self.ipBody.tcpHeader.flags.nonce,
                                 self.ipBody.tcpHeader.flags.nonce)
                            }, {
                                'label':
                                'Congestion Window Reduced',
                                'value':
                                '%s | .... %d... ....' %
                                (self.ipBody.tcpHeader.flags.cwr,
                                 self.ipBody.tcpHeader.flags.cwr)
                            }, {
                                'label':
                                'ECN-Echo',
                                'value':
                                '%s | .... .%d.. ....' %
                                (self.ipBody.tcpHeader.flags.ecn_echo,
                                 self.ipBody.tcpHeader.flags.ecn_echo)
                            }, {
                                'label':
                                'Urgent',
                                'value':
                                '%s | .... ..%d. ....' %
                                (self.ipBody.tcpHeader.flags.urgent,
                                 self.ipBody.tcpHeader.flags.urgent)
                            }, {
                                'label':
                                'Acknowledgment',
                                'value':
                                '%s | .... ...%d ....' %
                                (self.ipBody.tcpHeader.flags.acknowledgement,
                                 self.ipBody.tcpHeader.flags.acknowledgement)
                            }, {
                                'label':
                                'Push',
                                'value':
                                '%s | .... .... %d...' %
                                (self.ipBody.tcpHeader.flags.push,
                                 self.ipBody.tcpHeader.flags.push)
                            }, {
                                'label':
                                'Reset',
                                'value':
                                '%s | .... .... .%d..' %
                                (self.ipBody.tcpHeader.flags.reset,
                                 self.ipBody.tcpHeader.flags.reset)
                            }, {
                                'label':
                                'Syn',
                                'value':
                                '%s | .... .... ..%d.' %
                                (self.ipBody.tcpHeader.flags.syn,
                                 self.ipBody.tcpHeader.flags.syn)
                            }, {
                                'label':
                                'Fin',
                                'value':
                                '%s | .... .... ...%d' %
                                (self.ipBody.tcpHeader.flags.fin,
                                 self.ipBody.tcpHeader.flags.fin)
                            }]
                        }, {
                            'label': '窗口大小',
                            'value': self.ipBody.tcpHeader.window_size
                        }, {
                            'label':
                            '校验和',
                            'value':
                            '0x%s (%s)' %
                            (self.ipBody.tcpHeader.checksum, '校验' + {
                                True: '通过',
                                False: '失败'
                            }[self.ipBody.tcpHeader.verifyChecksum])
                        }]
                    }
                    options = []
                    if self.ipBody.tcpHeader.options:
                        for idx in range(len(self.ipBody.tcpHeader.options)):
                            option = {
                                'label':
                                self.ipBody.tcpHeader.options[idx][0]['label'],
                                'value':
                                '(%s)' %
                                self.ipBody.tcpHeader.options[idx][0]['value'],
                                'children':
                                self.ipBody.tcpHeader.options[idx][1:]
                            }
                            options.append(option)
                    if options:
                        tcp_header['children'].append({
                            'label': '选项',
                            'value': '',
                            'children': options
                        })

                    data.append(tcp_header)

                    print(self.id)
                    print(tcp_bodies)
                    if self.id in packet_id_struct:
                        tmp = []
                        http_payload = None
                        for p_id in packet_id_struct[self.id]:
                            tmp.append({'value': '', 'label': '#%s' % p_id})

                        if self.id in tcp_bodies:
                            # print(tcp_bodies[self.id]['data'].decode('utf-8', 'ignore'))
                            children = [{
                                'label':
                                '该包是 TCP 分段的最后一段, 可以通过右下角按钮「导出 TCP 分段数据」.',
                                'value': '',
                                'bold': True
                            }, {
                                'label': '共 %s 个分段' % len(tmp),
                                'value': '',
                                'bold': True,
                                'children': tmp
                            }]

                            try:
                                p = HttpParser()
                                recved = len(tcp_bodies[self.id]['data'])
                                nparsed = p.execute(
                                    tcp_bodies[self.id]['data'], recved)
                                assert nparsed == recved

                                headers = []
                                for header in p.get_headers():
                                    headers.append({
                                        'label':
                                        header,
                                        'value':
                                        p.get_headers()[header]
                                    })

                                print(p.get_path(), p.get_url(),
                                      p.get_fragment(), p.get_method(),
                                      p.get_query_string(),
                                      p.get_status_code(),
                                      p.get_wsgi_environ())

                                http_payload = [{
                                    'label':
                                    'HTTP 版本',
                                    'value':
                                    '%s.%s' %
                                    (p.get_version()[0], p.get_version()[1])
                                }, {
                                    'label': 'HTTP 头部',
                                    'value': '',
                                    'children': headers
                                }]

                                if len(p.get_url()) != 0:
                                    http_payload.append({
                                        'label': '请求方式',
                                        'value': p.get_method()
                                    })
                                    http_payload.append({
                                        'label': '路径',
                                        'value': p.get_url()
                                    })
                                    http_payload.append({
                                        'label':
                                        '请求参数',
                                        'value':
                                        p.get_query_string()
                                    })
                                    http_payload.append({
                                        'label':
                                        '主机名',
                                        'value':
                                        p.get_wsgi_environ()['HTTP_HOST']
                                    })
                                else:
                                    http_payload.append({
                                        'label':
                                        '状态码',
                                        'value':
                                        p.get_status_code()
                                    })

                            except AssertionError:
                                pass

                        else:
                            children = [{
                                'label': '共 %s 个分段' % len(tmp),
                                'value': '',
                                'bold': True,
                                'children': tmp
                            }]

                        data.append({
                            'label': 'TCP 数据 / TCP Payload',
                            'value': '',
                            'bold': True,
                            'children': children
                        })

                        if http_payload != None:
                            data.append({
                                'label': 'HTTP 数据 / HTTP Data',
                                'value': '',
                                'bold': True,
                                'children': http_payload
                            })
                    '''
                    if self.ipBody.tcpBody.has_body:
                        try:
                            p = HttpParser()
                            recved = len(self.ipBody.tcpBody.buf)
                            nparsed = p.execute(self.ipBody.tcpBody.buf, recved)
                            assert nparsed == recved

                            print(p.get_headers())
                        except AssertionError:
                            print('NOT HTTP')

                        data.append({
                            'label': 'TCP 数据 / Data',
                            'value': '',
                            'bold': True,
                            'children': [
                                {
                                    'label': '数据',
                                    'value': self.ipBody.tcpBody.raw
                                }
                            ]
                        })
                    '''

                elif self.ipHeader.protocol == 'UDP':
                    self.ipBody.udpHeader.verifyChecksum = verifyChecksum(
                        self.ipBody.parameters[0], self.ipBody.parameters[1],
                        self.ipHeader.protocol).verifyChecksum
                    data.append({
                        'label':
                        'UDP 头部 / User Datagram Protocol Header',
                        'value':
                        '',
                        'bold':
                        True,
                        'children': [{
                            'label': '源端口',
                            'value': self.ipBody.udpHeader.source_port
                        }, {
                            'label':
                            '目的端口',
                            'value':
                            self.ipBody.udpHeader.destination_port
                        }, {
                            'label': '长度',
                            'value': self.ipBody.udpHeader.length
                        }, {
                            'label':
                            '校验和',
                            'value':
                            '0x%s (%s)' %
                            (self.ipBody.udpHeader.checksum, '校验' + {
                                True: '通过',
                                False: '失败'
                            }[self.ipBody.udpHeader.verifyChecksum])
                        }]
                    })

                    if self.ipBody.udpHeader.source_port == 53 or self.ipBody.udpHeader.destination_port == 53:  # DNS
                        children = [{
                            'label': '会话标识',
                            'value': self.ipBody.dnsBody.transaction_id
                        }, {
                            'label':
                            '标志',
                            'value':
                            '0x' + self.ipBody.dnsBody.transaction_id
                        }, {
                            'label': '问题数',
                            'value': self.ipBody.dnsBody.questions
                        }, {
                            'label': '回答资源记录数',
                            'value': self.ipBody.dnsBody.answer_rrs
                        }, {
                            'label': '授权资源记录数',
                            'value': self.ipBody.dnsBody.authority_rrs
                        }, {
                            'label': '附加资源记录数',
                            'value': self.ipBody.dnsBody.additional_rrs
                        }]

                        if len(self.ipBody.dnsBody.queries) > 0:
                            queries = []
                            for query in self.ipBody.dnsBody.queries:
                                queries.append({
                                    'label':
                                    str(query.qname),
                                    'value':
                                    '',
                                    'bold':
                                    True,
                                    'children': [{
                                        'label': '域名',
                                        'value': str(query.qname)
                                    }, {
                                        'label':
                                        'Type',
                                        'value':
                                        '%s (%s)' %
                                        (consts.dns_types[query.qtype],
                                         query.qtype)
                                    }, {
                                        'label':
                                        'Class',
                                        'value':
                                        '%s (%s)' %
                                        (consts.dns_classes[query.qclass],
                                         query.qclass)
                                    }]
                                })
                            children.append({
                                'label': '查询问题',
                                'value': '',
                                'bold': True,
                                'children': queries
                            })

                        if len(self.ipBody.dnsBody.answers) > 0:
                            answers = []
                            for answer in self.ipBody.dnsBody.answers:
                                answers.append({
                                    'label':
                                    str(answer.rname),
                                    'value':
                                    '',
                                    'bold':
                                    True,
                                    'children': [{
                                        'label': '域名',
                                        'value': str(answer.rname)
                                    }, {
                                        'label':
                                        'Type',
                                        'value':
                                        '%s (%s)' %
                                        (consts.dns_types[answer.rtype],
                                         answer.rtype)
                                    }, {
                                        'label':
                                        'Class',
                                        'value':
                                        '%s (%s)' %
                                        (consts.dns_classes[answer.rclass],
                                         answer.rclass)
                                    }, {
                                        'label': '生存时间 (ttl)',
                                        'value': str(answer.ttl)
                                    }, {
                                        'label': '数据',
                                        'value': str(answer.rdata)
                                    }]
                                })
                            children.append({
                                'label': '回答',
                                'value': '',
                                'bold': True,
                                'children': answers
                            })

                        data.append({
                            'label': 'DNS / Domain Name System',
                            'value': '',
                            'bold': True,
                            'children': children
                        })

                elif 'ICMP' in self.ipHeader.protocol:
                    if 'IPv6' in self.ipHeader.protocol:
                        self.ipBody.icmpHeader.verifyChecksum = verifyChecksum(
                            self.ipBody.parameters[0],
                            self.ipBody.parameters[1],
                            self.ipHeader.protocol).verifyChecksum
                    else:
                        self.ipBody.icmpHeader.verifyChecksum = verifyChecksum(
                            self.ipBody.parameters, [], '').verifyChecksum
                    data.append({
                        'label':
                        'ICMP 头部 / Internet Control Message Protocol Headers',
                        'value':
                        '',
                        'bold':
                        True,
                        'children': [{
                            'label':
                            '类型',
                            'value':
                            '%s (%s)' % (self.ipBody.icmpHeader.type,
                                         self.ipBody.icmpHeader.type_name)
                        }, {
                            'label': '代码',
                            'value': self.ipBody.icmpHeader.code
                        }, {
                            'label':
                            '校验和',
                            'value':
                            '0x%s (%s)' %
                            (self.ipBody.icmpHeader.checksum, '校验' + {
                                True: '通过',
                                False: '失败'
                            }[self.ipBody.icmpHeader.verifyChecksum])
                        }]
                    })

                elif 'IGMP' in self.ipHeader.protocol:
                    if self.ipHeader.payload_length == 8:
                        self.ipBody.igmpHeader.verifyChecksum = verifyChecksum(
                            self.ipBody.parameters, [], '').verifyChecksum
                        data.append({
                            'label':
                            'IGMP 头部 / Internet Group Management Protocol Headers',
                            'value':
                            '',
                            'bold':
                            True,
                            'children': [{
                                'label':
                                '类型',
                                'value':
                                '0x%s(%s)' % (self.ipBody.igmpHeader.type,
                                              self.ipBody.igmpHeader.type_name)
                            }, {
                                'label':
                                '最大响应时延',
                                'value':
                                '%s 秒(0x%s)' %
                                (self.ipBody.igmpHeader.maxRespTime,
                                 self.ipBody.igmpHeader.maxRespTimeHex)
                            }, {
                                'label':
                                '校验和',
                                'value':
                                '0x%s(%s)' %
                                (self.ipBody.igmpHeader.checksum, '校验' + {
                                    True: '通过',
                                    False: '失败'
                                }[self.ipBody.igmpHeader.verifyChecksum])
                            }, {
                                'label':
                                '组地址',
                                'value':
                                self.ipBody.igmpHeader.groupAddress
                            }]
                        })
                    else:
                        self.ipBody.igmpv3Header.verifyChecksum = verifyChecksum(
                            self.ipBody.parameters, [], '').verifyChecksum
                        data.append({
                            'label':
                            'IGMPv3 头部 / Internet Group Management Protocol Version 3 Headers',
                            'value':
                            '',
                            'bold':
                            True,
                            'children': [{
                                'label':
                                '类型',
                                'value':
                                '0x%s' % self.ipBody.igmpv3Header.type
                            }, {
                                'label':
                                '校验和',
                                'value':
                                '0x%s(%s)' %
                                (self.ipBody.igmpv3Header.checksum, '校验' + {
                                    True: '通过',
                                    False: '失败'
                                }[self.ipBody.igmpv3Header.verifyChecksum])
                            }]
                        })

        return data