{
    "file_diffs": [
        {
            "old_file_content": "#!/usr/bin/env python\n#\n# Copyright 2009 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\"\"\"HTTP utility code shared by clients and servers.\n\nThis module also defines the `HTTPServerRequest` class which is exposed\nvia `tornado.web.RequestHandler.request`.\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function\n\nimport calendar\nimport collections\nimport copy\nimport datetime\nimport email.utils\nimport numbers\nimport re\nimport time\n\nfrom tornado.escape import native_str, parse_qs_bytes, utf8\nfrom tornado.log import gen_log\nfrom tornado.util import ObjectDict, PY3\n\nif PY3:\n    import http.cookies as Cookie\n    from http.client import responses\n    from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl\nelse:\n    import Cookie\n    from httplib import responses\n    from urllib import urlencode\n    from urlparse import urlparse, urlunparse, parse_qsl\n\n\n# responses is unused in this file, but we re-export it to other files.\n# Reference it so pyflakes doesn't complain.\nresponses\n\ntry:\n    from ssl import SSLError\nexcept ImportError:\n    # ssl is unavailable on app engine.\n    class _SSLError(Exception):\n        pass\n    # Hack around a mypy limitation. We can't simply put \"type: ignore\"\n    # on the class definition itself; must go through an assignment.\n    SSLError = _SSLError  # type: ignore\n\ntry:\n    import typing\nexcept ImportError:\n    pass\n\n\n# RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line\n# terminator and ignore any preceding CR.\n_CRLF_RE = re.compile(r'\\r?\\n')\n\n\nclass _NormalizedHeaderCache(dict):\n    \"\"\"Dynamic cached mapping of header names to Http-Header-Case.\n\n    Implemented as a dict subclass so that cache hits are as fast as a\n    normal dict lookup, without the overhead of a python function\n    call.\n\n    >>> normalized_headers = _NormalizedHeaderCache(10)\n    >>> normalized_headers[\"coNtent-TYPE\"]\n    'Content-Type'\n    \"\"\"\n    def __init__(self, size):\n        super(_NormalizedHeaderCache, self).__init__()\n        self.size = size\n        self.queue = collections.deque()\n\n    def __missing__(self, key):\n        normalized = \"-\".join([w.capitalize() for w in key.split(\"-\")])\n        self[key] = normalized\n        self.queue.append(key)\n        if len(self.queue) > self.size:\n            # Limit the size of the cache.  LRU would be better, but this\n            # simpler approach should be fine.  In Python 2.7+ we could\n            # use OrderedDict (or in 3.2+, @functools.lru_cache).\n            old_key = self.queue.popleft()\n            del self[old_key]\n        return normalized\n\n\n_normalized_headers = _NormalizedHeaderCache(1000)\n\n\nclass HTTPHeaders(collections.MutableMapping):\n    \"\"\"A dictionary that maintains ``Http-Header-Case`` for all keys.\n\n    Supports multiple values per key via a pair of new methods,\n    `add()` and `get_list()`.  The regular dictionary interface\n    returns a single value per key, with multiple values joined by a\n    comma.\n\n    >>> h = HTTPHeaders({\"content-type\": \"text/html\"})\n    >>> list(h.keys())\n    ['Content-Type']\n    >>> h[\"Content-Type\"]\n    'text/html'\n\n    >>> h.add(\"Set-Cookie\", \"A=B\")\n    >>> h.add(\"Set-Cookie\", \"C=D\")\n    >>> h[\"set-cookie\"]\n    'A=B,C=D'\n    >>> h.get_list(\"set-cookie\")\n    ['A=B', 'C=D']\n\n    >>> for (k,v) in sorted(h.get_all()):\n    ...    print('%s: %s' % (k,v))\n    ...\n    Content-Type: text/html\n    Set-Cookie: A=B\n    Set-Cookie: C=D\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self._dict = {}  # type: typing.Dict[str, str]\n        self._as_list = {}  # type: typing.Dict[str, typing.List[str]]\n        self._last_key = None\n        if (len(args) == 1 and len(kwargs) == 0 and\n                isinstance(args[0], HTTPHeaders)):\n            # Copy constructor\n            for k, v in args[0].get_all():\n                self.add(k, v)\n        else:\n            # Dict-style initialization\n            self.update(*args, **kwargs)\n\n    # new public methods\n\n    def add(self, name, value):\n        # type: (str, str) -> None\n        \"\"\"Adds a new value for the given key.\"\"\"\n        norm_name = _normalized_headers[name]\n        self._last_key = norm_name\n        if norm_name in self:\n            self._dict[norm_name] = (native_str(self[norm_name]) + ',' +\n                                     native_str(value))\n            self._as_list[norm_name].append(value)\n        else:\n            self[norm_name] = value\n\n    def get_list(self, name):\n        \"\"\"Returns all values for the given header as a list.\"\"\"\n        norm_name = _normalized_headers[name]\n        return self._as_list.get(norm_name, [])\n\n    def get_all(self):\n        # type: () -> typing.Iterable[typing.Tuple[str, str]]\n        \"\"\"Returns an iterable of all (name, value) pairs.\n\n        If a header has multiple values, multiple pairs will be\n        returned with the same name.\n        \"\"\"\n        for name, values in self._as_list.items():\n            for value in values:\n                yield (name, value)\n\n    def parse_line(self, line):\n        \"\"\"Updates the dictionary with a single header line.\n\n        >>> h = HTTPHeaders()\n        >>> h.parse_line(\"Content-Type: text/html\")\n        >>> h.get('content-type')\n        'text/html'\n        \"\"\"\n        if line[0].isspace():\n            # continuation of a multi-line header\n            new_part = ' ' + line.lstrip()\n            self._as_list[self._last_key][-1] += new_part\n            self._dict[self._last_key] += new_part\n        else:\n            name, value = line.split(\":\", 1)\n            self.add(name, value.strip())\n\n    @classmethod\n    def parse(cls, headers):\n        \"\"\"Returns a dictionary from HTTP header text.\n\n        >>> h = HTTPHeaders.parse(\"Content-Type: text/html\\\\r\\\\nContent-Length: 42\\\\r\\\\n\")\n        >>> sorted(h.items())\n        [('Content-Length', '42'), ('Content-Type', 'text/html')]\n        \"\"\"\n        h = cls()\n        for line in _CRLF_RE.split(headers):\n            if line:\n                h.parse_line(line)\n        return h\n\n    # MutableMapping abstract method implementations.\n\n    def __setitem__(self, name, value):\n        norm_name = _normalized_headers[name]\n        self._dict[norm_name] = value\n        self._as_list[norm_name] = [value]\n\n    def __getitem__(self, name):\n        # type: (str) -> str\n        return self._dict[_normalized_headers[name]]\n\n    def __delitem__(self, name):\n        norm_name = _normalized_headers[name]\n        del self._dict[norm_name]\n        del self._as_list[norm_name]\n\n    def __len__(self):\n        return len(self._dict)\n\n    def __iter__(self):\n        return iter(self._dict)\n\n    def copy(self):\n        # defined in dict but not in MutableMapping.\n        return HTTPHeaders(self)\n\n    # Use our overridden copy method for the copy.copy module.\n    # This makes shallow copies one level deeper, but preserves\n    # the appearance that HTTPHeaders is a single container.\n    __copy__ = copy\n\n    def __str__(self):\n        lines = []\n        for name, value in self.get_all():\n            lines.append(\"%s: %s\\n\" % (name, value))\n        return \"\".join(lines)\n\n    __unicode__ = __str__\n\n\nclass HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s, headers=%s)\" % (\n            self.__class__.__name__, args, dict(self.headers))\n\n\nclass HTTPInputError(Exception):\n    \"\"\"Exception class for malformed HTTP requests or responses\n    from remote sources.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPOutputError(Exception):\n    \"\"\"Exception class for errors in HTTP output.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPServerConnectionDelegate(object):\n    \"\"\"Implement this interface to handle requests from `.HTTPServer`.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def start_request(self, server_conn, request_conn):\n        \"\"\"This method is called by the server when a new request has started.\n\n        :arg server_conn: is an opaque object representing the long-lived\n            (e.g. tcp-level) connection.\n        :arg request_conn: is a `.HTTPConnection` object for a single\n            request/response exchange.\n\n        This method should return a `.HTTPMessageDelegate`.\n        \"\"\"\n        raise NotImplementedError()\n\n    def on_close(self, server_conn):\n        \"\"\"This method is called when a connection has been closed.\n\n        :arg server_conn: is a server connection that has previously been\n            passed to ``start_request``.\n        \"\"\"\n        pass\n\n\nclass HTTPMessageDelegate(object):\n    \"\"\"Implement this interface to handle an HTTP request or response.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def headers_received(self, start_line, headers):\n        \"\"\"Called when the HTTP headers have been received and parsed.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`\n            depending on whether this is a client or server message.\n        :arg headers: a `.HTTPHeaders` instance.\n\n        Some `.HTTPConnection` methods can only be called during\n        ``headers_received``.\n\n        May return a `.Future`; if it does the body will not be read\n        until it is done.\n        \"\"\"\n        pass\n\n    def data_received(self, chunk):\n        \"\"\"Called when a chunk of data has been received.\n\n        May return a `.Future` for flow control.\n        \"\"\"\n        pass\n\n    def finish(self):\n        \"\"\"Called after the last chunk of data has been received.\"\"\"\n        pass\n\n    def on_connection_close(self):\n        \"\"\"Called if the connection is closed without finishing the request.\n\n        If ``headers_received`` is called, either ``finish`` or\n        ``on_connection_close`` will be called, but not both.\n        \"\"\"\n        pass\n\n\nclass HTTPConnection(object):\n    \"\"\"Applications use this interface to write their responses.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def write_headers(self, start_line, headers, chunk=None, callback=None):\n        \"\"\"Write an HTTP header block.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.\n        :arg headers: a `.HTTPHeaders` instance.\n        :arg chunk: the first (optional) chunk of data.  This is an optimization\n            so that small responses can be written in the same call as their\n            headers.\n        :arg callback: a callback to be run when the write is complete.\n\n        The ``version`` field of ``start_line`` is ignored.\n\n        Returns a `.Future` if no callback is given.\n        \"\"\"\n        raise NotImplementedError()\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes a chunk of body data.\n\n        The callback will be run when the write is complete.  If no callback\n        is given, returns a Future.\n        \"\"\"\n        raise NotImplementedError()\n\n    def finish(self):\n        \"\"\"Indicates that the last body data has been written.\n        \"\"\"\n        raise NotImplementedError()\n\n\ndef url_concat(url, args):\n    \"\"\"Concatenate url and arguments regardless of whether\n    url has existing query parameters.\n\n    ``args`` may be either a dictionary or a list of key-value pairs\n    (the latter allows for multiple values with the same key.\n\n    >>> url_concat(\"http://example.com/foo\", dict(c=\"d\"))\n    'http://example.com/foo?c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", dict(c=\"d\"))\n    'http://example.com/foo?a=b&c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", [(\"c\", \"d\"), (\"c\", \"d2\")])\n    'http://example.com/foo?a=b&c=d&c=d2'\n    \"\"\"\n    if args is None:\n        return url\n    parsed_url = urlparse(url)\n    if isinstance(args, dict):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args.items())\n    elif isinstance(args, list) or isinstance(args, tuple):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args)\n    else:\n        err = \"'args' parameter should be dict, list or tuple. Not {0}\".format(\n            type(args))\n        raise TypeError(err)\n    final_query = urlencode(parsed_query)\n    url = urlunparse((\n        parsed_url[0],\n        parsed_url[1],\n        parsed_url[2],\n        parsed_url[3],\n        final_query,\n        parsed_url[5]))\n    return url\n\n\nclass HTTPFile(ObjectDict):\n    \"\"\"Represents a file uploaded via a form.\n\n    For backwards compatibility, its instance attributes are also\n    accessible as dictionary keys.\n\n    * ``filename``\n    * ``body``\n    * ``content_type``\n    \"\"\"\n    pass\n\n\ndef _parse_request_range(range_header):\n    \"\"\"Parses a Range header.\n\n    Returns either ``None`` or tuple ``(start, end)``.\n    Note that while the HTTP headers use inclusive byte positions,\n    this method returns indexes suitable for use in slices.\n\n    >>> start, end = _parse_request_range(\"bytes=1-2\")\n    >>> start, end\n    (1, 3)\n    >>> [0, 1, 2, 3, 4][start:end]\n    [1, 2]\n    >>> _parse_request_range(\"bytes=6-\")\n    (6, None)\n    >>> _parse_request_range(\"bytes=-6\")\n    (-6, None)\n    >>> _parse_request_range(\"bytes=-0\")\n    (None, 0)\n    >>> _parse_request_range(\"bytes=\")\n    (None, None)\n    >>> _parse_request_range(\"foo=42\")\n    >>> _parse_request_range(\"bytes=1-2,6-10\")\n\n    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).\n\n    See [0] for the details of the range header.\n\n    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges\n    \"\"\"\n    unit, _, value = range_header.partition(\"=\")\n    unit, value = unit.strip(), value.strip()\n    if unit != \"bytes\":\n        return None\n    start_b, _, end_b = value.partition(\"-\")\n    try:\n        start = _int_or_none(start_b)\n        end = _int_or_none(end_b)\n    except ValueError:\n        return None\n    if end is not None:\n        if start is None:\n            if end != 0:\n                start = -end\n                end = None\n        else:\n            end += 1\n    return (start, end)\n\n\ndef _get_content_range(start, end, total):\n    \"\"\"Returns a suitable Content-Range header:\n\n    >>> print(_get_content_range(None, 1, 4))\n    bytes 0-0/4\n    >>> print(_get_content_range(1, 3, 4))\n    bytes 1-2/4\n    >>> print(_get_content_range(None, None, 4))\n    bytes 0-3/4\n    \"\"\"\n    start = start or 0\n    end = (end or total) - 1\n    return \"bytes %s-%s/%s\" % (start, end, total)\n\n\ndef _int_or_none(val):\n    val = val.strip()\n    if val == \"\":\n        return None\n    return int(val)\n\n\ndef parse_body_arguments(content_type, body, arguments, files, headers=None):\n    \"\"\"Parses a form request body.\n\n    Supports ``application/x-www-form-urlencoded`` and\n    ``multipart/form-data``.  The ``content_type`` parameter should be\n    a string and ``body`` should be a byte string.  The ``arguments``\n    and ``files`` parameters are dictionaries that will be updated\n    with the parsed contents.\n    \"\"\"\n    if headers and 'Content-Encoding' in headers:\n        gen_log.warning(\"Unsupported Content-Encoding: %s\",\n                        headers['Content-Encoding'])\n        return\n    if content_type.startswith(\"application/x-www-form-urlencoded\"):\n        try:\n            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)\n        except Exception as e:\n            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)\n            uri_arguments = {}\n        for name, values in uri_arguments.items():\n            if values:\n                arguments.setdefault(name, []).extend(values)\n    elif content_type.startswith(\"multipart/form-data\"):\n        try:\n            fields = content_type.split(\";\")\n            for field in fields:\n                k, sep, v = field.strip().partition(\"=\")\n                if k == \"boundary\" and v:\n                    parse_multipart_form_data(utf8(v), body, arguments, files)\n                    break\n            else:\n                raise ValueError(\"multipart boundary not found\")\n        except Exception as e:\n            gen_log.warning(\"Invalid multipart/form-data: %s\", e)\n\n\ndef parse_multipart_form_data(boundary, data, arguments, files):\n    \"\"\"Parses a ``multipart/form-data`` body.\n\n    The ``boundary`` and ``data`` parameters are both byte strings.\n    The dictionaries given in the arguments and files parameters\n    will be updated with the contents of the body.\n    \"\"\"\n    # The standard allows for the boundary to be quoted in the header,\n    # although it's rare (it happens at least for google app engine\n    # xmpp).  I think we're also supposed to handle backslash-escapes\n    # here but I'll save that until we see a client that uses them\n    # in the wild.\n    if boundary.startswith(b'\"') and boundary.endswith(b'\"'):\n        boundary = boundary[1:-1]\n    final_boundary_index = data.rfind(b\"--\" + boundary + b\"--\")\n    if final_boundary_index == -1:\n        gen_log.warning(\"Invalid multipart/form-data: no final boundary\")\n        return\n    parts = data[:final_boundary_index].split(b\"--\" + boundary + b\"\\r\\n\")\n    for part in parts:\n        if not part:\n            continue\n        eoh = part.find(b\"\\r\\n\\r\\n\")\n        if eoh == -1:\n            gen_log.warning(\"multipart/form-data missing headers\")\n            continue\n        headers = HTTPHeaders.parse(part[:eoh].decode(\"utf-8\"))\n        disp_header = headers.get(\"Content-Disposition\", \"\")\n        disposition, disp_params = _parse_header(disp_header)\n        if disposition != \"form-data\" or not part.endswith(b\"\\r\\n\"):\n            gen_log.warning(\"Invalid multipart/form-data\")\n            continue\n        value = part[eoh + 4:-2]\n        if not disp_params.get(\"name\"):\n            gen_log.warning(\"multipart/form-data value missing name\")\n            continue\n        name = disp_params[\"name\"]\n        if disp_params.get(\"filename\"):\n            ctype = headers.get(\"Content-Type\", \"application/unknown\")\n            files.setdefault(name, []).append(HTTPFile(  # type: ignore\n                filename=disp_params[\"filename\"], body=value,\n                content_type=ctype))\n        else:\n            arguments.setdefault(name, []).append(value)\n\n\ndef format_timestamp(ts):\n    \"\"\"Formats a timestamp in the format used by HTTP.\n\n    The argument may be a numeric timestamp as returned by `time.time`,\n    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`\n    object.\n\n    >>> format_timestamp(1359312200)\n    'Sun, 27 Jan 2013 18:43:20 GMT'\n    \"\"\"\n    if isinstance(ts, numbers.Real):\n        pass\n    elif isinstance(ts, (tuple, time.struct_time)):\n        ts = calendar.timegm(ts)\n    elif isinstance(ts, datetime.datetime):\n        ts = calendar.timegm(ts.utctimetuple())\n    else:\n        raise TypeError(\"unknown timestamp type: %r\" % ts)\n    return email.utils.formatdate(ts, usegmt=True)\n\n\nRequestStartLine = collections.namedtuple(\n    'RequestStartLine', ['method', 'path', 'version'])\n\n\ndef parse_request_start_line(line):\n    \"\"\"Returns a (method, path, version) tuple for an HTTP 1.x request line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_request_start_line(\"GET /foo HTTP/1.1\")\n    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')\n    \"\"\"\n    try:\n        method, path, version = line.split(\" \")\n    except ValueError:\n        # https://tools.ietf.org/html/rfc7230#section-3.1.1\n        # invalid request-line SHOULD respond with a 400 (Bad Request)\n        raise HTTPInputError(\"Malformed HTTP request line\")\n    if not re.match(r\"^HTTP/1\\.[0-9]$\", version):\n        raise HTTPInputError(\n            \"Malformed HTTP version in HTTP Request-Line: %r\" % version)\n    return RequestStartLine(method, path, version)\n\n\nResponseStartLine = collections.namedtuple(\n    'ResponseStartLine', ['version', 'code', 'reason'])\n\n\ndef parse_response_start_line(line):\n    \"\"\"Returns a (version, code, reason) tuple for an HTTP 1.x response line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_response_start_line(\"HTTP/1.1 200 OK\")\n    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')\n    \"\"\"\n    line = native_str(line)\n    match = re.match(\"(HTTP/1.[0-9]) ([0-9]+) ([^\\r]*)\", line)\n    if not match:\n        raise HTTPInputError(\"Error parsing response start line\")\n    return ResponseStartLine(match.group(1), int(match.group(2)),\n                             match.group(3))\n\n# _parseparam and _parse_header are copied and modified from python2.7's cgi.py\n# The original 2.7 version of this code did not correctly support some\n# combinations of semicolons and double quotes.\n# It has also been modified to support valueless parameters as seen in\n# websocket extension negotiations.\n\n\ndef _parseparam(s):\n    while s[:1] == ';':\n        s = s[1:]\n        end = s.find(';')\n        while end > 0 and (s.count('\"', 0, end) - s.count('\\\\\"', 0, end)) % 2:\n            end = s.find(';', end + 1)\n        if end < 0:\n            end = len(s)\n        f = s[:end]\n        yield f.strip()\n        s = s[end:]\n\n\ndef _parse_header(line):\n    \"\"\"Parse a Content-type like header.\n\n    Return the main content-type and a dictionary of options.\n\n    \"\"\"\n    parts = _parseparam(';' + line)\n    key = next(parts)\n    pdict = {}\n    for p in parts:\n        i = p.find('=')\n        if i >= 0:\n            name = p[:i].strip().lower()\n            value = p[i + 1:].strip()\n            if len(value) >= 2 and value[0] == value[-1] == '\"':\n                value = value[1:-1]\n                value = value.replace('\\\\\\\\', '\\\\').replace('\\\\\"', '\"')\n            pdict[name] = value\n        else:\n            pdict[p] = None\n    return key, pdict\n\n\ndef _encode_header(key, pdict):\n    \"\"\"Inverse of _parse_header.\n\n    >>> _encode_header('permessage-deflate',\n    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})\n    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'\n    \"\"\"\n    if not pdict:\n        return key\n    out = [key]\n    # Sort the parameters just to make it easy to test.\n    for k, v in sorted(pdict.items()):\n        if v is None:\n            out.append(k)\n        else:\n            # TODO: quote if necessary.\n            out.append('%s=%s' % (k, v))\n    return '; '.join(out)\n\n\ndef doctests():\n    import doctest\n    return doctest.DocTestSuite()\n\n\ndef split_host_and_port(netloc):\n    \"\"\"Returns ``(host, port)`` tuple from ``netloc``.\n\n    Returned ``port`` will be ``None`` if not present.\n\n    .. versionadded:: 4.1\n    \"\"\"\n    match = re.match(r'^(.+):(\\d+)$', netloc)\n    if match:\n        host = match.group(1)\n        port = int(match.group(2))\n    else:\n        host = netloc\n        port = None\n    return (host, port)\n\n\ndef qs_to_qsl(qs):\n    \"\"\"Generator rewinding a result of ``parse_qs`` back to name-value pairs. \n    \"\"\"\n    for k, vs in qs.items():\n        for v in vs:\n            yield (k, v)\n\n\n_OctalPatt = re.compile(r\"\\\\[0-3][0-7][0-7]\")\n_QuotePatt = re.compile(r\"[\\\\].\")\n_nulljoin = ''.join\n\n\ndef _unquote_cookie(str):\n    \"\"\"Handle double quotes and escaping in cookie values.\n\n    This method is copied verbatim from the Python 3.5 standard\n    library (http.cookies._unquote) so we don't have to depend on\n    non-public interfaces.\n    \"\"\"\n    # If there aren't any doublequotes,\n    # then there can't be any special characters.  See RFC 2109.\n    if str is None or len(str) < 2:\n        return str\n    if str[0] != '\"' or str[-1] != '\"':\n        return str\n\n    # We have to assume that we must decode this string.\n    # Down to work.\n\n    # Remove the \"s\n    str = str[1:-1]\n\n    # Check for special sequences.  Examples:\n    #    \\012 --> \\n\n    #    \\\"   --> \"\n    #\n    i = 0\n    n = len(str)\n    res = []\n    while 0 <= i < n:\n        o_match = _OctalPatt.search(str, i)\n        q_match = _QuotePatt.search(str, i)\n        if not o_match and not q_match:              # Neither matched\n            res.append(str[i:])\n            break\n        # else:\n        j = k = -1\n        if o_match:\n            j = o_match.start(0)\n        if q_match:\n            k = q_match.start(0)\n        if q_match and (not o_match or k < j):     # QuotePatt matched\n            res.append(str[i:k])\n            res.append(str[k + 1])\n            i = k + 2\n        else:                                      # OctalPatt matched\n            res.append(str[i:j])\n            res.append(chr(int(str[j + 1:j + 4], 8)))\n            i = j + 4\n    return _nulljoin(res)\n\n\ndef parse_cookie(cookie):\n    \"\"\"Parse a ``Cookie`` HTTP header into a dict of name/value pairs.\n\n    This function attempts to mimic browser cookie parsing behavior;\n    it specifically does not follow any of the cookie-related RFCs\n    (because browsers don't either).\n\n    The algorithm used is identical to that used by Django version 1.9.10.\n\n    .. versionadded:: 4.4.2\n    \"\"\"\n    cookiedict = {}\n    for chunk in cookie.split(str(';')):\n        if str('=') in chunk:\n            key, val = chunk.split(str('='), 1)\n        else:\n            # Assume an empty name per\n            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n            key, val = str(''), chunk\n        key, val = key.strip(), val.strip()\n        if key or val:\n            # unquote using Python's algorithm.\n            cookiedict[key] = _unquote_cookie(val)\n    return cookiedict\n",
            "new_file_content": "#!/usr/bin/env python\n#\n# Copyright 2009 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\"\"\"HTTP utility code shared by clients and servers.\n\nThis module also defines the `HTTPServerRequest` class which is exposed\nvia `tornado.web.RequestHandler.request`.\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function\n\nimport calendar\nimport collections\nimport copy\nimport datetime\nimport email.utils\nimport numbers\nimport re\nimport time\n\nfrom tornado.escape import native_str, parse_qs_bytes, utf8\nfrom tornado.log import gen_log\nfrom tornado.util import ObjectDict, PY3\n\nif PY3:\n    import http.cookies as Cookie\n    from http.client import responses\n    from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl\nelse:\n    import Cookie\n    from httplib import responses\n    from urllib import urlencode\n    from urlparse import urlparse, urlunparse, parse_qsl\n\n\n# responses is unused in this file, but we re-export it to other files.\n# Reference it so pyflakes doesn't complain.\nresponses\n\ntry:\n    from ssl import SSLError\nexcept ImportError:\n    # ssl is unavailable on app engine.\n    class _SSLError(Exception):\n        pass\n    # Hack around a mypy limitation. We can't simply put \"type: ignore\"\n    # on the class definition itself; must go through an assignment.\n    SSLError = _SSLError  # type: ignore\n\ntry:\n    import typing\nexcept ImportError:\n    pass\n\n\n# RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line\n# terminator and ignore any preceding CR.\n_CRLF_RE = re.compile(r'\\r?\\n')\n\n\nclass _NormalizedHeaderCache(dict):\n    \"\"\"Dynamic cached mapping of header names to Http-Header-Case.\n\n    Implemented as a dict subclass so that cache hits are as fast as a\n    normal dict lookup, without the overhead of a python function\n    call.\n\n    >>> normalized_headers = _NormalizedHeaderCache(10)\n    >>> normalized_headers[\"coNtent-TYPE\"]\n    'Content-Type'\n    \"\"\"\n    def __init__(self, size):\n        super(_NormalizedHeaderCache, self).__init__()\n        self.size = size\n        self.queue = collections.deque()\n\n    def __missing__(self, key):\n        normalized = \"-\".join([w.capitalize() for w in key.split(\"-\")])\n        self[key] = normalized\n        self.queue.append(key)\n        if len(self.queue) > self.size:\n            # Limit the size of the cache.  LRU would be better, but this\n            # simpler approach should be fine.  In Python 2.7+ we could\n            # use OrderedDict (or in 3.2+, @functools.lru_cache).\n            old_key = self.queue.popleft()\n            del self[old_key]\n        return normalized\n\n\n_normalized_headers = _NormalizedHeaderCache(1000)\n\n\nclass HTTPHeaders(collections.MutableMapping):\n    \"\"\"A dictionary that maintains ``Http-Header-Case`` for all keys.\n\n    Supports multiple values per key via a pair of new methods,\n    `add()` and `get_list()`.  The regular dictionary interface\n    returns a single value per key, with multiple values joined by a\n    comma.\n\n    >>> h = HTTPHeaders({\"content-type\": \"text/html\"})\n    >>> list(h.keys())\n    ['Content-Type']\n    >>> h[\"Content-Type\"]\n    'text/html'\n\n    >>> h.add(\"Set-Cookie\", \"A=B\")\n    >>> h.add(\"Set-Cookie\", \"C=D\")\n    >>> h[\"set-cookie\"]\n    'A=B,C=D'\n    >>> h.get_list(\"set-cookie\")\n    ['A=B', 'C=D']\n\n    >>> for (k,v) in sorted(h.get_all()):\n    ...    print('%s: %s' % (k,v))\n    ...\n    Content-Type: text/html\n    Set-Cookie: A=B\n    Set-Cookie: C=D\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self._dict = {}  # type: typing.Dict[str, str]\n        self._as_list = {}  # type: typing.Dict[str, typing.List[str]]\n        self._last_key = None\n        if (len(args) == 1 and len(kwargs) == 0 and\n                isinstance(args[0], HTTPHeaders)):\n            # Copy constructor\n            for k, v in args[0].get_all():\n                self.add(k, v)\n        else:\n            # Dict-style initialization\n            self.update(*args, **kwargs)\n\n    # new public methods\n\n    def add(self, name, value):\n        # type: (str, str) -> None\n        \"\"\"Adds a new value for the given key.\"\"\"\n        norm_name = _normalized_headers[name]\n        self._last_key = norm_name\n        if norm_name in self:\n            self._dict[norm_name] = (native_str(self[norm_name]) + ',' +\n                                     native_str(value))\n            self._as_list[norm_name].append(value)\n        else:\n            self[norm_name] = value\n\n    def get_list(self, name):\n        \"\"\"Returns all values for the given header as a list.\"\"\"\n        norm_name = _normalized_headers[name]\n        return self._as_list.get(norm_name, [])\n\n    def get_all(self):\n        # type: () -> typing.Iterable[typing.Tuple[str, str]]\n        \"\"\"Returns an iterable of all (name, value) pairs.\n\n        If a header has multiple values, multiple pairs will be\n        returned with the same name.\n        \"\"\"\n        for name, values in self._as_list.items():\n            for value in values:\n                yield (name, value)\n\n    def parse_line(self, line):\n        \"\"\"Updates the dictionary with a single header line.\n\n        >>> h = HTTPHeaders()\n        >>> h.parse_line(\"Content-Type: text/html\")\n        >>> h.get('content-type')\n        'text/html'\n        \"\"\"\n        if line[0].isspace():\n            # continuation of a multi-line header\n            new_part = ' ' + line.lstrip()\n            self._as_list[self._last_key][-1] += new_part\n            self._dict[self._last_key] += new_part\n        else:\n            name, value = line.split(\":\", 1)\n            self.add(name, value.strip())\n\n    @classmethod\n    def parse(cls, headers):\n        \"\"\"Returns a dictionary from HTTP header text.\n\n        >>> h = HTTPHeaders.parse(\"Content-Type: text/html\\\\r\\\\nContent-Length: 42\\\\r\\\\n\")\n        >>> sorted(h.items())\n        [('Content-Length', '42'), ('Content-Type', 'text/html')]\n        \"\"\"\n        h = cls()\n        for line in _CRLF_RE.split(headers):\n            if line:\n                h.parse_line(line)\n        return h\n\n    # MutableMapping abstract method implementations.\n\n    def __setitem__(self, name, value):\n        norm_name = _normalized_headers[name]\n        self._dict[norm_name] = value\n        self._as_list[norm_name] = [value]\n\n    def __getitem__(self, name):\n        # type: (str) -> str\n        return self._dict[_normalized_headers[name]]\n\n    def __delitem__(self, name):\n        norm_name = _normalized_headers[name]\n        del self._dict[norm_name]\n        del self._as_list[norm_name]\n\n    def __len__(self):\n        return len(self._dict)\n\n    def __iter__(self):\n        return iter(self._dict)\n\n    def copy(self):\n        # defined in dict but not in MutableMapping.\n        return HTTPHeaders(self)\n\n    # Use our overridden copy method for the copy.copy module.\n    # This makes shallow copies one level deeper, but preserves\n    # the appearance that HTTPHeaders is a single container.\n    __copy__ = copy\n\n    def __str__(self):\n        lines = []\n        for name, value in self.get_all():\n            lines.append(\"%s: %s\\n\" % (name, value))\n        return \"\".join(lines)\n\n    __unicode__ = __str__\n\n\nclass HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s)\" % (self.__class__.__name__, args)\n\n\nclass HTTPInputError(Exception):\n    \"\"\"Exception class for malformed HTTP requests or responses\n    from remote sources.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPOutputError(Exception):\n    \"\"\"Exception class for errors in HTTP output.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPServerConnectionDelegate(object):\n    \"\"\"Implement this interface to handle requests from `.HTTPServer`.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def start_request(self, server_conn, request_conn):\n        \"\"\"This method is called by the server when a new request has started.\n\n        :arg server_conn: is an opaque object representing the long-lived\n            (e.g. tcp-level) connection.\n        :arg request_conn: is a `.HTTPConnection` object for a single\n            request/response exchange.\n\n        This method should return a `.HTTPMessageDelegate`.\n        \"\"\"\n        raise NotImplementedError()\n\n    def on_close(self, server_conn):\n        \"\"\"This method is called when a connection has been closed.\n\n        :arg server_conn: is a server connection that has previously been\n            passed to ``start_request``.\n        \"\"\"\n        pass\n\n\nclass HTTPMessageDelegate(object):\n    \"\"\"Implement this interface to handle an HTTP request or response.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def headers_received(self, start_line, headers):\n        \"\"\"Called when the HTTP headers have been received and parsed.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`\n            depending on whether this is a client or server message.\n        :arg headers: a `.HTTPHeaders` instance.\n\n        Some `.HTTPConnection` methods can only be called during\n        ``headers_received``.\n\n        May return a `.Future`; if it does the body will not be read\n        until it is done.\n        \"\"\"\n        pass\n\n    def data_received(self, chunk):\n        \"\"\"Called when a chunk of data has been received.\n\n        May return a `.Future` for flow control.\n        \"\"\"\n        pass\n\n    def finish(self):\n        \"\"\"Called after the last chunk of data has been received.\"\"\"\n        pass\n\n    def on_connection_close(self):\n        \"\"\"Called if the connection is closed without finishing the request.\n\n        If ``headers_received`` is called, either ``finish`` or\n        ``on_connection_close`` will be called, but not both.\n        \"\"\"\n        pass\n\n\nclass HTTPConnection(object):\n    \"\"\"Applications use this interface to write their responses.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def write_headers(self, start_line, headers, chunk=None, callback=None):\n        \"\"\"Write an HTTP header block.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.\n        :arg headers: a `.HTTPHeaders` instance.\n        :arg chunk: the first (optional) chunk of data.  This is an optimization\n            so that small responses can be written in the same call as their\n            headers.\n        :arg callback: a callback to be run when the write is complete.\n\n        The ``version`` field of ``start_line`` is ignored.\n\n        Returns a `.Future` if no callback is given.\n        \"\"\"\n        raise NotImplementedError()\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes a chunk of body data.\n\n        The callback will be run when the write is complete.  If no callback\n        is given, returns a Future.\n        \"\"\"\n        raise NotImplementedError()\n\n    def finish(self):\n        \"\"\"Indicates that the last body data has been written.\n        \"\"\"\n        raise NotImplementedError()\n\n\ndef url_concat(url, args):\n    \"\"\"Concatenate url and arguments regardless of whether\n    url has existing query parameters.\n\n    ``args`` may be either a dictionary or a list of key-value pairs\n    (the latter allows for multiple values with the same key.\n\n    >>> url_concat(\"http://example.com/foo\", dict(c=\"d\"))\n    'http://example.com/foo?c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", dict(c=\"d\"))\n    'http://example.com/foo?a=b&c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", [(\"c\", \"d\"), (\"c\", \"d2\")])\n    'http://example.com/foo?a=b&c=d&c=d2'\n    \"\"\"\n    if args is None:\n        return url\n    parsed_url = urlparse(url)\n    if isinstance(args, dict):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args.items())\n    elif isinstance(args, list) or isinstance(args, tuple):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args)\n    else:\n        err = \"'args' parameter should be dict, list or tuple. Not {0}\".format(\n            type(args))\n        raise TypeError(err)\n    final_query = urlencode(parsed_query)\n    url = urlunparse((\n        parsed_url[0],\n        parsed_url[1],\n        parsed_url[2],\n        parsed_url[3],\n        final_query,\n        parsed_url[5]))\n    return url\n\n\nclass HTTPFile(ObjectDict):\n    \"\"\"Represents a file uploaded via a form.\n\n    For backwards compatibility, its instance attributes are also\n    accessible as dictionary keys.\n\n    * ``filename``\n    * ``body``\n    * ``content_type``\n    \"\"\"\n    pass\n\n\ndef _parse_request_range(range_header):\n    \"\"\"Parses a Range header.\n\n    Returns either ``None`` or tuple ``(start, end)``.\n    Note that while the HTTP headers use inclusive byte positions,\n    this method returns indexes suitable for use in slices.\n\n    >>> start, end = _parse_request_range(\"bytes=1-2\")\n    >>> start, end\n    (1, 3)\n    >>> [0, 1, 2, 3, 4][start:end]\n    [1, 2]\n    >>> _parse_request_range(\"bytes=6-\")\n    (6, None)\n    >>> _parse_request_range(\"bytes=-6\")\n    (-6, None)\n    >>> _parse_request_range(\"bytes=-0\")\n    (None, 0)\n    >>> _parse_request_range(\"bytes=\")\n    (None, None)\n    >>> _parse_request_range(\"foo=42\")\n    >>> _parse_request_range(\"bytes=1-2,6-10\")\n\n    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).\n\n    See [0] for the details of the range header.\n\n    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges\n    \"\"\"\n    unit, _, value = range_header.partition(\"=\")\n    unit, value = unit.strip(), value.strip()\n    if unit != \"bytes\":\n        return None\n    start_b, _, end_b = value.partition(\"-\")\n    try:\n        start = _int_or_none(start_b)\n        end = _int_or_none(end_b)\n    except ValueError:\n        return None\n    if end is not None:\n        if start is None:\n            if end != 0:\n                start = -end\n                end = None\n        else:\n            end += 1\n    return (start, end)\n\n\ndef _get_content_range(start, end, total):\n    \"\"\"Returns a suitable Content-Range header:\n\n    >>> print(_get_content_range(None, 1, 4))\n    bytes 0-0/4\n    >>> print(_get_content_range(1, 3, 4))\n    bytes 1-2/4\n    >>> print(_get_content_range(None, None, 4))\n    bytes 0-3/4\n    \"\"\"\n    start = start or 0\n    end = (end or total) - 1\n    return \"bytes %s-%s/%s\" % (start, end, total)\n\n\ndef _int_or_none(val):\n    val = val.strip()\n    if val == \"\":\n        return None\n    return int(val)\n\n\ndef parse_body_arguments(content_type, body, arguments, files, headers=None):\n    \"\"\"Parses a form request body.\n\n    Supports ``application/x-www-form-urlencoded`` and\n    ``multipart/form-data``.  The ``content_type`` parameter should be\n    a string and ``body`` should be a byte string.  The ``arguments``\n    and ``files`` parameters are dictionaries that will be updated\n    with the parsed contents.\n    \"\"\"\n    if headers and 'Content-Encoding' in headers:\n        gen_log.warning(\"Unsupported Content-Encoding: %s\",\n                        headers['Content-Encoding'])\n        return\n    if content_type.startswith(\"application/x-www-form-urlencoded\"):\n        try:\n            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)\n        except Exception as e:\n            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)\n            uri_arguments = {}\n        for name, values in uri_arguments.items():\n            if values:\n                arguments.setdefault(name, []).extend(values)\n    elif content_type.startswith(\"multipart/form-data\"):\n        try:\n            fields = content_type.split(\";\")\n            for field in fields:\n                k, sep, v = field.strip().partition(\"=\")\n                if k == \"boundary\" and v:\n                    parse_multipart_form_data(utf8(v), body, arguments, files)\n                    break\n            else:\n                raise ValueError(\"multipart boundary not found\")\n        except Exception as e:\n            gen_log.warning(\"Invalid multipart/form-data: %s\", e)\n\n\ndef parse_multipart_form_data(boundary, data, arguments, files):\n    \"\"\"Parses a ``multipart/form-data`` body.\n\n    The ``boundary`` and ``data`` parameters are both byte strings.\n    The dictionaries given in the arguments and files parameters\n    will be updated with the contents of the body.\n    \"\"\"\n    # The standard allows for the boundary to be quoted in the header,\n    # although it's rare (it happens at least for google app engine\n    # xmpp).  I think we're also supposed to handle backslash-escapes\n    # here but I'll save that until we see a client that uses them\n    # in the wild.\n    if boundary.startswith(b'\"') and boundary.endswith(b'\"'):\n        boundary = boundary[1:-1]\n    final_boundary_index = data.rfind(b\"--\" + boundary + b\"--\")\n    if final_boundary_index == -1:\n        gen_log.warning(\"Invalid multipart/form-data: no final boundary\")\n        return\n    parts = data[:final_boundary_index].split(b\"--\" + boundary + b\"\\r\\n\")\n    for part in parts:\n        if not part:\n            continue\n        eoh = part.find(b\"\\r\\n\\r\\n\")\n        if eoh == -1:\n            gen_log.warning(\"multipart/form-data missing headers\")\n            continue\n        headers = HTTPHeaders.parse(part[:eoh].decode(\"utf-8\"))\n        disp_header = headers.get(\"Content-Disposition\", \"\")\n        disposition, disp_params = _parse_header(disp_header)\n        if disposition != \"form-data\" or not part.endswith(b\"\\r\\n\"):\n            gen_log.warning(\"Invalid multipart/form-data\")\n            continue\n        value = part[eoh + 4:-2]\n        if not disp_params.get(\"name\"):\n            gen_log.warning(\"multipart/form-data value missing name\")\n            continue\n        name = disp_params[\"name\"]\n        if disp_params.get(\"filename\"):\n            ctype = headers.get(\"Content-Type\", \"application/unknown\")\n            files.setdefault(name, []).append(HTTPFile(  # type: ignore\n                filename=disp_params[\"filename\"], body=value,\n                content_type=ctype))\n        else:\n            arguments.setdefault(name, []).append(value)\n\n\ndef format_timestamp(ts):\n    \"\"\"Formats a timestamp in the format used by HTTP.\n\n    The argument may be a numeric timestamp as returned by `time.time`,\n    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`\n    object.\n\n    >>> format_timestamp(1359312200)\n    'Sun, 27 Jan 2013 18:43:20 GMT'\n    \"\"\"\n    if isinstance(ts, numbers.Real):\n        pass\n    elif isinstance(ts, (tuple, time.struct_time)):\n        ts = calendar.timegm(ts)\n    elif isinstance(ts, datetime.datetime):\n        ts = calendar.timegm(ts.utctimetuple())\n    else:\n        raise TypeError(\"unknown timestamp type: %r\" % ts)\n    return email.utils.formatdate(ts, usegmt=True)\n\n\nRequestStartLine = collections.namedtuple(\n    'RequestStartLine', ['method', 'path', 'version'])\n\n\ndef parse_request_start_line(line):\n    \"\"\"Returns a (method, path, version) tuple for an HTTP 1.x request line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_request_start_line(\"GET /foo HTTP/1.1\")\n    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')\n    \"\"\"\n    try:\n        method, path, version = line.split(\" \")\n    except ValueError:\n        # https://tools.ietf.org/html/rfc7230#section-3.1.1\n        # invalid request-line SHOULD respond with a 400 (Bad Request)\n        raise HTTPInputError(\"Malformed HTTP request line\")\n    if not re.match(r\"^HTTP/1\\.[0-9]$\", version):\n        raise HTTPInputError(\n            \"Malformed HTTP version in HTTP Request-Line: %r\" % version)\n    return RequestStartLine(method, path, version)\n\n\nResponseStartLine = collections.namedtuple(\n    'ResponseStartLine', ['version', 'code', 'reason'])\n\n\ndef parse_response_start_line(line):\n    \"\"\"Returns a (version, code, reason) tuple for an HTTP 1.x response line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_response_start_line(\"HTTP/1.1 200 OK\")\n    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')\n    \"\"\"\n    line = native_str(line)\n    match = re.match(\"(HTTP/1.[0-9]) ([0-9]+) ([^\\r]*)\", line)\n    if not match:\n        raise HTTPInputError(\"Error parsing response start line\")\n    return ResponseStartLine(match.group(1), int(match.group(2)),\n                             match.group(3))\n\n# _parseparam and _parse_header are copied and modified from python2.7's cgi.py\n# The original 2.7 version of this code did not correctly support some\n# combinations of semicolons and double quotes.\n# It has also been modified to support valueless parameters as seen in\n# websocket extension negotiations.\n\n\ndef _parseparam(s):\n    while s[:1] == ';':\n        s = s[1:]\n        end = s.find(';')\n        while end > 0 and (s.count('\"', 0, end) - s.count('\\\\\"', 0, end)) % 2:\n            end = s.find(';', end + 1)\n        if end < 0:\n            end = len(s)\n        f = s[:end]\n        yield f.strip()\n        s = s[end:]\n\n\ndef _parse_header(line):\n    \"\"\"Parse a Content-type like header.\n\n    Return the main content-type and a dictionary of options.\n\n    \"\"\"\n    parts = _parseparam(';' + line)\n    key = next(parts)\n    pdict = {}\n    for p in parts:\n        i = p.find('=')\n        if i >= 0:\n            name = p[:i].strip().lower()\n            value = p[i + 1:].strip()\n            if len(value) >= 2 and value[0] == value[-1] == '\"':\n                value = value[1:-1]\n                value = value.replace('\\\\\\\\', '\\\\').replace('\\\\\"', '\"')\n            pdict[name] = value\n        else:\n            pdict[p] = None\n    return key, pdict\n\n\ndef _encode_header(key, pdict):\n    \"\"\"Inverse of _parse_header.\n\n    >>> _encode_header('permessage-deflate',\n    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})\n    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'\n    \"\"\"\n    if not pdict:\n        return key\n    out = [key]\n    # Sort the parameters just to make it easy to test.\n    for k, v in sorted(pdict.items()):\n        if v is None:\n            out.append(k)\n        else:\n            # TODO: quote if necessary.\n            out.append('%s=%s' % (k, v))\n    return '; '.join(out)\n\n\ndef doctests():\n    import doctest\n    return doctest.DocTestSuite()\n\n\ndef split_host_and_port(netloc):\n    \"\"\"Returns ``(host, port)`` tuple from ``netloc``.\n\n    Returned ``port`` will be ``None`` if not present.\n\n    .. versionadded:: 4.1\n    \"\"\"\n    match = re.match(r'^(.+):(\\d+)$', netloc)\n    if match:\n        host = match.group(1)\n        port = int(match.group(2))\n    else:\n        host = netloc\n        port = None\n    return (host, port)\n\n\ndef qs_to_qsl(qs):\n    \"\"\"Generator rewinding a result of ``parse_qs`` back to name-value pairs. \n    \"\"\"\n    for k, vs in qs.items():\n        for v in vs:\n            yield (k, v)\n\n\n_OctalPatt = re.compile(r\"\\\\[0-3][0-7][0-7]\")\n_QuotePatt = re.compile(r\"[\\\\].\")\n_nulljoin = ''.join\n\n\ndef _unquote_cookie(str):\n    \"\"\"Handle double quotes and escaping in cookie values.\n\n    This method is copied verbatim from the Python 3.5 standard\n    library (http.cookies._unquote) so we don't have to depend on\n    non-public interfaces.\n    \"\"\"\n    # If there aren't any doublequotes,\n    # then there can't be any special characters.  See RFC 2109.\n    if str is None or len(str) < 2:\n        return str\n    if str[0] != '\"' or str[-1] != '\"':\n        return str\n\n    # We have to assume that we must decode this string.\n    # Down to work.\n\n    # Remove the \"s\n    str = str[1:-1]\n\n    # Check for special sequences.  Examples:\n    #    \\012 --> \\n\n    #    \\\"   --> \"\n    #\n    i = 0\n    n = len(str)\n    res = []\n    while 0 <= i < n:\n        o_match = _OctalPatt.search(str, i)\n        q_match = _QuotePatt.search(str, i)\n        if not o_match and not q_match:              # Neither matched\n            res.append(str[i:])\n            break\n        # else:\n        j = k = -1\n        if o_match:\n            j = o_match.start(0)\n        if q_match:\n            k = q_match.start(0)\n        if q_match and (not o_match or k < j):     # QuotePatt matched\n            res.append(str[i:k])\n            res.append(str[k + 1])\n            i = k + 2\n        else:                                      # OctalPatt matched\n            res.append(str[i:j])\n            res.append(chr(int(str[j + 1:j + 4], 8)))\n            i = j + 4\n    return _nulljoin(res)\n\n\ndef parse_cookie(cookie):\n    \"\"\"Parse a ``Cookie`` HTTP header into a dict of name/value pairs.\n\n    This function attempts to mimic browser cookie parsing behavior;\n    it specifically does not follow any of the cookie-related RFCs\n    (because browsers don't either).\n\n    The algorithm used is identical to that used by Django version 1.9.10.\n\n    .. versionadded:: 4.4.2\n    \"\"\"\n    cookiedict = {}\n    for chunk in cookie.split(str(';')):\n        if str('=') in chunk:\n            key, val = chunk.split(str('='), 1)\n        else:\n            # Assume an empty name per\n            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n            key, val = str(''), chunk\n        key, val = key.strip(), val.strip()\n        if key or val:\n            # unquote using Python's algorithm.\n            cookiedict[key] = _unquote_cookie(val)\n    return cookiedict\n",
            "header": {
                "file": {
                    "path": "tornado/httputil.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "a98273ae",
                "new_commit_hash": "f2b289b3",
                "mode": "100755"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/httputil.py"
            },
            "plus_file": {
                "path": "b/tornado/httputil.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 467,
                            "length": 8
                        },
                        "new_range": {
                            "start": 467,
                            "length": 7
                        },
                        "section": "class HTTPServerRequest(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    def __repr__(self):",
                                "type": "context"
                            },
                            {
                                "content": "        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")",
                                "type": "context"
                            },
                            {
                                "content": "        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])",
                                "type": "context"
                            },
                            {
                                "content": "        return \"%s(%s, headers=%s)\" % (",
                                "type": "deleted"
                            },
                            {
                                "content": "            self.__class__.__name__, args, dict(self.headers))",
                                "type": "deleted"
                            },
                            {
                                "content": "        return \"%s(%s)\" % (self.__class__.__name__, args)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class HTTPInputError(Exception):",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/httputil.py",
                            "type": "class",
                            "name": "HTTPServerRequest",
                            "content": "class HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s, headers=%s)\" % (\n            self.__class__.__name__, args, dict(self.headers))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 248,
                            "end_lineno": 471,
                            "parent": null
                        },
                        {
                            "file_name": "tornado/httputil.py",
                            "type": "method",
                            "name": "HTTPServerRequest.__repr__",
                            "content": "class HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s, headers=%s)\" % (\n            self.__class__.__name__, args, dict(self.headers))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 467,
                            "end_lineno": 471,
                            "parent": {
                                "file_name": "tornado/httputil.py",
                                "type": "class",
                                "name": "HTTPServerRequest",
                                "content": "class HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s, headers=%s)\" % (\n            self.__class__.__name__, args, dict(self.headers))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 248,
                                "end_lineno": 471,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\nfrom __future__ import absolute_import, division, print_function\nfrom tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp, HTTPServerRequest, parse_request_start_line, parse_cookie, qs_to_qsl, PY3\nfrom tornado.escape import utf8, native_str\nfrom tornado.log import gen_log\nfrom tornado.testing import ExpectLog\nfrom tornado.test.util import unittest\n\nimport copy\nimport datetime\nimport logging\nimport pickle\nimport time\n\nif PY3:\n    import urllib.parse as urllib_parse\nelse:\n    import urlparse as urllib_parse\n\n\nclass TestUrlConcat(unittest.TestCase):\n    def test_url_concat_no_query_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_encode_args(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', '/y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=%2Fy&z=z\")\n\n    def test_url_concat_trailing_q(self):\n        url = url_concat(\n            \"https://localhost/path?\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_q_with_no_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x&\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_mult_params(self):\n        url = url_concat(\n            \"https://localhost/path?a=1&b=2\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?a=1&b=2&y=y&z=z\")\n\n    def test_url_concat_no_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            [],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_none_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            None,\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_with_frag(self):\n        url = url_concat(\n            \"https://localhost/path#tab\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y#tab\")\n\n    def test_url_concat_multi_same_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y1'), ('y', 'y2')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y1&y=y2\")\n\n    def test_url_concat_multi_same_query_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&r=2\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&r=2&y=y\")\n\n    def test_url_concat_dict_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            dict(y='y'),\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y\")\n\n\nclass QsParseTest(unittest.TestCase):\n\n    def test_parsing(self):\n        qsstring = \"a=1&b=2&a=3\"\n        qs = urllib_parse.parse_qs(qsstring)\n        qsl = list(qs_to_qsl(qs))\n        self.assertIn(('a', '1'), qsl)\n        self.assertIn(('a', '3'), qsl)\n        self.assertIn(('b', '2'), qsl)\n\n\nclass MultipartFormDataTest(unittest.TestCase):\n    def test_file_upload(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_unquoted_names(self):\n        # quotes are optional unless special characters are present\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=files; filename=ab.txt\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_special_filenames(self):\n        filenames = ['a;b.txt',\n                     'a\"b.txt',\n                     'a\";b.txt',\n                     'a;\"b.txt',\n                     'a\";\";.txt',\n                     'a\\\\\"b.txt',\n                     'a\\\\b.txt',\n                     ]\n        for filename in filenames:\n            logging.debug(\"trying filename %r\", filename)\n            data = \"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"%s\"\n\nFoo\n--1234--\"\"\" % filename.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"')\n            data = utf8(data.replace(\"\\n\", \"\\r\\n\"))\n            args = {}\n            files = {}\n            parse_multipart_form_data(b\"1234\", data, args, files)\n            file = files[\"files\"][0]\n            self.assertEqual(file[\"filename\"], filename)\n            self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_boundary_starts_and_ends_with_quotes(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b'\"1234\"', data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_missing_headers(self):\n        data = b'''\\\n--1234\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data missing headers\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_invalid_content_disposition(self):\n        data = b'''\\\n--1234\nContent-Disposition: invalid; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_line_does_not_end_with_correct_line_break(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_content_disposition_header_without_name_parameter(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data value missing name\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_data_after_final_boundary(self):\n        # The spec requires that data after the final boundary be ignored.\n        # http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html\n        # In practice, some libraries include an extra CRLF after the boundary.\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\n\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n\nclass HTTPHeadersTest(unittest.TestCase):\n    def test_multi_line(self):\n        # Lines beginning with whitespace are appended to the previous line\n        # with any leading whitespace replaced by a single space.\n        # Note that while multi-line headers are a part of the HTTP spec,\n        # their use is strongly discouraged.\n        data = \"\"\"\\\nFoo: bar\n baz\nAsdf: qwer\n\\tzxcv\nFoo: even\n     more\n     lines\n\"\"\".replace(\"\\n\", \"\\r\\n\")\n        headers = HTTPHeaders.parse(data)\n        self.assertEqual(headers[\"asdf\"], \"qwer zxcv\")\n        self.assertEqual(headers.get_list(\"asdf\"), [\"qwer zxcv\"])\n        self.assertEqual(headers[\"Foo\"], \"bar baz,even more lines\")\n        self.assertEqual(headers.get_list(\"foo\"), [\"bar baz\", \"even more lines\"])\n        self.assertEqual(sorted(list(headers.get_all())),\n                         [(\"Asdf\", \"qwer zxcv\"),\n                          (\"Foo\", \"bar baz\"),\n                          (\"Foo\", \"even more lines\")])\n\n    def test_unicode_newlines(self):\n        # Ensure that only \\r\\n is recognized as a header separator, and not\n        # the other newline-like unicode characters.\n        # Characters that are likely to be problematic can be found in\n        # http://unicode.org/standard/reports/tr13/tr13-5.html\n        # and cpython's unicodeobject.c (which defines the implementation\n        # of unicode_type.splitlines(), and uses a different list than TR13).\n        newlines = [\n            u'\\u001b',  # VERTICAL TAB\n            u'\\u001c',  # FILE SEPARATOR\n            u'\\u001d',  # GROUP SEPARATOR\n            u'\\u001e',  # RECORD SEPARATOR\n            u'\\u0085',  # NEXT LINE\n            u'\\u2028',  # LINE SEPARATOR\n            u'\\u2029',  # PARAGRAPH SEPARATOR\n        ]\n        for newline in newlines:\n            # Try the utf8 and latin1 representations of each newline\n            for encoding in ['utf8', 'latin1']:\n                try:\n                    try:\n                        encoded = newline.encode(encoding)\n                    except UnicodeEncodeError:\n                        # Some chars cannot be represented in latin1\n                        continue\n                    data = b'Cookie: foo=' + encoded + b'bar'\n                    # parse() wants a native_str, so decode through latin1\n                    # in the same way the real parser does.\n                    headers = HTTPHeaders.parse(\n                        native_str(data.decode('latin1')))\n                    expected = [('Cookie', 'foo=' +\n                                 native_str(encoded.decode('latin1')) + 'bar')]\n                    self.assertEqual(\n                        expected, list(headers.get_all()))\n                except Exception:\n                    gen_log.warning(\"failed while trying %r in %s\",\n                                    newline, encoding)\n                    raise\n\n    def test_optional_cr(self):\n        # Both CRLF and LF should be accepted as separators. CR should not be\n        # part of the data when followed by LF, but it is a normal char\n        # otherwise (or should bare CR be an error?)\n        headers = HTTPHeaders.parse(\n            'CRLF: crlf\\r\\nLF: lf\\nCR: cr\\rMore: more\\r\\n')\n        self.assertEqual(sorted(headers.get_all()),\n                         [('Cr', 'cr\\rMore: more'),\n                          ('Crlf', 'crlf'),\n                          ('Lf', 'lf'),\n                          ])\n\n    def test_copy(self):\n        all_pairs = [('A', '1'), ('A', '2'), ('B', 'c')]\n        h1 = HTTPHeaders()\n        for k, v in all_pairs:\n            h1.add(k, v)\n        h2 = h1.copy()\n        h3 = copy.copy(h1)\n        h4 = copy.deepcopy(h1)\n        for headers in [h1, h2, h3, h4]:\n            # All the copies are identical, no matter how they were\n            # constructed.\n            self.assertEqual(list(sorted(headers.get_all())), all_pairs)\n        for headers in [h2, h3, h4]:\n            # Neither the dict or its member lists are reused.\n            self.assertIsNot(headers, h1)\n            self.assertIsNot(headers.get_list('A'), h1.get_list('A'))\n\n    def test_pickle_roundtrip(self):\n        headers = HTTPHeaders()\n        headers.add('Set-Cookie', 'a=b')\n        headers.add('Set-Cookie', 'c=d')\n        headers.add('Content-Type', 'text/html')\n        pickled = pickle.dumps(headers)\n        unpickled = pickle.loads(pickled)\n        self.assertEqual(sorted(headers.get_all()), sorted(unpickled.get_all()))\n        self.assertEqual(sorted(headers.items()), sorted(unpickled.items()))\n\n    def test_setdefault(self):\n        headers = HTTPHeaders()\n        headers['foo'] = 'bar'\n        # If a value is present, setdefault returns it without changes.\n        self.assertEqual(headers.setdefault('foo', 'baz'), 'bar')\n        self.assertEqual(headers['foo'], 'bar')\n        # If a value is not present, setdefault sets it for future use.\n        self.assertEqual(headers.setdefault('quux', 'xyzzy'), 'xyzzy')\n        self.assertEqual(headers['quux'], 'xyzzy')\n        self.assertEqual(sorted(headers.get_all()), [('Foo', 'bar'), ('Quux', 'xyzzy')])\n\n    def test_string(self):\n        headers = HTTPHeaders()\n        headers.add(\"Foo\", \"1\")\n        headers.add(\"Foo\", \"2\")\n        headers.add(\"Foo\", \"3\")\n        headers2 = HTTPHeaders.parse(str(headers))\n        self.assertEquals(headers, headers2)\n\n\nclass FormatTimestampTest(unittest.TestCase):\n    # Make sure that all the input types are supported.\n    TIMESTAMP = 1359312200.503611\n    EXPECTED = 'Sun, 27 Jan 2013 18:43:20 GMT'\n\n    def check(self, value):\n        self.assertEqual(format_timestamp(value), self.EXPECTED)\n\n    def test_unix_time_float(self):\n        self.check(self.TIMESTAMP)\n\n    def test_unix_time_int(self):\n        self.check(int(self.TIMESTAMP))\n\n    def test_struct_time(self):\n        self.check(time.gmtime(self.TIMESTAMP))\n\n    def test_time_tuple(self):\n        tup = tuple(time.gmtime(self.TIMESTAMP))\n        self.assertEqual(9, len(tup))\n        self.check(tup)\n\n    def test_datetime(self):\n        self.check(datetime.datetime.utcfromtimestamp(self.TIMESTAMP))\n\n\n# HTTPServerRequest is mainly tested incidentally to the server itself,\n# but this tests the parts of the class that can be tested in isolation.\nclass HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n\nclass ParseRequestStartLineTest(unittest.TestCase):\n    METHOD = \"GET\"\n    PATH = \"/foo\"\n    VERSION = \"HTTP/1.1\"\n\n    def test_parse_request_start_line(self):\n        start_line = \" \".join([self.METHOD, self.PATH, self.VERSION])\n        parsed_start_line = parse_request_start_line(start_line)\n        self.assertEqual(parsed_start_line.method, self.METHOD)\n        self.assertEqual(parsed_start_line.path, self.PATH)\n        self.assertEqual(parsed_start_line.version, self.VERSION)\n\n\nclass ParseCookieTest(unittest.TestCase):\n    # These tests copied from Django:\n    # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28\n    def test_python_cookies(self):\n        \"\"\"\n        Test cases copied from Python's Lib/test/test_http_cookies.py\n        \"\"\"\n        self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'})\n        # Here parse_cookie() differs from Python's cookie parsing in that it\n        # treats all semicolons as delimiters, even within quotes.\n        self.assertEqual(\n            parse_cookie('keebler=\"E=mc2; L=\\\\\"Loves\\\\\"; fudge=\\\\012;\"'),\n            {'keebler': '\"E=mc2', 'L': '\\\\\"Loves\\\\\"', 'fudge': '\\\\012', '': '\"'}\n        )\n        # Illegal cookies that have an '=' char in an unquoted value.\n        self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'})\n        # Cookies with ':' character in their name.\n        self.assertEqual(parse_cookie('key:term=value:term'), {'key:term': 'value:term'})\n        # Cookies with '[' and ']'.\n        self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'})\n\n    def test_cookie_edgecases(self):\n        # Cookies that RFC6265 allows.\n        self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'})\n        # parse_cookie() has historically kept only the last cookie with the\n        # same name.\n        self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'})\n\n    def test_invalid_cookies(self):\n        \"\"\"\n        Cookie strings that go against RFC6265 but browsers will send if set\n        via document.cookie.\n        \"\"\"\n        # Chunks without an equals sign appear as unnamed values per\n        # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n        self.assertIn('django_language', parse_cookie('abc=def; unnamed; django_language=en').keys())\n        # Even a double quote may be an unamed value.\n        self.assertEqual(parse_cookie('a=b; \"; c=d'), {'a': 'b', '': '\"', 'c': 'd'})\n        # Spaces in names and values, and an equals sign in values.\n        self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c': 'd e = f', 'gh': 'i'})\n        # More characters the spec forbids.\n        self.assertEqual(parse_cookie('a   b,c<>@:/[]?{}=d  \"  =e,f g'), {'a   b,c<>@:/[]?{}': 'd  \"  =e,f g'})\n        # Unicode characters. The spec only allows ASCII.\n        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': native_str('André Bessette')})\n        # Browsers don't send extra whitespace or semicolons in Cookie headers,\n        # but parse_cookie() should parse whitespace the same way\n        # document.cookie parses whitespace.\n        self.assertEqual(parse_cookie('  =  b  ;  ;  =  ;   c  =  ;  '), {'': 'b', 'c': ''})\n",
            "new_file_content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\nfrom __future__ import absolute_import, division, print_function\nfrom tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp, HTTPServerRequest, parse_request_start_line, parse_cookie, qs_to_qsl, PY3\nfrom tornado.escape import utf8, native_str\nfrom tornado.log import gen_log\nfrom tornado.testing import ExpectLog\nfrom tornado.test.util import unittest\n\nimport copy\nimport datetime\nimport logging\nimport pickle\nimport time\n\nif PY3:\n    import urllib.parse as urllib_parse\nelse:\n    import urlparse as urllib_parse\n\n\nclass TestUrlConcat(unittest.TestCase):\n    def test_url_concat_no_query_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_encode_args(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', '/y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=%2Fy&z=z\")\n\n    def test_url_concat_trailing_q(self):\n        url = url_concat(\n            \"https://localhost/path?\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_q_with_no_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x&\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_mult_params(self):\n        url = url_concat(\n            \"https://localhost/path?a=1&b=2\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?a=1&b=2&y=y&z=z\")\n\n    def test_url_concat_no_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            [],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_none_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            None,\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_with_frag(self):\n        url = url_concat(\n            \"https://localhost/path#tab\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y#tab\")\n\n    def test_url_concat_multi_same_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y1'), ('y', 'y2')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y1&y=y2\")\n\n    def test_url_concat_multi_same_query_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&r=2\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&r=2&y=y\")\n\n    def test_url_concat_dict_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            dict(y='y'),\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y\")\n\n\nclass QsParseTest(unittest.TestCase):\n\n    def test_parsing(self):\n        qsstring = \"a=1&b=2&a=3\"\n        qs = urllib_parse.parse_qs(qsstring)\n        qsl = list(qs_to_qsl(qs))\n        self.assertIn(('a', '1'), qsl)\n        self.assertIn(('a', '3'), qsl)\n        self.assertIn(('b', '2'), qsl)\n\n\nclass MultipartFormDataTest(unittest.TestCase):\n    def test_file_upload(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_unquoted_names(self):\n        # quotes are optional unless special characters are present\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=files; filename=ab.txt\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_special_filenames(self):\n        filenames = ['a;b.txt',\n                     'a\"b.txt',\n                     'a\";b.txt',\n                     'a;\"b.txt',\n                     'a\";\";.txt',\n                     'a\\\\\"b.txt',\n                     'a\\\\b.txt',\n                     ]\n        for filename in filenames:\n            logging.debug(\"trying filename %r\", filename)\n            data = \"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"%s\"\n\nFoo\n--1234--\"\"\" % filename.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"')\n            data = utf8(data.replace(\"\\n\", \"\\r\\n\"))\n            args = {}\n            files = {}\n            parse_multipart_form_data(b\"1234\", data, args, files)\n            file = files[\"files\"][0]\n            self.assertEqual(file[\"filename\"], filename)\n            self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_boundary_starts_and_ends_with_quotes(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b'\"1234\"', data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_missing_headers(self):\n        data = b'''\\\n--1234\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data missing headers\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_invalid_content_disposition(self):\n        data = b'''\\\n--1234\nContent-Disposition: invalid; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_line_does_not_end_with_correct_line_break(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_content_disposition_header_without_name_parameter(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data value missing name\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_data_after_final_boundary(self):\n        # The spec requires that data after the final boundary be ignored.\n        # http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html\n        # In practice, some libraries include an extra CRLF after the boundary.\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\n\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n\nclass HTTPHeadersTest(unittest.TestCase):\n    def test_multi_line(self):\n        # Lines beginning with whitespace are appended to the previous line\n        # with any leading whitespace replaced by a single space.\n        # Note that while multi-line headers are a part of the HTTP spec,\n        # their use is strongly discouraged.\n        data = \"\"\"\\\nFoo: bar\n baz\nAsdf: qwer\n\\tzxcv\nFoo: even\n     more\n     lines\n\"\"\".replace(\"\\n\", \"\\r\\n\")\n        headers = HTTPHeaders.parse(data)\n        self.assertEqual(headers[\"asdf\"], \"qwer zxcv\")\n        self.assertEqual(headers.get_list(\"asdf\"), [\"qwer zxcv\"])\n        self.assertEqual(headers[\"Foo\"], \"bar baz,even more lines\")\n        self.assertEqual(headers.get_list(\"foo\"), [\"bar baz\", \"even more lines\"])\n        self.assertEqual(sorted(list(headers.get_all())),\n                         [(\"Asdf\", \"qwer zxcv\"),\n                          (\"Foo\", \"bar baz\"),\n                          (\"Foo\", \"even more lines\")])\n\n    def test_unicode_newlines(self):\n        # Ensure that only \\r\\n is recognized as a header separator, and not\n        # the other newline-like unicode characters.\n        # Characters that are likely to be problematic can be found in\n        # http://unicode.org/standard/reports/tr13/tr13-5.html\n        # and cpython's unicodeobject.c (which defines the implementation\n        # of unicode_type.splitlines(), and uses a different list than TR13).\n        newlines = [\n            u'\\u001b',  # VERTICAL TAB\n            u'\\u001c',  # FILE SEPARATOR\n            u'\\u001d',  # GROUP SEPARATOR\n            u'\\u001e',  # RECORD SEPARATOR\n            u'\\u0085',  # NEXT LINE\n            u'\\u2028',  # LINE SEPARATOR\n            u'\\u2029',  # PARAGRAPH SEPARATOR\n        ]\n        for newline in newlines:\n            # Try the utf8 and latin1 representations of each newline\n            for encoding in ['utf8', 'latin1']:\n                try:\n                    try:\n                        encoded = newline.encode(encoding)\n                    except UnicodeEncodeError:\n                        # Some chars cannot be represented in latin1\n                        continue\n                    data = b'Cookie: foo=' + encoded + b'bar'\n                    # parse() wants a native_str, so decode through latin1\n                    # in the same way the real parser does.\n                    headers = HTTPHeaders.parse(\n                        native_str(data.decode('latin1')))\n                    expected = [('Cookie', 'foo=' +\n                                 native_str(encoded.decode('latin1')) + 'bar')]\n                    self.assertEqual(\n                        expected, list(headers.get_all()))\n                except Exception:\n                    gen_log.warning(\"failed while trying %r in %s\",\n                                    newline, encoding)\n                    raise\n\n    def test_optional_cr(self):\n        # Both CRLF and LF should be accepted as separators. CR should not be\n        # part of the data when followed by LF, but it is a normal char\n        # otherwise (or should bare CR be an error?)\n        headers = HTTPHeaders.parse(\n            'CRLF: crlf\\r\\nLF: lf\\nCR: cr\\rMore: more\\r\\n')\n        self.assertEqual(sorted(headers.get_all()),\n                         [('Cr', 'cr\\rMore: more'),\n                          ('Crlf', 'crlf'),\n                          ('Lf', 'lf'),\n                          ])\n\n    def test_copy(self):\n        all_pairs = [('A', '1'), ('A', '2'), ('B', 'c')]\n        h1 = HTTPHeaders()\n        for k, v in all_pairs:\n            h1.add(k, v)\n        h2 = h1.copy()\n        h3 = copy.copy(h1)\n        h4 = copy.deepcopy(h1)\n        for headers in [h1, h2, h3, h4]:\n            # All the copies are identical, no matter how they were\n            # constructed.\n            self.assertEqual(list(sorted(headers.get_all())), all_pairs)\n        for headers in [h2, h3, h4]:\n            # Neither the dict or its member lists are reused.\n            self.assertIsNot(headers, h1)\n            self.assertIsNot(headers.get_list('A'), h1.get_list('A'))\n\n    def test_pickle_roundtrip(self):\n        headers = HTTPHeaders()\n        headers.add('Set-Cookie', 'a=b')\n        headers.add('Set-Cookie', 'c=d')\n        headers.add('Content-Type', 'text/html')\n        pickled = pickle.dumps(headers)\n        unpickled = pickle.loads(pickled)\n        self.assertEqual(sorted(headers.get_all()), sorted(unpickled.get_all()))\n        self.assertEqual(sorted(headers.items()), sorted(unpickled.items()))\n\n    def test_setdefault(self):\n        headers = HTTPHeaders()\n        headers['foo'] = 'bar'\n        # If a value is present, setdefault returns it without changes.\n        self.assertEqual(headers.setdefault('foo', 'baz'), 'bar')\n        self.assertEqual(headers['foo'], 'bar')\n        # If a value is not present, setdefault sets it for future use.\n        self.assertEqual(headers.setdefault('quux', 'xyzzy'), 'xyzzy')\n        self.assertEqual(headers['quux'], 'xyzzy')\n        self.assertEqual(sorted(headers.get_all()), [('Foo', 'bar'), ('Quux', 'xyzzy')])\n\n    def test_string(self):\n        headers = HTTPHeaders()\n        headers.add(\"Foo\", \"1\")\n        headers.add(\"Foo\", \"2\")\n        headers.add(\"Foo\", \"3\")\n        headers2 = HTTPHeaders.parse(str(headers))\n        self.assertEquals(headers, headers2)\n\n\nclass FormatTimestampTest(unittest.TestCase):\n    # Make sure that all the input types are supported.\n    TIMESTAMP = 1359312200.503611\n    EXPECTED = 'Sun, 27 Jan 2013 18:43:20 GMT'\n\n    def check(self, value):\n        self.assertEqual(format_timestamp(value), self.EXPECTED)\n\n    def test_unix_time_float(self):\n        self.check(self.TIMESTAMP)\n\n    def test_unix_time_int(self):\n        self.check(int(self.TIMESTAMP))\n\n    def test_struct_time(self):\n        self.check(time.gmtime(self.TIMESTAMP))\n\n    def test_time_tuple(self):\n        tup = tuple(time.gmtime(self.TIMESTAMP))\n        self.assertEqual(9, len(tup))\n        self.check(tup)\n\n    def test_datetime(self):\n        self.check(datetime.datetime.utcfromtimestamp(self.TIMESTAMP))\n\n\n# HTTPServerRequest is mainly tested incidentally to the server itself,\n# but this tests the parts of the class that can be tested in isolation.\nclass HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n    def test_repr_does_not_contain_headers(self):\n        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})\n        self.assertTrue('Canary' not in repr(request))\n\n\nclass ParseRequestStartLineTest(unittest.TestCase):\n    METHOD = \"GET\"\n    PATH = \"/foo\"\n    VERSION = \"HTTP/1.1\"\n\n    def test_parse_request_start_line(self):\n        start_line = \" \".join([self.METHOD, self.PATH, self.VERSION])\n        parsed_start_line = parse_request_start_line(start_line)\n        self.assertEqual(parsed_start_line.method, self.METHOD)\n        self.assertEqual(parsed_start_line.path, self.PATH)\n        self.assertEqual(parsed_start_line.version, self.VERSION)\n\n\nclass ParseCookieTest(unittest.TestCase):\n    # These tests copied from Django:\n    # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28\n    def test_python_cookies(self):\n        \"\"\"\n        Test cases copied from Python's Lib/test/test_http_cookies.py\n        \"\"\"\n        self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'})\n        # Here parse_cookie() differs from Python's cookie parsing in that it\n        # treats all semicolons as delimiters, even within quotes.\n        self.assertEqual(\n            parse_cookie('keebler=\"E=mc2; L=\\\\\"Loves\\\\\"; fudge=\\\\012;\"'),\n            {'keebler': '\"E=mc2', 'L': '\\\\\"Loves\\\\\"', 'fudge': '\\\\012', '': '\"'}\n        )\n        # Illegal cookies that have an '=' char in an unquoted value.\n        self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'})\n        # Cookies with ':' character in their name.\n        self.assertEqual(parse_cookie('key:term=value:term'), {'key:term': 'value:term'})\n        # Cookies with '[' and ']'.\n        self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'})\n\n    def test_cookie_edgecases(self):\n        # Cookies that RFC6265 allows.\n        self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'})\n        # parse_cookie() has historically kept only the last cookie with the\n        # same name.\n        self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'})\n\n    def test_invalid_cookies(self):\n        \"\"\"\n        Cookie strings that go against RFC6265 but browsers will send if set\n        via document.cookie.\n        \"\"\"\n        # Chunks without an equals sign appear as unnamed values per\n        # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n        self.assertIn('django_language', parse_cookie('abc=def; unnamed; django_language=en').keys())\n        # Even a double quote may be an unamed value.\n        self.assertEqual(parse_cookie('a=b; \"; c=d'), {'a': 'b', '': '\"', 'c': 'd'})\n        # Spaces in names and values, and an equals sign in values.\n        self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c': 'd e = f', 'gh': 'i'})\n        # More characters the spec forbids.\n        self.assertEqual(parse_cookie('a   b,c<>@:/[]?{}=d  \"  =e,f g'), {'a   b,c<>@:/[]?{}': 'd  \"  =e,f g'})\n        # Unicode characters. The spec only allows ASCII.\n        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': native_str('André Bessette')})\n        # Browsers don't send extra whitespace or semicolons in Cookie headers,\n        # but parse_cookie() should parse whitespace the same way\n        # document.cookie parses whitespace.\n        self.assertEqual(parse_cookie('  =  b  ;  ;  =  ;   c  =  ;  '), {'': 'b', 'c': ''})\n",
            "header": {
                "file": {
                    "path": "tornado/test/httputil_test.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "7ac79925",
                "new_commit_hash": "1521ca03",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tornado/test/httputil_test.py"
            },
            "plus_file": {
                "path": "b/tornado/test/httputil_test.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 418,
                            "length": 6
                        },
                        "new_range": {
                            "start": 418,
                            "length": 10
                        },
                        "section": "class HTTPServerRequestTest(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        requets = HTTPServerRequest(uri='/')",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertIsInstance(requets.body, bytes)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_repr_does_not_contain_headers(self):",
                                "type": "added"
                            },
                            {
                                "content": "        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue('Canary' not in repr(request))",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "class ParseRequestStartLineTest(unittest.TestCase):",
                                "type": "context"
                            },
                            {
                                "content": "    METHOD = \"GET\"",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tornado/test/httputil_test.py",
                            "type": "class",
                            "name": "HTTPServerRequestTest",
                            "content": "class HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n    def test_repr_does_not_contain_headers(self):\n        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})\n        self.assertTrue('Canary' not in repr(request))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 410,
                            "end_lineno": 423,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tornado/test/httputil_test.py",
                            "type": "method",
                            "name": "HTTPServerRequestTest.test_repr_does_not_contain_headers",
                            "content": "class HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n    def test_repr_does_not_contain_headers(self):\n        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})\n        self.assertTrue('Canary' not in repr(request))",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 421,
                            "end_lineno": 423,
                            "parent": {
                                "file_name": "tornado/test/httputil_test.py",
                                "type": "class",
                                "name": "HTTPServerRequestTest",
                                "content": "class HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n    def test_repr_does_not_contain_headers(self):\n        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})\n        self.assertTrue('Canary' not in repr(request))",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 410,
                                "end_lineno": 423,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "871bf81c229cb482b67d41f460e55970e8fdf922^",
    "new_commit_hash": "871bf81c229cb482b67d41f460e55970e8fdf922",
    "commit_message": "Remove headers from HTTPServerRequest repr\n\n * In tornadoweb/tornado#1112 it was decided to stop including headers\n   in the request repr, since they are needlessly verbose and risk\n   leaking user secrets into the application log.",
    "commit_date": "2017-08-10T11:22:48-04:00",
    "metadata": {}
}
{
    "repo_name": "tornado",
    "new_commit_hash": "871bf81c229cb482b67d41f460e55970e8fdf922",
    "test_file_codes": [
        "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\nfrom __future__ import absolute_import, division, print_function\nfrom tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders, format_timestamp, HTTPServerRequest, parse_request_start_line, parse_cookie, qs_to_qsl, PY3\nfrom tornado.escape import utf8, native_str\nfrom tornado.log import gen_log\nfrom tornado.testing import ExpectLog\nfrom tornado.test.util import unittest\n\nimport copy\nimport datetime\nimport logging\nimport pickle\nimport time\n\nif PY3:\n    import urllib.parse as urllib_parse\nelse:\n    import urlparse as urllib_parse\n\n\nclass TestUrlConcat(unittest.TestCase):\n    def test_url_concat_no_query_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_encode_args(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', '/y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=%2Fy&z=z\")\n\n    def test_url_concat_trailing_q(self):\n        url = url_concat(\n            \"https://localhost/path?\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y&z=z\")\n\n    def test_url_concat_q_with_no_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_trailing_amp(self):\n        url = url_concat(\n            \"https://localhost/path?x&\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?x=&y=y&z=z\")\n\n    def test_url_concat_mult_params(self):\n        url = url_concat(\n            \"https://localhost/path?a=1&b=2\",\n            [('y', 'y'), ('z', 'z')],\n        )\n        self.assertEqual(url, \"https://localhost/path?a=1&b=2&y=y&z=z\")\n\n    def test_url_concat_no_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            [],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_none_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&t=2\",\n            None,\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&t=2\")\n\n    def test_url_concat_with_frag(self):\n        url = url_concat(\n            \"https://localhost/path#tab\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y#tab\")\n\n    def test_url_concat_multi_same_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            [('y', 'y1'), ('y', 'y2')],\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y1&y=y2\")\n\n    def test_url_concat_multi_same_query_params(self):\n        url = url_concat(\n            \"https://localhost/path?r=1&r=2\",\n            [('y', 'y')],\n        )\n        self.assertEqual(url, \"https://localhost/path?r=1&r=2&y=y\")\n\n    def test_url_concat_dict_params(self):\n        url = url_concat(\n            \"https://localhost/path\",\n            dict(y='y'),\n        )\n        self.assertEqual(url, \"https://localhost/path?y=y\")\n\n\nclass QsParseTest(unittest.TestCase):\n\n    def test_parsing(self):\n        qsstring = \"a=1&b=2&a=3\"\n        qs = urllib_parse.parse_qs(qsstring)\n        qsl = list(qs_to_qsl(qs))\n        self.assertIn(('a', '1'), qsl)\n        self.assertIn(('a', '3'), qsl)\n        self.assertIn(('b', '2'), qsl)\n\n\nclass MultipartFormDataTest(unittest.TestCase):\n    def test_file_upload(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_unquoted_names(self):\n        # quotes are optional unless special characters are present\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=files; filename=ab.txt\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_special_filenames(self):\n        filenames = ['a;b.txt',\n                     'a\"b.txt',\n                     'a\";b.txt',\n                     'a;\"b.txt',\n                     'a\";\";.txt',\n                     'a\\\\\"b.txt',\n                     'a\\\\b.txt',\n                     ]\n        for filename in filenames:\n            logging.debug(\"trying filename %r\", filename)\n            data = \"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"%s\"\n\nFoo\n--1234--\"\"\" % filename.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"')\n            data = utf8(data.replace(\"\\n\", \"\\r\\n\"))\n            args = {}\n            files = {}\n            parse_multipart_form_data(b\"1234\", data, args, files)\n            file = files[\"files\"][0]\n            self.assertEqual(file[\"filename\"], filename)\n            self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_boundary_starts_and_ends_with_quotes(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b'\"1234\"', data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n    def test_missing_headers(self):\n        data = b'''\\\n--1234\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data missing headers\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_invalid_content_disposition(self):\n        data = b'''\\\n--1234\nContent-Disposition: invalid; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_line_does_not_end_with_correct_line_break(self):\n        data = b'''\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo--1234--'''.replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"Invalid multipart/form-data\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_content_disposition_header_without_name_parameter(self):\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; filename=\"ab.txt\"\n\nFoo\n--1234--\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        with ExpectLog(gen_log, \"multipart/form-data value missing name\"):\n            parse_multipart_form_data(b\"1234\", data, args, files)\n        self.assertEqual(files, {})\n\n    def test_data_after_final_boundary(self):\n        # The spec requires that data after the final boundary be ignored.\n        # http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html\n        # In practice, some libraries include an extra CRLF after the boundary.\n        data = b\"\"\"\\\n--1234\nContent-Disposition: form-data; name=\"files\"; filename=\"ab.txt\"\n\nFoo\n--1234--\n\"\"\".replace(b\"\\n\", b\"\\r\\n\")\n        args = {}\n        files = {}\n        parse_multipart_form_data(b\"1234\", data, args, files)\n        file = files[\"files\"][0]\n        self.assertEqual(file[\"filename\"], \"ab.txt\")\n        self.assertEqual(file[\"body\"], b\"Foo\")\n\n\nclass HTTPHeadersTest(unittest.TestCase):\n    def test_multi_line(self):\n        # Lines beginning with whitespace are appended to the previous line\n        # with any leading whitespace replaced by a single space.\n        # Note that while multi-line headers are a part of the HTTP spec,\n        # their use is strongly discouraged.\n        data = \"\"\"\\\nFoo: bar\n baz\nAsdf: qwer\n\\tzxcv\nFoo: even\n     more\n     lines\n\"\"\".replace(\"\\n\", \"\\r\\n\")\n        headers = HTTPHeaders.parse(data)\n        self.assertEqual(headers[\"asdf\"], \"qwer zxcv\")\n        self.assertEqual(headers.get_list(\"asdf\"), [\"qwer zxcv\"])\n        self.assertEqual(headers[\"Foo\"], \"bar baz,even more lines\")\n        self.assertEqual(headers.get_list(\"foo\"), [\"bar baz\", \"even more lines\"])\n        self.assertEqual(sorted(list(headers.get_all())),\n                         [(\"Asdf\", \"qwer zxcv\"),\n                          (\"Foo\", \"bar baz\"),\n                          (\"Foo\", \"even more lines\")])\n\n    def test_unicode_newlines(self):\n        # Ensure that only \\r\\n is recognized as a header separator, and not\n        # the other newline-like unicode characters.\n        # Characters that are likely to be problematic can be found in\n        # http://unicode.org/standard/reports/tr13/tr13-5.html\n        # and cpython's unicodeobject.c (which defines the implementation\n        # of unicode_type.splitlines(), and uses a different list than TR13).\n        newlines = [\n            u'\\u001b',  # VERTICAL TAB\n            u'\\u001c',  # FILE SEPARATOR\n            u'\\u001d',  # GROUP SEPARATOR\n            u'\\u001e',  # RECORD SEPARATOR\n            u'\\u0085',  # NEXT LINE\n            u'\\u2028',  # LINE SEPARATOR\n            u'\\u2029',  # PARAGRAPH SEPARATOR\n        ]\n        for newline in newlines:\n            # Try the utf8 and latin1 representations of each newline\n            for encoding in ['utf8', 'latin1']:\n                try:\n                    try:\n                        encoded = newline.encode(encoding)\n                    except UnicodeEncodeError:\n                        # Some chars cannot be represented in latin1\n                        continue\n                    data = b'Cookie: foo=' + encoded + b'bar'\n                    # parse() wants a native_str, so decode through latin1\n                    # in the same way the real parser does.\n                    headers = HTTPHeaders.parse(\n                        native_str(data.decode('latin1')))\n                    expected = [('Cookie', 'foo=' +\n                                 native_str(encoded.decode('latin1')) + 'bar')]\n                    self.assertEqual(\n                        expected, list(headers.get_all()))\n                except Exception:\n                    gen_log.warning(\"failed while trying %r in %s\",\n                                    newline, encoding)\n                    raise\n\n    def test_optional_cr(self):\n        # Both CRLF and LF should be accepted as separators. CR should not be\n        # part of the data when followed by LF, but it is a normal char\n        # otherwise (or should bare CR be an error?)\n        headers = HTTPHeaders.parse(\n            'CRLF: crlf\\r\\nLF: lf\\nCR: cr\\rMore: more\\r\\n')\n        self.assertEqual(sorted(headers.get_all()),\n                         [('Cr', 'cr\\rMore: more'),\n                          ('Crlf', 'crlf'),\n                          ('Lf', 'lf'),\n                          ])\n\n    def test_copy(self):\n        all_pairs = [('A', '1'), ('A', '2'), ('B', 'c')]\n        h1 = HTTPHeaders()\n        for k, v in all_pairs:\n            h1.add(k, v)\n        h2 = h1.copy()\n        h3 = copy.copy(h1)\n        h4 = copy.deepcopy(h1)\n        for headers in [h1, h2, h3, h4]:\n            # All the copies are identical, no matter how they were\n            # constructed.\n            self.assertEqual(list(sorted(headers.get_all())), all_pairs)\n        for headers in [h2, h3, h4]:\n            # Neither the dict or its member lists are reused.\n            self.assertIsNot(headers, h1)\n            self.assertIsNot(headers.get_list('A'), h1.get_list('A'))\n\n    def test_pickle_roundtrip(self):\n        headers = HTTPHeaders()\n        headers.add('Set-Cookie', 'a=b')\n        headers.add('Set-Cookie', 'c=d')\n        headers.add('Content-Type', 'text/html')\n        pickled = pickle.dumps(headers)\n        unpickled = pickle.loads(pickled)\n        self.assertEqual(sorted(headers.get_all()), sorted(unpickled.get_all()))\n        self.assertEqual(sorted(headers.items()), sorted(unpickled.items()))\n\n    def test_setdefault(self):\n        headers = HTTPHeaders()\n        headers['foo'] = 'bar'\n        # If a value is present, setdefault returns it without changes.\n        self.assertEqual(headers.setdefault('foo', 'baz'), 'bar')\n        self.assertEqual(headers['foo'], 'bar')\n        # If a value is not present, setdefault sets it for future use.\n        self.assertEqual(headers.setdefault('quux', 'xyzzy'), 'xyzzy')\n        self.assertEqual(headers['quux'], 'xyzzy')\n        self.assertEqual(sorted(headers.get_all()), [('Foo', 'bar'), ('Quux', 'xyzzy')])\n\n    def test_string(self):\n        headers = HTTPHeaders()\n        headers.add(\"Foo\", \"1\")\n        headers.add(\"Foo\", \"2\")\n        headers.add(\"Foo\", \"3\")\n        headers2 = HTTPHeaders.parse(str(headers))\n        self.assertEquals(headers, headers2)\n\n\nclass FormatTimestampTest(unittest.TestCase):\n    # Make sure that all the input types are supported.\n    TIMESTAMP = 1359312200.503611\n    EXPECTED = 'Sun, 27 Jan 2013 18:43:20 GMT'\n\n    def check(self, value):\n        self.assertEqual(format_timestamp(value), self.EXPECTED)\n\n    def test_unix_time_float(self):\n        self.check(self.TIMESTAMP)\n\n    def test_unix_time_int(self):\n        self.check(int(self.TIMESTAMP))\n\n    def test_struct_time(self):\n        self.check(time.gmtime(self.TIMESTAMP))\n\n    def test_time_tuple(self):\n        tup = tuple(time.gmtime(self.TIMESTAMP))\n        self.assertEqual(9, len(tup))\n        self.check(tup)\n\n    def test_datetime(self):\n        self.check(datetime.datetime.utcfromtimestamp(self.TIMESTAMP))\n\n\n# HTTPServerRequest is mainly tested incidentally to the server itself,\n# but this tests the parts of the class that can be tested in isolation.\nclass HTTPServerRequestTest(unittest.TestCase):\n    def test_default_constructor(self):\n        # All parameters are formally optional, but uri is required\n        # (and has been for some time).  This test ensures that no\n        # more required parameters slip in.\n        HTTPServerRequest(uri='/')\n\n    def test_body_is_a_byte_string(self):\n        requets = HTTPServerRequest(uri='/')\n        self.assertIsInstance(requets.body, bytes)\n\n    def test_repr_does_not_contain_headers(self):\n        request = HTTPServerRequest(uri='/', headers={'Canary': 'Coal Mine'})\n        self.assertTrue('Canary' not in repr(request))\n\n\nclass ParseRequestStartLineTest(unittest.TestCase):\n    METHOD = \"GET\"\n    PATH = \"/foo\"\n    VERSION = \"HTTP/1.1\"\n\n    def test_parse_request_start_line(self):\n        start_line = \" \".join([self.METHOD, self.PATH, self.VERSION])\n        parsed_start_line = parse_request_start_line(start_line)\n        self.assertEqual(parsed_start_line.method, self.METHOD)\n        self.assertEqual(parsed_start_line.path, self.PATH)\n        self.assertEqual(parsed_start_line.version, self.VERSION)\n\n\nclass ParseCookieTest(unittest.TestCase):\n    # These tests copied from Django:\n    # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28\n    def test_python_cookies(self):\n        \"\"\"\n        Test cases copied from Python's Lib/test/test_http_cookies.py\n        \"\"\"\n        self.assertEqual(parse_cookie('chips=ahoy; vienna=finger'), {'chips': 'ahoy', 'vienna': 'finger'})\n        # Here parse_cookie() differs from Python's cookie parsing in that it\n        # treats all semicolons as delimiters, even within quotes.\n        self.assertEqual(\n            parse_cookie('keebler=\"E=mc2; L=\\\\\"Loves\\\\\"; fudge=\\\\012;\"'),\n            {'keebler': '\"E=mc2', 'L': '\\\\\"Loves\\\\\"', 'fudge': '\\\\012', '': '\"'}\n        )\n        # Illegal cookies that have an '=' char in an unquoted value.\n        self.assertEqual(parse_cookie('keebler=E=mc2'), {'keebler': 'E=mc2'})\n        # Cookies with ':' character in their name.\n        self.assertEqual(parse_cookie('key:term=value:term'), {'key:term': 'value:term'})\n        # Cookies with '[' and ']'.\n        self.assertEqual(parse_cookie('a=b; c=[; d=r; f=h'), {'a': 'b', 'c': '[', 'd': 'r', 'f': 'h'})\n\n    def test_cookie_edgecases(self):\n        # Cookies that RFC6265 allows.\n        self.assertEqual(parse_cookie('a=b; Domain=example.com'), {'a': 'b', 'Domain': 'example.com'})\n        # parse_cookie() has historically kept only the last cookie with the\n        # same name.\n        self.assertEqual(parse_cookie('a=b; h=i; a=c'), {'a': 'c', 'h': 'i'})\n\n    def test_invalid_cookies(self):\n        \"\"\"\n        Cookie strings that go against RFC6265 but browsers will send if set\n        via document.cookie.\n        \"\"\"\n        # Chunks without an equals sign appear as unnamed values per\n        # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n        self.assertIn('django_language', parse_cookie('abc=def; unnamed; django_language=en').keys())\n        # Even a double quote may be an unamed value.\n        self.assertEqual(parse_cookie('a=b; \"; c=d'), {'a': 'b', '': '\"', 'c': 'd'})\n        # Spaces in names and values, and an equals sign in values.\n        self.assertEqual(parse_cookie('a b c=d e = f; gh=i'), {'a b c': 'd e = f', 'gh': 'i'})\n        # More characters the spec forbids.\n        self.assertEqual(parse_cookie('a   b,c<>@:/[]?{}=d  \"  =e,f g'), {'a   b,c<>@:/[]?{}': 'd  \"  =e,f g'})\n        # Unicode characters. The spec only allows ASCII.\n        self.assertEqual(parse_cookie('saint=André Bessette'), {'saint': native_str('André Bessette')})\n        # Browsers don't send extra whitespace or semicolons in Cookie headers,\n        # but parse_cookie() should parse whitespace the same way\n        # document.cookie parses whitespace.\n        self.assertEqual(parse_cookie('  =  b  ;  ;  =  ;   c  =  ;  '), {'': 'b', 'c': ''})\n",
        "#!/usr/bin/env python\nimport unittest\nimport sys\nimport time\nimport traceback\nimport platform\nimport os\n\n\nclass PytestLikeResult(unittest.TestResult):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.start_time = None\n        # Store (test, outcome, info) for each test:\n        #   outcome ∈ { \"passed\", \"failed\", \"error\", \"skipped\" }\n        #   info can hold the exception or skip reason, etc.\n        self.results = []\n\n    def startTestRun(self):\n        \"\"\"Called once before all tests.\"\"\"\n        self.start_time = time.time()\n        # Print a header similar to pytest\n        print(\"=\" * 29 + \" test session starts \" + \"=\" * 29)\n        # You can customize the platform/versions/paths as you like:\n        print(\n            f\"platform {platform.system().lower()} -- Python {platform.python_version()}\"\n        )\n        print(f\"rootdir: {os.path.abspath(os.curdir)}\")\n\n    def stopTestRun(self):\n        \"\"\"Called once after all tests are done.\"\"\"\n        elapsed = time.time() - self.start_time\n        print()  # blank line after final dot\n\n        # Summarize\n        ntests = len(self.results)\n        print(f\"collected {ntests} items\")\n\n        # Show details of failures/errors\n        failures = [r for r in self.results if r[1] == \"failed\"]\n        errors = [r for r in self.results if r[1] == \"error\"]\n\n        if failures:\n            print(\"\\n\" + \"=\" * 35 + \" FAILURES \" + \"=\" * 35)\n            for test, outcome, err_info in failures:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n        if errors:\n            print(\"\\n\" + \"=\" * 35 + \" ERRORS \" + \"=\" * 37)\n            for test, outcome, err_info in errors:\n                test = test.split(\"::\")\n                if len(test) == 3:\n                    test = f\"{test[1]}.{test[2]}\"\n                else:\n                    test = f\"{test[1]}\"\n                print(f\"__________ {test} __________\")\n                self._print_traceback(err_info)\n\n        # Optional short summary lines for passes/fails/skips\n        print(\"\\n==================== short test summary info ====================\")\n        for test, outcome, info in self.results:\n            if outcome in (\"passed\", \"failed\", \"error\", \"skipped\"):\n                print(f\"{outcome.upper()} {test}\")\n\n        # Final one-line summary: “1 failed, 1 errors, 10 passed in 2.04s”\n        passed_count = sum(1 for r in self.results if r[1] == \"passed\")\n        failed_count = len(failures)\n        error_count = len(errors)\n        skipped_count = sum(1 for r in self.results if r[1] == \"skipped\")\n\n        summary_bits = []\n        if failed_count:\n            summary_bits.append(f\"{failed_count} failed\")\n        if error_count:\n            summary_bits.append(f\"{error_count} error{'s' if error_count != 1 else ''}\")\n        if passed_count:\n            summary_bits.append(f\"{passed_count} passed\")\n        if skipped_count:\n            summary_bits.append(f\"{skipped_count} skipped\")\n\n        summary_str = \", \".join(summary_bits) if summary_bits else \"no tests run\"\n        print(\n            f\"=================== {summary_str} in {elapsed:.2f}s ===================\"\n        )\n\n    def startTest(self, test):\n        \"\"\"Called right before each test method.\"\"\"\n        super().startTest(test)\n        # Print a dot or some indicator\n        print(\".\", end=\"\", flush=True)\n\n    def addSuccess(self, test):\n        super().addSuccess(test)\n        self.results.append((self._test_id(test), \"passed\", None))\n\n    def addFailure(self, test, err):\n        super().addFailure(test, err)\n        self.results.append((self._test_id(test), \"failed\", err))\n\n    def addError(self, test, err):\n        super().addError(test, err)\n        self.results.append((self._test_id(test), \"error\", err))\n\n    def addSkip(self, test, reason):\n        super().addSkip(test, reason)\n        self.results.append((self._test_id(test), \"skipped\", reason))\n\n    def _print_traceback(self, err_info):\n        \"\"\"Helper to print the traceback like pytest does.\"\"\"\n        if isinstance(err_info, tuple) and len(err_info) == 3:\n            exc_type, exc_value, tb = err_info\n            traceback.print_exception(exc_type, exc_value, tb, file=sys.stdout)\n        else:\n            print(str(err_info))\n\n    def _test_id(self, test):\n        try:\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}::{test._testMethodName}\"\n        except AttributeError:\n            # Fallback for _ErrorHolder objects\n            return f\"{test.__class__.__module__}::{test.__class__.__name__}\"\n\n\nclass PytestLikeRunner(unittest.TextTestRunner):\n    \"\"\"A custom TextTestRunner that uses the PytestLikeResult.\"\"\"\n\n    resultclass = PytestLikeResult\n\n    def run(self, test):\n        result = self._makeResult()\n        # Overriding run to ensure we call startTestRun/stopTestRun\n        result.startTestRun()\n        test(result)\n        result.stopTestRun()\n        return result\n\n    def tearDown(self):\n        # Reset signal handlers\n        from twisted.internet import reactor\n\n        reactor.removeAll()\n        reactor.stop()\n        super().tearDown()\n\n\ndef main():\n    loader = unittest.TestLoader()\n    suite = loader.discover(\".\", pattern=\"test_*.py\")  # discover tests in r2e_tests/\n    runner = PytestLikeRunner(verbosity=0)\n    result = runner.run(suite)\n    # Exit with code 0 if all tests passed/skipped, 1 if there were fails/errors\n    sys.exit(not result.wasSuccessful())\n\n\nif __name__ == \"__main__\":\n    main()\n"
    ],
    "test_file_names": [
        "test_1.py",
        "tornado_unittest_runner.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 1 package in 758ms\nPrepared 1 package in 1.09s\nInstalled 1 package in 0.74ms\n + tornado==5.0.dev1 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_871bf81c229cb482b67d41f460e55970e8fdf922)\nResolved 29 packages in 13ms\nInstalled 29 packages in 155ms\n + attrs==24.3.0\n + automat==24.8.1\n + cachetools==5.5.0\n + cffi==1.17.1\n + chardet==5.2.0\n + colorama==0.4.6\n + constantly==23.10.4\n + distlib==0.3.9\n + exceptiongroup==1.2.2\n + filelock==3.16.1\n + hyperlink==21.0.0\n + idna==3.10\n + incremental==24.7.2\n + iniconfig==2.0.0\n + packaging==24.2\n + platformdirs==4.3.6\n + pluggy==1.5.0\n + pycares==4.5.0\n + pycparser==2.22\n + pycurl==7.45.4\n + pyproject-api==1.8.0\n + pytest==8.3.4\n + setuptools==75.6.0\n + tomli==2.2.1\n + tox==4.23.2\n + twisted==24.11.0\n + typing-extensions==4.12.2\n + virtualenv==20.28.0\n + zope-interface==7.2\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_871bf81c229cb482b67d41f460e55970e8fdf922\n.........................................\ncollected 41 items\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::FormatTimestampTest::test_datetime\nPASSED r2e_tests.test_1::FormatTimestampTest::test_struct_time\nPASSED r2e_tests.test_1::FormatTimestampTest::test_time_tuple\nPASSED r2e_tests.test_1::FormatTimestampTest::test_unix_time_float\nPASSED r2e_tests.test_1::FormatTimestampTest::test_unix_time_int\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_copy\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_multi_line\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_optional_cr\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_pickle_roundtrip\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_setdefault\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_string\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_unicode_newlines\nPASSED r2e_tests.test_1::HTTPServerRequestTest::test_body_is_a_byte_string\nPASSED r2e_tests.test_1::HTTPServerRequestTest::test_default_constructor\nPASSED r2e_tests.test_1::HTTPServerRequestTest::test_repr_does_not_contain_headers\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_boundary_starts_and_ends_with_quotes\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_content_disposition_header_without_name_parameter\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_data_after_final_boundary\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_file_upload\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_invalid_content_disposition\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_line_does_not_end_with_correct_line_break\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_missing_headers\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_special_filenames\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_unquoted_names\nPASSED r2e_tests.test_1::ParseCookieTest::test_cookie_edgecases\nPASSED r2e_tests.test_1::ParseCookieTest::test_invalid_cookies\nPASSED r2e_tests.test_1::ParseCookieTest::test_python_cookies\nPASSED r2e_tests.test_1::ParseRequestStartLineTest::test_parse_request_start_line\nPASSED r2e_tests.test_1::QsParseTest::test_parsing\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_dict_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_encode_args\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_mult_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_multi_same_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_multi_same_query_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_no_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_no_query_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_none_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_q_with_no_trailing_amp\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_trailing_amp\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_trailing_q\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_with_frag\n=================== 41 passed in 0.00s ===================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts =============================\nplatform linux -- Python 3.9.21\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_871bf81c229cb482b67d41f460e55970e8fdf922\n.........................................\ncollected 41 items\n\n=================================== FAILURES ===================================\n__________ HTTPServerRequestTest.test_repr_does_not_contain_headers __________\nTraceback (most recent call last):\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 59, in testPartExecutor\n    yield\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 592, in run\n    self._callTestMethod(testMethod)\n  File \"/home/gcpuser/.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/unittest/case.py\", line 550, in _callTestMethod\n    method()\n  File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/tornado_871bf81c229cb482b67d41f460e55970e8fdf922/r2e_tests/test_1.py\", line 423, in test_repr_does_not_contain_headers\n    self.assertTrue('Canary' not in repr(request))\nAssertionError: False is not true\n\n==================== short test summary info ====================\nPASSED r2e_tests.test_1::FormatTimestampTest::test_datetime\nPASSED r2e_tests.test_1::FormatTimestampTest::test_struct_time\nPASSED r2e_tests.test_1::FormatTimestampTest::test_time_tuple\nPASSED r2e_tests.test_1::FormatTimestampTest::test_unix_time_float\nPASSED r2e_tests.test_1::FormatTimestampTest::test_unix_time_int\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_copy\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_multi_line\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_optional_cr\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_pickle_roundtrip\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_setdefault\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_string\nPASSED r2e_tests.test_1::HTTPHeadersTest::test_unicode_newlines\nPASSED r2e_tests.test_1::HTTPServerRequestTest::test_body_is_a_byte_string\nPASSED r2e_tests.test_1::HTTPServerRequestTest::test_default_constructor\nFAILED r2e_tests.test_1::HTTPServerRequestTest::test_repr_does_not_contain_headers\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_boundary_starts_and_ends_with_quotes\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_content_disposition_header_without_name_parameter\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_data_after_final_boundary\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_file_upload\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_invalid_content_disposition\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_line_does_not_end_with_correct_line_break\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_missing_headers\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_special_filenames\nPASSED r2e_tests.test_1::MultipartFormDataTest::test_unquoted_names\nPASSED r2e_tests.test_1::ParseCookieTest::test_cookie_edgecases\nPASSED r2e_tests.test_1::ParseCookieTest::test_invalid_cookies\nPASSED r2e_tests.test_1::ParseCookieTest::test_python_cookies\nPASSED r2e_tests.test_1::ParseRequestStartLineTest::test_parse_request_start_line\nPASSED r2e_tests.test_1::QsParseTest::test_parsing\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_dict_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_encode_args\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_mult_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_multi_same_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_multi_same_query_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_no_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_no_query_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_none_params\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_q_with_no_trailing_amp\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_trailing_amp\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_trailing_q\nPASSED r2e_tests.test_1::TestUrlConcat::test_url_concat_with_frag\n=================== 1 failed, 40 passed in 0.00s ===================\n",
    "old_commit_res_stderr": ""
}
tornado/httputil.py tornado/test/httputil_test.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** HTTPServerRequest `repr` Includes Headers, Risking Sensitive Information Exposure

**Description:**
When creating an instance of `HTTPServerRequest`, printing its representation includes all HTTP headers. This results in overly verbose logs and poses a security risk by potentially exposing sensitive user information.

**Example Code:**
```python
from tornado.httputil import HTTPServerRequest

request = HTTPServerRequest(uri='/', headers={'Authorization': 'Bearer secret_token'})
print(repr(request))
```

**Expected Behavior:**
The representation of `HTTPServerRequest` should exclude headers to keep logs concise and prevent leaking sensitive information.

**Actual Behavior:**
The `repr` of `HTTPServerRequest` includes all headers, such as the `Authorization` header, which can expose sensitive data in application logs.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/httputil.py
#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""HTTP utility code shared by clients and servers.

This module also defines the `HTTPServerRequest` class which is exposed
via `tornado.web.RequestHandler.request`.
"""

from __future__ import absolute_import, division, print_function

import calendar
import collections
import copy
import datetime
import email.utils
import numbers
import re
import time

from tornado.escape import native_str, parse_qs_bytes, utf8
from tornado.log import gen_log
from tornado.util import ObjectDict, PY3

if PY3:
    import http.cookies as Cookie
    from http.client import responses
    from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl
else:
    import Cookie
    from httplib import responses
    from urllib import urlencode
    from urlparse import urlparse, urlunparse, parse_qsl


# responses is unused in this file, but we re-export it to other files.
# Reference it so pyflakes doesn't complain.
responses

try:
    from ssl import SSLError
except ImportError:
    # ssl is unavailable on app engine.
    class _SSLError(Exception):
        pass
    # Hack around a mypy limitation. We can't simply put "type: ignore"
    # on the class definition itself; must go through an assignment.
    SSLError = _SSLError  # type: ignore

try:
    import typing
except ImportError:
    pass


# RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line
# terminator and ignore any preceding CR.
_CRLF_RE = re.compile(r'\r?\n')


class _NormalizedHeaderCache(dict):
    """Dynamic cached mapping of header names to Http-Header-Case.

    Implemented as a dict subclass so that cache hits are as fast as a
    normal dict lookup, without the overhead of a python function
    call.

    >>> normalized_headers = _NormalizedHeaderCache(10)
    >>> normalized_headers["coNtent-TYPE"]
    'Content-Type'
    """
    def __init__(self, size):
        super(_NormalizedHeaderCache, self).__init__()
        self.size = size
        self.queue = collections.deque()

    def __missing__(self, key):
        normalized = "-".join([w.capitalize() for w in key.split("-")])
        self[key] = normalized
        self.queue.append(key)
        if len(self.queue) > self.size:
            # Limit the size of the cache.  LRU would be better, but this
            # simpler approach should be fine.  In Python 2.7+ we could
            # use OrderedDict (or in 3.2+, @functools.lru_cache).
            old_key = self.queue.popleft()
            del self[old_key]
        return normalized


_normalized_headers = _NormalizedHeaderCache(1000)


class HTTPHeaders(collections.MutableMapping):
    """A dictionary that maintains ``Http-Header-Case`` for all keys.

    Supports multiple values per key via a pair of new methods,
    `add()` and `get_list()`.  The regular dictionary interface
    returns a single value per key, with multiple values joined by a
    comma.

    >>> h = HTTPHeaders({"content-type": "text/html"})
    >>> list(h.keys())
    ['Content-Type']
    >>> h["Content-Type"]
    'text/html'

    >>> h.add("Set-Cookie", "A=B")
    >>> h.add("Set-Cookie", "C=D")
    >>> h["set-cookie"]
    'A=B,C=D'
    >>> h.get_list("set-cookie")
    ['A=B', 'C=D']

    >>> for (k,v) in sorted(h.get_all()):
    ...    print('%s: %s' % (k,v))
    ...
    Content-Type: text/html
    Set-Cookie: A=B
    Set-Cookie: C=D
    """
    def __init__(self, *args, **kwargs):
        self._dict = {}  # type: typing.Dict[str, str]
        self._as_list = {}  # type: typing.Dict[str, typing.List[str]]
        self._last_key = None
        if (len(args) == 1 and len(kwargs) == 0 and
                isinstance(args[0], HTTPHeaders)):
            # Copy constructor
            for k, v in args[0].get_all():
                self.add(k, v)
        else:
            # Dict-style initialization
            self.update(*args, **kwargs)

    # new public methods

    def add(self, name, value):
        # type: (str, str) -> None
        """Adds a new value for the given key."""
        norm_name = _normalized_headers[name]
        self._last_key = norm_name
        if norm_name in self:
            self._dict[norm_name] = (native_str(self[norm_name]) + ',' +
                                     native_str(value))
            self._as_list[norm_name].append(value)
        else:
            self[norm_name] = value

    def get_list(self, name):
        """Returns all values for the given header as a list."""
        norm_name = _normalized_headers[name]
        return self._as_list.get(norm_name, [])

    def get_all(self):
        # type: () -> typing.Iterable[typing.Tuple[str, str]]
        """Returns an iterable of all (name, value) pairs.

        If a header has multiple values, multiple pairs will be
        returned with the same name.
        """
        for name, values in self._as_list.items():
            for value in values:
                yield (name, value)

    def parse_line(self, line):
        """Updates the dictionary with a single header line.

        >>> h = HTTPHeaders()
        >>> h.parse_line("Content-Type: text/html")
        >>> h.get('content-type')
        'text/html'
        """
        if line[0].isspace():
            # continuation of a multi-line header
            new_part = ' ' + line.lstrip()
            self._as_list[self._last_key][-1] += new_part
            self._dict[self._last_key] += new_part
        else:
            name, value = line.split(":", 1)
            self.add(name, value.strip())

    @classmethod
    def parse(cls, headers):
        """Returns a dictionary from HTTP header text.

        >>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n")
        >>> sorted(h.items())
        [('Content-Length', '42'), ('Content-Type', 'text/html')]
        """
        h = cls()
        for line in _CRLF_RE.split(headers):
            if line:
                h.parse_line(line)
        return h

    # MutableMapping abstract method implementations.

    def __setitem__(self, name, value):
        norm_name = _normalized_headers[name]
        self._dict[norm_name] = value
        self._as_list[norm_name] = [value]

    def __getitem__(self, name):
        # type: (str) -> str
        return self._dict[_normalized_headers[name]]

    def __delitem__(self, name):
        norm_name = _normalized_headers[name]
        del self._dict[norm_name]
        del self._as_list[norm_name]

    def __len__(self):
        return len(self._dict)

    def __iter__(self):
        return iter(self._dict)

    def copy(self):
        # defined in dict but not in MutableMapping.
        return HTTPHeaders(self)

    # Use our overridden copy method for the copy.copy module.
    # This makes shallow copies one level deeper, but preserves
    # the appearance that HTTPHeaders is a single container.
    __copy__ = copy

    def __str__(self):
        lines = []
        for name, value in self.get_all():
            lines.append("%s: %s\n" % (name, value))
        return "".join(lines)

    __unicode__ = __str__


class HTTPServerRequest(object):
    """A single HTTP request.

    All attributes are type `str` unless otherwise noted.

    .. attribute:: method

       HTTP request method, e.g. "GET" or "POST"

    .. attribute:: uri

       The requested uri.

    .. attribute:: path

       The path portion of `uri`

    .. attribute:: query

       The query portion of `uri`

    .. attribute:: version

       HTTP version specified in request, e.g. "HTTP/1.1"

    .. attribute:: headers

       `.HTTPHeaders` dictionary-like object for request headers.  Acts like
       a case-insensitive dictionary with additional methods for repeated
       headers.

    .. attribute:: body

       Request body, if present, as a byte string.

    .. attribute:: remote_ip

       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,
       will pass along the real IP address provided by a load balancer
       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.

    .. versionchanged:: 3.1
       The list format of ``X-Forwarded-For`` is now supported.

    .. attribute:: protocol

       The protocol used, either "http" or "https".  If ``HTTPServer.xheaders``
       is set, will pass along the protocol used by a load balancer if
       reported via an ``X-Scheme`` header.

    .. attribute:: host

       The requested hostname, usually taken from the ``Host`` header.

    .. attribute:: arguments

       GET/POST arguments are available in the arguments property, which
       maps arguments names to lists of values (to support multiple values
       for individual names). Names are of type `str`, while arguments
       are byte strings.  Note that this is different from
       `.RequestHandler.get_argument`, which returns argument values as
       unicode strings.

    .. attribute:: query_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the query string.

       .. versionadded:: 3.2

    .. attribute:: body_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the request body.

       .. versionadded:: 3.2

    .. attribute:: files

       File uploads are available in the files property, which maps file
       names to lists of `.HTTPFile`.

    .. attribute:: connection

       An HTTP request is attached to a single HTTP connection, which can
       be accessed through the "connection" attribute. Since connections
       are typically kept open in HTTP/1.1, multiple requests can be handled
       sequentially on a single connection.

    .. versionchanged:: 4.0
       Moved from ``tornado.httpserver.HTTPRequest``.
    """
    def __init__(self, method=None, uri=None, version="HTTP/1.0", headers=None,
                 body=None, host=None, files=None, connection=None,
                 start_line=None, server_connection=None):
        if start_line is not None:
            method, uri, version = start_line
        self.method = method
        self.uri = uri
        self.version = version
        self.headers = headers or HTTPHeaders()
        self.body = body or b""

        # set remote IP and protocol
        context = getattr(connection, 'context', None)
        self.remote_ip = getattr(context, 'remote_ip', None)
        self.protocol = getattr(context, 'protocol', "http")

        self.host = host or self.headers.get("Host") or "127.0.0.1"
        self.host_name = split_host_and_port(self.host.lower())[0]
        self.files = files or {}
        self.connection = connection
        self.server_connection = server_connection
        self._start_time = time.time()
        self._finish_time = None

        self.path, sep, self.query = uri.partition('?')
        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
        self.query_arguments = copy.deepcopy(self.arguments)
        self.body_arguments = {}

    def supports_http_1_1(self):
        """Returns True if this request supports HTTP/1.1 semantics.

        .. deprecated:: 4.0
           Applications are less likely to need this information with the
           introduction of `.HTTPConnection`.  If you still need it, access
           the ``version`` attribute directly.
        """
        return self.version == "HTTP/1.1"

    @property
    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self, "_cookies"):
            self._cookies = Cookie.SimpleCookie()
            if "Cookie" in self.headers:
                try:
                    parsed = parse_cookie(self.headers["Cookie"])
                except Exception:
                    pass
                else:
                    for k, v in parsed.items():
                        try:
                            self._cookies[k] = v
                        except Exception:
                            # SimpleCookie imposes some restrictions on keys;
                            # parse_cookie does not. Discard any cookies
                            # with disallowed keys.
                            pass
        return self._cookies

    def write(self, chunk, callback=None):
        """Writes the given chunk to the response stream.

        .. deprecated:: 4.0
           Use ``request.connection`` and the `.HTTPConnection` methods
           to write the response.
        """
        assert isinstance(chunk, bytes)
        assert self.version.startswith("HTTP/1."), \
            "deprecated interface only supported in HTTP/1.x"
        self.connection.write(chunk, callback=callback)

    def finish(self):
        """Finishes this HTTP request on the open connection.

        .. deprecated:: 4.0
           Use ``request.connection`` and the `.HTTPConnection` methods
           to write the response.
        """
        self.connection.finish()
        self._finish_time = time.time()

    def full_url(self):
        """Reconstructs the full URL for this request."""
        return self.protocol + "://" + self.host + self.uri

    def request_time(self):
        """Returns the amount of time it took for this request to execute."""
        if self._finish_time is None:
            return time.time() - self._start_time
        else:
            return self._finish_time - self._start_time

    def get_ssl_certificate(self, binary_form=False):
        """Returns the client's SSL certificate, if any.

        To use client certificates, the HTTPServer's
        `ssl.SSLContext.verify_mode` field must be set, e.g.::

            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_ctx.load_cert_chain("foo.crt", "foo.key")
            ssl_ctx.load_verify_locations("cacerts.pem")
            ssl_ctx.verify_mode = ssl.CERT_REQUIRED
            server = HTTPServer(app, ssl_options=ssl_ctx)

        By default, the return value is a dictionary (or None, if no
        client certificate is present).  If ``binary_form`` is true, a
        DER-encoded form of the certificate is returned instead.  See
        SSLSocket.getpeercert() in the standard library for more
        details.
        http://docs.python.org/library/ssl.html#sslsocket-objects
        """
        try:
            return self.connection.stream.socket.getpeercert(
                binary_form=binary_form)
        except SSLError:
            return None

    def _parse_body(self):
        parse_body_arguments(
            self.headers.get("Content-Type", ""), self.body,
            self.body_arguments, self.files,
            self.headers)

        for k, v in self.body_arguments.items():
            self.arguments.setdefault(k, []).extend(v)

    def __repr__(self):
        attrs = ("protocol", "host", "method", "uri", "version", "remote_ip")
        args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs])
        return "%s(%s, headers=%s)" % (
            self.__class__.__name__, args, dict(self.headers))


class HTTPInputError(Exception):
    """Exception class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    """
    pass


class HTTPOutputError(Exception):
    """Exception class for errors in HTTP output.

    .. versionadded:: 4.0
    """
    pass


class HTTPServerConnectionDelegate(object):
    """Implement this interface to handle requests from `.HTTPServer`.

    .. versionadded:: 4.0
    """
    def start_request(self, server_conn, request_conn):
        """This method is called by the server when a new request has started.

        :arg server_conn: is an opaque object representing the long-lived
            (e.g. tcp-level) connection.
        :arg request_conn: is a `.HTTPConnection` object for a single
            request/response exchange.

        This method should return a `.HTTPMessageDelegate`.
        """
        raise NotImplementedError()

    def on_close(self, server_conn):
        """This method is called when a connection has been closed.

        :arg server_conn: is a server connection that has previously been
            passed to ``start_request``.
        """
        pass


class HTTPMessageDelegate(object):
    """Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    """
    def headers_received(self, start_line, headers):
        """Called when the HTTP headers have been received and parsed.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`
            depending on whether this is a client or server message.
        :arg headers: a `.HTTPHeaders` instance.

        Some `.HTTPConnection` methods can only be called during
        ``headers_received``.

        May return a `.Future`; if it does the body will not be read
        until it is done.
        """
        pass

    def data_received(self, chunk):
        """Called when a chunk of data has been received.

        May return a `.Future` for flow control.
        """
        pass

    def finish(self):
        """Called after the last chunk of data has been received."""
        pass

    def on_connection_close(self):
        """Called if the connection is closed without finishing the request.

        If ``headers_received`` is called, either ``finish`` or
        ``on_connection_close`` will be called, but not both.
        """
        pass


class HTTPConnection(object):
    """Applications use this interface to write their responses.

    .. versionadded:: 4.0
    """
    def write_headers(self, start_line, headers, chunk=None, callback=None):
        """Write an HTTP header block.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.
        :arg headers: a `.HTTPHeaders` instance.
        :arg chunk: the first (optional) chunk of data.  This is an optimization
            so that small responses can be written in the same call as their
            headers.
        :arg callback: a callback to be run when the write is complete.

        The ``version`` field of ``start_line`` is ignored.

        Returns a `.Future` if no callback is given.
        """
        raise NotImplementedError()

    def write(self, chunk, callback=None):
        """Writes a chunk of body data.

        The callback will be run when the write is complete.  If no callback
        is given, returns a Future.
        """
        raise NotImplementedError()

    def finish(self):
        """Indicates that the last body data has been written.
        """
        raise NotImplementedError()


def url_concat(url, args):
    """Concatenate url and arguments regardless of whether
    url has existing query parameters.

    ``args`` may be either a dictionary or a list of key-value pairs
    (the latter allows for multiple values with the same key.

    >>> url_concat("http://example.com/foo", dict(c="d"))
    'http://example.com/foo?c=d'
    >>> url_concat("http://example.com/foo?a=b", dict(c="d"))
    'http://example.com/foo?a=b&c=d'
    >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")])
    'http://example.com/foo?a=b&c=d&c=d2'
    """
    if args is None:
        return url
    parsed_url = urlparse(url)
    if isinstance(args, dict):
        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)
        parsed_query.extend(args.items())
    elif isinstance(args, list) or isinstance(args, tuple):
        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)
        parsed_query.extend(args)
    else:
        err = "'args' parameter should be dict, list or tuple. Not {0}".format(
            type(args))
        raise TypeError(err)
    final_query = urlencode(parsed_query)
    url = urlunparse((
        parsed_url[0],
        parsed_url[1],
        parsed_url[2],
        parsed_url[3],
        final_query,
        parsed_url[5]))
    return url


class HTTPFile(ObjectDict):
    """Represents a file uploaded via a form.

    For backwards compatibility, its instance attributes are also
    accessible as dictionary keys.

    * ``filename``
    * ``body``
    * ``content_type``
    """
    pass


def _parse_request_range(range_header):
    """Parses a Range header.

    Returns either ``None`` or tuple ``(start, end)``.
    Note that while the HTTP headers use inclusive byte positions,
    this method returns indexes suitable for use in slices.

    >>> start, end = _parse_request_range("bytes=1-2")
    >>> start, end
    (1, 3)
    >>> [0, 1, 2, 3, 4][start:end]
    [1, 2]
    >>> _parse_request_range("bytes=6-")
    (6, None)
    >>> _parse_request_range("bytes=-6")
    (-6, None)
    >>> _parse_request_range("bytes=-0")
    (None, 0)
    >>> _parse_request_range("bytes=")
    (None, None)
    >>> _parse_request_range("foo=42")
    >>> _parse_request_range("bytes=1-2,6-10")

    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).

    See [0] for the details of the range header.

    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges
    """
    unit, _, value = range_header.partition("=")
    unit, value = unit.strip(), value.strip()
    if unit != "bytes":
        return None
    start_b, _, end_b = value.partition("-")
    try:
        start = _int_or_none(start_b)
        end = _int_or_none(end_b)
    except ValueError:
        return None
    if end is not None:
        if start is None:
            if end != 0:
                start = -end
                end = None
        else:
            end += 1
    return (start, end)


def _get_content_range(start, end, total):
    """Returns a suitable Content-Range header:

    >>> print(_get_content_range(None, 1, 4))
    bytes 0-0/4
    >>> print(_get_content_range(1, 3, 4))
    bytes 1-2/4
    >>> print(_get_content_range(None, None, 4))
    bytes 0-3/4
    """
    start = start or 0
    end = (end or total) - 1
    return "bytes %s-%s/%s" % (start, end, total)


def _int_or_none(val):
    val = val.strip()
    if val == "":
        return None
    return int(val)


def parse_body_arguments(content_type, body, arguments, files, headers=None):
    """Parses a form request body.

    Supports ``application/x-www-form-urlencoded`` and
    ``multipart/form-data``.  The ``content_type`` parameter should be
    a string and ``body`` should be a byte string.  The ``arguments``
    and ``files`` parameters are dictionaries that will be updated
    with the parsed contents.
    """
    if headers and 'Content-Encoding' in headers:
        gen_log.warning("Unsupported Content-Encoding: %s",
                        headers['Content-Encoding'])
        return
    if content_type.startswith("application/x-www-form-urlencoded"):
        try:
            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)
        except Exception as e:
            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)
            uri_arguments = {}
        for name, values in uri_arguments.items():
            if values:
                arguments.setdefault(name, []).extend(values)
    elif content_type.startswith("multipart/form-data"):
        try:
            fields = content_type.split(";")
            for field in fields:
                k, sep, v = field.strip().partition("=")
                if k == "boundary" and v:
                    parse_multipart_form_data(utf8(v), body, arguments, files)
                    break
            else:
                raise ValueError("multipart boundary not found")
        except Exception as e:
            gen_log.warning("Invalid multipart/form-data: %s", e)


def parse_multipart_form_data(boundary, data, arguments, files):
    """Parses a ``multipart/form-data`` body.

    The ``boundary`` and ``data`` parameters are both byte strings.
    The dictionaries given in the arguments and files parameters
    will be updated with the contents of the body.
    """
    # The standard allows for the boundary to be quoted in the header,
    # although it's rare (it happens at least for google app engine
    # xmpp).  I think we're also supposed to handle backslash-escapes
    # here but I'll save that until we see a client that uses them
    # in the wild.
    if boundary.startswith(b'"') and boundary.endswith(b'"'):
        boundary = boundary[1:-1]
    final_boundary_index = data.rfind(b"--" + boundary + b"--")
    if final_boundary_index == -1:
        gen_log.warning("Invalid multipart/form-data: no final boundary")
        return
    parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")
    for part in parts:
        if not part:
            continue
        eoh = part.find(b"\r\n\r\n")
        if eoh == -1:
            gen_log.warning("multipart/form-data missing headers")
            continue
        headers = HTTPHeaders.parse(part[:eoh].decode("utf-8"))
        disp_header = headers.get("Content-Disposition", "")
        disposition, disp_params = _parse_header(disp_header)
        if disposition != "form-data" or not part.endswith(b"\r\n"):
            gen_log.warning("Invalid multipart/form-data")
            continue
        value = part[eoh + 4:-2]
        if not disp_params.get("name"):
            gen_log.warning("multipart/form-data value missing name")
            continue
        name = disp_params["name"]
        if disp_params.get("filename"):
            ctype = headers.get("Content-Type", "application/unknown")
            files.setdefault(name, []).append(HTTPFile(  # type: ignore
                filename=disp_params["filename"], body=value,
                content_type=ctype))
        else:
            arguments.setdefault(name, []).append(value)


def format_timestamp(ts):
    """Formats a timestamp in the format used by HTTP.

    The argument may be a numeric timestamp as returned by `time.time`,
    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`
    object.

    >>> format_timestamp(1359312200)
    'Sun, 27 Jan 2013 18:43:20 GMT'
    """
    if isinstance(ts, numbers.Real):
        pass
    elif isinstance(ts, (tuple, time.struct_time)):
        ts = calendar.timegm(ts)
    elif isinstance(ts, datetime.datetime):
        ts = calendar.timegm(ts.utctimetuple())
    else:
        raise TypeError("unknown timestamp type: %r" % ts)
    return email.utils.formatdate(ts, usegmt=True)


RequestStartLine = collections.namedtuple(
    'RequestStartLine', ['method', 'path', 'version'])


def parse_request_start_line(line):
    """Returns a (method, path, version) tuple for an HTTP 1.x request line.

    The response is a `collections.namedtuple`.

    >>> parse_request_start_line("GET /foo HTTP/1.1")
    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')
    """
    try:
        method, path, version = line.split(" ")
    except ValueError:
        # https://tools.ietf.org/html/rfc7230#section-3.1.1
        # invalid request-line SHOULD respond with a 400 (Bad Request)
        raise HTTPInputError("Malformed HTTP request line")
    if not re.match(r"^HTTP/1\.[0-9]$", version):
        raise HTTPInputError(
            "Malformed HTTP version in HTTP Request-Line: %r" % version)
    return RequestStartLine(method, path, version)


ResponseStartLine = collections.namedtuple(
    'ResponseStartLine', ['version', 'code', 'reason'])


def parse_response_start_line(line):
    """Returns a (version, code, reason) tuple for an HTTP 1.x response line.

    The response is a `collections.namedtuple`.

    >>> parse_response_start_line("HTTP/1.1 200 OK")
    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')
    """
    line = native_str(line)
    match = re.match("(HTTP/1.[0-9]) ([0-9]+) ([^\r]*)", line)
    if not match:
        raise HTTPInputError("Error parsing response start line")
    return ResponseStartLine(match.group(1), int(match.group(2)),
                             match.group(3))

# _parseparam and _parse_header are copied and modified from python2.7's cgi.py
# The original 2.7 version of this code did not correctly support some
# combinations of semicolons and double quotes.
# It has also been modified to support valueless parameters as seen in
# websocket extension negotiations.


def _parseparam(s):
    while s[:1] == ';':
        s = s[1:]
        end = s.find(';')
        while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2:
            end = s.find(';', end + 1)
        if end < 0:
            end = len(s)
        f = s[:end]
        yield f.strip()
        s = s[end:]


def _parse_header(line):
    """Parse a Content-type like header.

    Return the main content-type and a dictionary of options.

    """
    parts = _parseparam(';' + line)
    key = next(parts)
    pdict = {}
    for p in parts:
        i = p.find('=')
        if i >= 0:
            name = p[:i].strip().lower()
            value = p[i + 1:].strip()
            if len(value) >= 2 and value[0] == value[-1] == '"':
                value = value[1:-1]
                value = value.replace('\\\\', '\\').replace('\\"', '"')
            pdict[name] = value
        else:
            pdict[p] = None
    return key, pdict


def _encode_header(key, pdict):
    """Inverse of _parse_header.

    >>> _encode_header('permessage-deflate',
    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})
    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'
    """
    if not pdict:
        return key
    out = [key]
    # Sort the parameters just to make it easy to test.
    for k, v in sorted(pdict.items()):
        if v is None:
            out.append(k)
        else:
            # TODO: quote if necessary.
            out.append('%s=%s' % (k, v))
    return '; '.join(out)


def doctests():
    import doctest
    return doctest.DocTestSuite()


def split_host_and_port(netloc):
    """Returns ``(host, port)`` tuple from ``netloc``.

    Returned ``port`` will be ``None`` if not present.

    .. versionadded:: 4.1
    """
    match = re.match(r'^(.+):(\d+)$', netloc)
    if match:
        host = match.group(1)
        port = int(match.group(2))
    else:
        host = netloc
        port = None
    return (host, port)


def qs_to_qsl(qs):
    """Generator rewinding a result of ``parse_qs`` back to name-value pairs. 
    """
    for k, vs in qs.items():
        for v in vs:
            yield (k, v)


_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
_QuotePatt = re.compile(r"[\\].")
_nulljoin = ''.join


def _unquote_cookie(str):
    """Handle double quotes and escaping in cookie values.

    This method is copied verbatim from the Python 3.5 standard
    library (http.cookies._unquote) so we don't have to depend on
    non-public interfaces.
    """
    # If there aren't any doublequotes,
    # then there can't be any special characters.  See RFC 2109.
    if str is None or len(str) < 2:
        return str
    if str[0] != '"' or str[-1] != '"':
        return str

    # We have to assume that we must decode this string.
    # Down to work.

    # Remove the "s
    str = str[1:-1]

    # Check for special sequences.  Examples:
    #    \012 --> \n
    #    \"   --> "
    #
    i = 0
    n = len(str)
    res = []
    while 0 <= i < n:
        o_match = _OctalPatt.search(str, i)
        q_match = _QuotePatt.search(str, i)
        if not o_match and not q_match:              # Neither matched
            res.append(str[i:])
            break
        # else:
        j = k = -1
        if o_match:
            j = o_match.start(0)
        if q_match:
            k = q_match.start(0)
        if q_match and (not o_match or k < j):     # QuotePatt matched
            res.append(str[i:k])
            res.append(str[k + 1])
            i = k + 2
        else:                                      # OctalPatt matched
            res.append(str[i:j])
            res.append(chr(int(str[j + 1:j + 4], 8)))
            i = j + 4
    return _nulljoin(res)


def parse_cookie(cookie):
    """Parse a ``Cookie`` HTTP header into a dict of name/value pairs.

    This function attempts to mimic browser cookie parsing behavior;
    it specifically does not follow any of the cookie-related RFCs
    (because browsers don't either).

    The algorithm used is identical to that used by Django version 1.9.10.

    .. versionadded:: 4.4.2
    """
    cookiedict = {}
    for chunk in cookie.split(str(';')):
        if str('=') in chunk:
            key, val = chunk.split(str('='), 1)
        else:
            # Assume an empty name per
            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
            key, val = str(''), chunk
        key, val = key.strip(), val.strip()
        if key or val:
            # unquote using Python's algorithm.
            cookiedict[key] = _unquote_cookie(val)
    return cookiedict

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** HTTPServerRequest `repr` Includes Headers, Risking Sensitive Information Exposure

**Description:**
When creating an instance of `HTTPServerRequest`, printing its representation includes all HTTP headers. This results in overly verbose logs and poses a security risk by potentially exposing sensitive user information.

**Example Code:**
```python
from tornado.httputil import HTTPServerRequest

request = HTTPServerRequest(uri='/', headers={'Authorization': 'Bearer secret_token'})
print(repr(request))
```

**Expected Behavior:**
The representation of `HTTPServerRequest` should exclude headers to keep logs concise and prevent leaking sensitive information.

**Actual Behavior:**
The `repr` of `HTTPServerRequest` includes all headers, such as the `Authorization` header, which can expose sensitive data in application logs.
[/ISSUE]
{
    "FormatTimestampTest.test_datetime": "PASSED",
    "FormatTimestampTest.test_struct_time": "PASSED",
    "FormatTimestampTest.test_time_tuple": "PASSED",
    "FormatTimestampTest.test_unix_time_float": "PASSED",
    "FormatTimestampTest.test_unix_time_int": "PASSED",
    "HTTPHeadersTest.test_copy": "PASSED",
    "HTTPHeadersTest.test_multi_line": "PASSED",
    "HTTPHeadersTest.test_optional_cr": "PASSED",
    "HTTPHeadersTest.test_pickle_roundtrip": "PASSED",
    "HTTPHeadersTest.test_setdefault": "PASSED",
    "HTTPHeadersTest.test_string": "PASSED",
    "HTTPHeadersTest.test_unicode_newlines": "PASSED",
    "HTTPServerRequestTest.test_body_is_a_byte_string": "PASSED",
    "HTTPServerRequestTest.test_default_constructor": "PASSED",
    "HTTPServerRequestTest.test_repr_does_not_contain_headers": "PASSED",
    "MultipartFormDataTest.test_boundary_starts_and_ends_with_quotes": "PASSED",
    "MultipartFormDataTest.test_content_disposition_header_without_name_parameter": "PASSED",
    "MultipartFormDataTest.test_data_after_final_boundary": "PASSED",
    "MultipartFormDataTest.test_file_upload": "PASSED",
    "MultipartFormDataTest.test_invalid_content_disposition": "PASSED",
    "MultipartFormDataTest.test_line_does_not_end_with_correct_line_break": "PASSED",
    "MultipartFormDataTest.test_missing_headers": "PASSED",
    "MultipartFormDataTest.test_special_filenames": "PASSED",
    "MultipartFormDataTest.test_unquoted_names": "PASSED",
    "ParseCookieTest.test_cookie_edgecases": "PASSED",
    "ParseCookieTest.test_invalid_cookies": "PASSED",
    "ParseCookieTest.test_python_cookies": "PASSED",
    "ParseRequestStartLineTest.test_parse_request_start_line": "PASSED",
    "QsParseTest.test_parsing": "PASSED",
    "TestUrlConcat.test_url_concat_dict_params": "PASSED",
    "TestUrlConcat.test_url_concat_encode_args": "PASSED",
    "TestUrlConcat.test_url_concat_mult_params": "PASSED",
    "TestUrlConcat.test_url_concat_multi_same_params": "PASSED",
    "TestUrlConcat.test_url_concat_multi_same_query_params": "PASSED",
    "TestUrlConcat.test_url_concat_no_params": "PASSED",
    "TestUrlConcat.test_url_concat_no_query_params": "PASSED",
    "TestUrlConcat.test_url_concat_none_params": "PASSED",
    "TestUrlConcat.test_url_concat_q_with_no_trailing_amp": "PASSED",
    "TestUrlConcat.test_url_concat_trailing_amp": "PASSED",
    "TestUrlConcat.test_url_concat_trailing_q": "PASSED",
    "TestUrlConcat.test_url_concat_with_frag": "PASSED"
}
diff --git a/tornado/httputil.py b/tornado/httputil.py
index a98273ae..f2b289b3 100755
--- a/tornado/httputil.py
+++ b/tornado/httputil.py
@@ -467,8 +467,7 @@ class HTTPServerRequest(object):
     def __repr__(self):
         attrs = ("protocol", "host", "method", "uri", "version", "remote_ip")
         args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs])
-        return "%s(%s, headers=%s)" % (
-            self.__class__.__name__, args, dict(self.headers))
+        return "%s(%s)" % (self.__class__.__name__, args)
 
 
 class HTTPInputError(Exception):

{"tornado/httputil.py": "#!/usr/bin/env python\n#\n# Copyright 2009 Facebook\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\"\"\"HTTP utility code shared by clients and servers.\n\nThis module also defines the `HTTPServerRequest` class which is exposed\nvia `tornado.web.RequestHandler.request`.\n\"\"\"\n\nfrom __future__ import absolute_import, division, print_function\n\nimport calendar\nimport collections\nimport copy\nimport datetime\nimport email.utils\nimport numbers\nimport re\nimport time\n\nfrom tornado.escape import native_str, parse_qs_bytes, utf8\nfrom tornado.log import gen_log\nfrom tornado.util import ObjectDict, PY3\n\nif PY3:\n    import http.cookies as Cookie\n    from http.client import responses\n    from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl\nelse:\n    import Cookie\n    from httplib import responses\n    from urllib import urlencode\n    from urlparse import urlparse, urlunparse, parse_qsl\n\n\n# responses is unused in this file, but we re-export it to other files.\n# Reference it so pyflakes doesn't complain.\nresponses\n\ntry:\n    from ssl import SSLError\nexcept ImportError:\n    # ssl is unavailable on app engine.\n    class _SSLError(Exception):\n        pass\n    # Hack around a mypy limitation. We can't simply put \"type: ignore\"\n    # on the class definition itself; must go through an assignment.\n    SSLError = _SSLError  # type: ignore\n\ntry:\n    import typing\nexcept ImportError:\n    pass\n\n\n# RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line\n# terminator and ignore any preceding CR.\n_CRLF_RE = re.compile(r'\\r?\\n')\n\n\nclass _NormalizedHeaderCache(dict):\n    \"\"\"Dynamic cached mapping of header names to Http-Header-Case.\n\n    Implemented as a dict subclass so that cache hits are as fast as a\n    normal dict lookup, without the overhead of a python function\n    call.\n\n    >>> normalized_headers = _NormalizedHeaderCache(10)\n    >>> normalized_headers[\"coNtent-TYPE\"]\n    'Content-Type'\n    \"\"\"\n    def __init__(self, size):\n        super(_NormalizedHeaderCache, self).__init__()\n        self.size = size\n        self.queue = collections.deque()\n\n    def __missing__(self, key):\n        normalized = \"-\".join([w.capitalize() for w in key.split(\"-\")])\n        self[key] = normalized\n        self.queue.append(key)\n        if len(self.queue) > self.size:\n            # Limit the size of the cache.  LRU would be better, but this\n            # simpler approach should be fine.  In Python 2.7+ we could\n            # use OrderedDict (or in 3.2+, @functools.lru_cache).\n            old_key = self.queue.popleft()\n            del self[old_key]\n        return normalized\n\n\n_normalized_headers = _NormalizedHeaderCache(1000)\n\n\nclass HTTPHeaders(collections.MutableMapping):\n    \"\"\"A dictionary that maintains ``Http-Header-Case`` for all keys.\n\n    Supports multiple values per key via a pair of new methods,\n    `add()` and `get_list()`.  The regular dictionary interface\n    returns a single value per key, with multiple values joined by a\n    comma.\n\n    >>> h = HTTPHeaders({\"content-type\": \"text/html\"})\n    >>> list(h.keys())\n    ['Content-Type']\n    >>> h[\"Content-Type\"]\n    'text/html'\n\n    >>> h.add(\"Set-Cookie\", \"A=B\")\n    >>> h.add(\"Set-Cookie\", \"C=D\")\n    >>> h[\"set-cookie\"]\n    'A=B,C=D'\n    >>> h.get_list(\"set-cookie\")\n    ['A=B', 'C=D']\n\n    >>> for (k,v) in sorted(h.get_all()):\n    ...    print('%s: %s' % (k,v))\n    ...\n    Content-Type: text/html\n    Set-Cookie: A=B\n    Set-Cookie: C=D\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self._dict = {}  # type: typing.Dict[str, str]\n        self._as_list = {}  # type: typing.Dict[str, typing.List[str]]\n        self._last_key = None\n        if (len(args) == 1 and len(kwargs) == 0 and\n                isinstance(args[0], HTTPHeaders)):\n            # Copy constructor\n            for k, v in args[0].get_all():\n                self.add(k, v)\n        else:\n            # Dict-style initialization\n            self.update(*args, **kwargs)\n\n    # new public methods\n\n    def add(self, name, value):\n        # type: (str, str) -> None\n        \"\"\"Adds a new value for the given key.\"\"\"\n        norm_name = _normalized_headers[name]\n        self._last_key = norm_name\n        if norm_name in self:\n            self._dict[norm_name] = (native_str(self[norm_name]) + ',' +\n                                     native_str(value))\n            self._as_list[norm_name].append(value)\n        else:\n            self[norm_name] = value\n\n    def get_list(self, name):\n        \"\"\"Returns all values for the given header as a list.\"\"\"\n        norm_name = _normalized_headers[name]\n        return self._as_list.get(norm_name, [])\n\n    def get_all(self):\n        # type: () -> typing.Iterable[typing.Tuple[str, str]]\n        \"\"\"Returns an iterable of all (name, value) pairs.\n\n        If a header has multiple values, multiple pairs will be\n        returned with the same name.\n        \"\"\"\n        for name, values in self._as_list.items():\n            for value in values:\n                yield (name, value)\n\n    def parse_line(self, line):\n        \"\"\"Updates the dictionary with a single header line.\n\n        >>> h = HTTPHeaders()\n        >>> h.parse_line(\"Content-Type: text/html\")\n        >>> h.get('content-type')\n        'text/html'\n        \"\"\"\n        if line[0].isspace():\n            # continuation of a multi-line header\n            new_part = ' ' + line.lstrip()\n            self._as_list[self._last_key][-1] += new_part\n            self._dict[self._last_key] += new_part\n        else:\n            name, value = line.split(\":\", 1)\n            self.add(name, value.strip())\n\n    @classmethod\n    def parse(cls, headers):\n        \"\"\"Returns a dictionary from HTTP header text.\n\n        >>> h = HTTPHeaders.parse(\"Content-Type: text/html\\\\r\\\\nContent-Length: 42\\\\r\\\\n\")\n        >>> sorted(h.items())\n        [('Content-Length', '42'), ('Content-Type', 'text/html')]\n        \"\"\"\n        h = cls()\n        for line in _CRLF_RE.split(headers):\n            if line:\n                h.parse_line(line)\n        return h\n\n    # MutableMapping abstract method implementations.\n\n    def __setitem__(self, name, value):\n        norm_name = _normalized_headers[name]\n        self._dict[norm_name] = value\n        self._as_list[norm_name] = [value]\n\n    def __getitem__(self, name):\n        # type: (str) -> str\n        return self._dict[_normalized_headers[name]]\n\n    def __delitem__(self, name):\n        norm_name = _normalized_headers[name]\n        del self._dict[norm_name]\n        del self._as_list[norm_name]\n\n    def __len__(self):\n        return len(self._dict)\n\n    def __iter__(self):\n        return iter(self._dict)\n\n    def copy(self):\n        # defined in dict but not in MutableMapping.\n        return HTTPHeaders(self)\n\n    # Use our overridden copy method for the copy.copy module.\n    # This makes shallow copies one level deeper, but preserves\n    # the appearance that HTTPHeaders is a single container.\n    __copy__ = copy\n\n    def __str__(self):\n        lines = []\n        for name, value in self.get_all():\n            lines.append(\"%s: %s\\n\" % (name, value))\n        return \"\".join(lines)\n\n    __unicode__ = __str__\n\n\nclass HTTPServerRequest(object):\n    \"\"\"A single HTTP request.\n\n    All attributes are type `str` unless otherwise noted.\n\n    .. attribute:: method\n\n       HTTP request method, e.g. \"GET\" or \"POST\"\n\n    .. attribute:: uri\n\n       The requested uri.\n\n    .. attribute:: path\n\n       The path portion of `uri`\n\n    .. attribute:: query\n\n       The query portion of `uri`\n\n    .. attribute:: version\n\n       HTTP version specified in request, e.g. \"HTTP/1.1\"\n\n    .. attribute:: headers\n\n       `.HTTPHeaders` dictionary-like object for request headers.  Acts like\n       a case-insensitive dictionary with additional methods for repeated\n       headers.\n\n    .. attribute:: body\n\n       Request body, if present, as a byte string.\n\n    .. attribute:: remote_ip\n\n       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,\n       will pass along the real IP address provided by a load balancer\n       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.\n\n    .. versionchanged:: 3.1\n       The list format of ``X-Forwarded-For`` is now supported.\n\n    .. attribute:: protocol\n\n       The protocol used, either \"http\" or \"https\".  If ``HTTPServer.xheaders``\n       is set, will pass along the protocol used by a load balancer if\n       reported via an ``X-Scheme`` header.\n\n    .. attribute:: host\n\n       The requested hostname, usually taken from the ``Host`` header.\n\n    .. attribute:: arguments\n\n       GET/POST arguments are available in the arguments property, which\n       maps arguments names to lists of values (to support multiple values\n       for individual names). Names are of type `str`, while arguments\n       are byte strings.  Note that this is different from\n       `.RequestHandler.get_argument`, which returns argument values as\n       unicode strings.\n\n    .. attribute:: query_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the query string.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: body_arguments\n\n       Same format as ``arguments``, but contains only arguments extracted\n       from the request body.\n\n       .. versionadded:: 3.2\n\n    .. attribute:: files\n\n       File uploads are available in the files property, which maps file\n       names to lists of `.HTTPFile`.\n\n    .. attribute:: connection\n\n       An HTTP request is attached to a single HTTP connection, which can\n       be accessed through the \"connection\" attribute. Since connections\n       are typically kept open in HTTP/1.1, multiple requests can be handled\n       sequentially on a single connection.\n\n    .. versionchanged:: 4.0\n       Moved from ``tornado.httpserver.HTTPRequest``.\n    \"\"\"\n    def __init__(self, method=None, uri=None, version=\"HTTP/1.0\", headers=None,\n                 body=None, host=None, files=None, connection=None,\n                 start_line=None, server_connection=None):\n        if start_line is not None:\n            method, uri, version = start_line\n        self.method = method\n        self.uri = uri\n        self.version = version\n        self.headers = headers or HTTPHeaders()\n        self.body = body or b\"\"\n\n        # set remote IP and protocol\n        context = getattr(connection, 'context', None)\n        self.remote_ip = getattr(context, 'remote_ip', None)\n        self.protocol = getattr(context, 'protocol', \"http\")\n\n        self.host = host or self.headers.get(\"Host\") or \"127.0.0.1\"\n        self.host_name = split_host_and_port(self.host.lower())[0]\n        self.files = files or {}\n        self.connection = connection\n        self.server_connection = server_connection\n        self._start_time = time.time()\n        self._finish_time = None\n\n        self.path, sep, self.query = uri.partition('?')\n        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)\n        self.query_arguments = copy.deepcopy(self.arguments)\n        self.body_arguments = {}\n\n    def supports_http_1_1(self):\n        \"\"\"Returns True if this request supports HTTP/1.1 semantics.\n\n        .. deprecated:: 4.0\n           Applications are less likely to need this information with the\n           introduction of `.HTTPConnection`.  If you still need it, access\n           the ``version`` attribute directly.\n        \"\"\"\n        return self.version == \"HTTP/1.1\"\n\n    @property\n    def cookies(self):\n        \"\"\"A dictionary of Cookie.Morsel objects.\"\"\"\n        if not hasattr(self, \"_cookies\"):\n            self._cookies = Cookie.SimpleCookie()\n            if \"Cookie\" in self.headers:\n                try:\n                    parsed = parse_cookie(self.headers[\"Cookie\"])\n                except Exception:\n                    pass\n                else:\n                    for k, v in parsed.items():\n                        try:\n                            self._cookies[k] = v\n                        except Exception:\n                            # SimpleCookie imposes some restrictions on keys;\n                            # parse_cookie does not. Discard any cookies\n                            # with disallowed keys.\n                            pass\n        return self._cookies\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes the given chunk to the response stream.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        assert isinstance(chunk, bytes)\n        assert self.version.startswith(\"HTTP/1.\"), \\\n            \"deprecated interface only supported in HTTP/1.x\"\n        self.connection.write(chunk, callback=callback)\n\n    def finish(self):\n        \"\"\"Finishes this HTTP request on the open connection.\n\n        .. deprecated:: 4.0\n           Use ``request.connection`` and the `.HTTPConnection` methods\n           to write the response.\n        \"\"\"\n        self.connection.finish()\n        self._finish_time = time.time()\n\n    def full_url(self):\n        \"\"\"Reconstructs the full URL for this request.\"\"\"\n        return self.protocol + \"://\" + self.host + self.uri\n\n    def request_time(self):\n        \"\"\"Returns the amount of time it took for this request to execute.\"\"\"\n        if self._finish_time is None:\n            return time.time() - self._start_time\n        else:\n            return self._finish_time - self._start_time\n\n    def get_ssl_certificate(self, binary_form=False):\n        \"\"\"Returns the client's SSL certificate, if any.\n\n        To use client certificates, the HTTPServer's\n        `ssl.SSLContext.verify_mode` field must be set, e.g.::\n\n            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)\n            ssl_ctx.load_cert_chain(\"foo.crt\", \"foo.key\")\n            ssl_ctx.load_verify_locations(\"cacerts.pem\")\n            ssl_ctx.verify_mode = ssl.CERT_REQUIRED\n            server = HTTPServer(app, ssl_options=ssl_ctx)\n\n        By default, the return value is a dictionary (or None, if no\n        client certificate is present).  If ``binary_form`` is true, a\n        DER-encoded form of the certificate is returned instead.  See\n        SSLSocket.getpeercert() in the standard library for more\n        details.\n        http://docs.python.org/library/ssl.html#sslsocket-objects\n        \"\"\"\n        try:\n            return self.connection.stream.socket.getpeercert(\n                binary_form=binary_form)\n        except SSLError:\n            return None\n\n    def _parse_body(self):\n        parse_body_arguments(\n            self.headers.get(\"Content-Type\", \"\"), self.body,\n            self.body_arguments, self.files,\n            self.headers)\n\n        for k, v in self.body_arguments.items():\n            self.arguments.setdefault(k, []).extend(v)\n\n    def __repr__(self):\n        attrs = (\"protocol\", \"host\", \"method\", \"uri\", \"version\", \"remote_ip\")\n        args = \", \".join([\"%s=%r\" % (n, getattr(self, n)) for n in attrs])\n        return \"%s(%s, headers=%s)\" % (\n            self.__class__.__name__, args, dict(self.headers))\n\n\nclass HTTPInputError(Exception):\n    \"\"\"Exception class for malformed HTTP requests or responses\n    from remote sources.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPOutputError(Exception):\n    \"\"\"Exception class for errors in HTTP output.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    pass\n\n\nclass HTTPServerConnectionDelegate(object):\n    \"\"\"Implement this interface to handle requests from `.HTTPServer`.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def start_request(self, server_conn, request_conn):\n        \"\"\"This method is called by the server when a new request has started.\n\n        :arg server_conn: is an opaque object representing the long-lived\n            (e.g. tcp-level) connection.\n        :arg request_conn: is a `.HTTPConnection` object for a single\n            request/response exchange.\n\n        This method should return a `.HTTPMessageDelegate`.\n        \"\"\"\n        raise NotImplementedError()\n\n    def on_close(self, server_conn):\n        \"\"\"This method is called when a connection has been closed.\n\n        :arg server_conn: is a server connection that has previously been\n            passed to ``start_request``.\n        \"\"\"\n        pass\n\n\nclass HTTPMessageDelegate(object):\n    \"\"\"Implement this interface to handle an HTTP request or response.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def headers_received(self, start_line, headers):\n        \"\"\"Called when the HTTP headers have been received and parsed.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`\n            depending on whether this is a client or server message.\n        :arg headers: a `.HTTPHeaders` instance.\n\n        Some `.HTTPConnection` methods can only be called during\n        ``headers_received``.\n\n        May return a `.Future`; if it does the body will not be read\n        until it is done.\n        \"\"\"\n        pass\n\n    def data_received(self, chunk):\n        \"\"\"Called when a chunk of data has been received.\n\n        May return a `.Future` for flow control.\n        \"\"\"\n        pass\n\n    def finish(self):\n        \"\"\"Called after the last chunk of data has been received.\"\"\"\n        pass\n\n    def on_connection_close(self):\n        \"\"\"Called if the connection is closed without finishing the request.\n\n        If ``headers_received`` is called, either ``finish`` or\n        ``on_connection_close`` will be called, but not both.\n        \"\"\"\n        pass\n\n\nclass HTTPConnection(object):\n    \"\"\"Applications use this interface to write their responses.\n\n    .. versionadded:: 4.0\n    \"\"\"\n    def write_headers(self, start_line, headers, chunk=None, callback=None):\n        \"\"\"Write an HTTP header block.\n\n        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.\n        :arg headers: a `.HTTPHeaders` instance.\n        :arg chunk: the first (optional) chunk of data.  This is an optimization\n            so that small responses can be written in the same call as their\n            headers.\n        :arg callback: a callback to be run when the write is complete.\n\n        The ``version`` field of ``start_line`` is ignored.\n\n        Returns a `.Future` if no callback is given.\n        \"\"\"\n        raise NotImplementedError()\n\n    def write(self, chunk, callback=None):\n        \"\"\"Writes a chunk of body data.\n\n        The callback will be run when the write is complete.  If no callback\n        is given, returns a Future.\n        \"\"\"\n        raise NotImplementedError()\n\n    def finish(self):\n        \"\"\"Indicates that the last body data has been written.\n        \"\"\"\n        raise NotImplementedError()\n\n\ndef url_concat(url, args):\n    \"\"\"Concatenate url and arguments regardless of whether\n    url has existing query parameters.\n\n    ``args`` may be either a dictionary or a list of key-value pairs\n    (the latter allows for multiple values with the same key.\n\n    >>> url_concat(\"http://example.com/foo\", dict(c=\"d\"))\n    'http://example.com/foo?c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", dict(c=\"d\"))\n    'http://example.com/foo?a=b&c=d'\n    >>> url_concat(\"http://example.com/foo?a=b\", [(\"c\", \"d\"), (\"c\", \"d2\")])\n    'http://example.com/foo?a=b&c=d&c=d2'\n    \"\"\"\n    if args is None:\n        return url\n    parsed_url = urlparse(url)\n    if isinstance(args, dict):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args.items())\n    elif isinstance(args, list) or isinstance(args, tuple):\n        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)\n        parsed_query.extend(args)\n    else:\n        err = \"'args' parameter should be dict, list or tuple. Not {0}\".format(\n            type(args))\n        raise TypeError(err)\n    final_query = urlencode(parsed_query)\n    url = urlunparse((\n        parsed_url[0],\n        parsed_url[1],\n        parsed_url[2],\n        parsed_url[3],\n        final_query,\n        parsed_url[5]))\n    return url\n\n\nclass HTTPFile(ObjectDict):\n    \"\"\"Represents a file uploaded via a form.\n\n    For backwards compatibility, its instance attributes are also\n    accessible as dictionary keys.\n\n    * ``filename``\n    * ``body``\n    * ``content_type``\n    \"\"\"\n    pass\n\n\ndef _parse_request_range(range_header):\n    \"\"\"Parses a Range header.\n\n    Returns either ``None`` or tuple ``(start, end)``.\n    Note that while the HTTP headers use inclusive byte positions,\n    this method returns indexes suitable for use in slices.\n\n    >>> start, end = _parse_request_range(\"bytes=1-2\")\n    >>> start, end\n    (1, 3)\n    >>> [0, 1, 2, 3, 4][start:end]\n    [1, 2]\n    >>> _parse_request_range(\"bytes=6-\")\n    (6, None)\n    >>> _parse_request_range(\"bytes=-6\")\n    (-6, None)\n    >>> _parse_request_range(\"bytes=-0\")\n    (None, 0)\n    >>> _parse_request_range(\"bytes=\")\n    (None, None)\n    >>> _parse_request_range(\"foo=42\")\n    >>> _parse_request_range(\"bytes=1-2,6-10\")\n\n    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).\n\n    See [0] for the details of the range header.\n\n    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges\n    \"\"\"\n    unit, _, value = range_header.partition(\"=\")\n    unit, value = unit.strip(), value.strip()\n    if unit != \"bytes\":\n        return None\n    start_b, _, end_b = value.partition(\"-\")\n    try:\n        start = _int_or_none(start_b)\n        end = _int_or_none(end_b)\n    except ValueError:\n        return None\n    if end is not None:\n        if start is None:\n            if end != 0:\n                start = -end\n                end = None\n        else:\n            end += 1\n    return (start, end)\n\n\ndef _get_content_range(start, end, total):\n    \"\"\"Returns a suitable Content-Range header:\n\n    >>> print(_get_content_range(None, 1, 4))\n    bytes 0-0/4\n    >>> print(_get_content_range(1, 3, 4))\n    bytes 1-2/4\n    >>> print(_get_content_range(None, None, 4))\n    bytes 0-3/4\n    \"\"\"\n    start = start or 0\n    end = (end or total) - 1\n    return \"bytes %s-%s/%s\" % (start, end, total)\n\n\ndef _int_or_none(val):\n    val = val.strip()\n    if val == \"\":\n        return None\n    return int(val)\n\n\ndef parse_body_arguments(content_type, body, arguments, files, headers=None):\n    \"\"\"Parses a form request body.\n\n    Supports ``application/x-www-form-urlencoded`` and\n    ``multipart/form-data``.  The ``content_type`` parameter should be\n    a string and ``body`` should be a byte string.  The ``arguments``\n    and ``files`` parameters are dictionaries that will be updated\n    with the parsed contents.\n    \"\"\"\n    if headers and 'Content-Encoding' in headers:\n        gen_log.warning(\"Unsupported Content-Encoding: %s\",\n                        headers['Content-Encoding'])\n        return\n    if content_type.startswith(\"application/x-www-form-urlencoded\"):\n        try:\n            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)\n        except Exception as e:\n            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)\n            uri_arguments = {}\n        for name, values in uri_arguments.items():\n            if values:\n                arguments.setdefault(name, []).extend(values)\n    elif content_type.startswith(\"multipart/form-data\"):\n        try:\n            fields = content_type.split(\";\")\n            for field in fields:\n                k, sep, v = field.strip().partition(\"=\")\n                if k == \"boundary\" and v:\n                    parse_multipart_form_data(utf8(v), body, arguments, files)\n                    break\n            else:\n                raise ValueError(\"multipart boundary not found\")\n        except Exception as e:\n            gen_log.warning(\"Invalid multipart/form-data: %s\", e)\n\n\ndef parse_multipart_form_data(boundary, data, arguments, files):\n    \"\"\"Parses a ``multipart/form-data`` body.\n\n    The ``boundary`` and ``data`` parameters are both byte strings.\n    The dictionaries given in the arguments and files parameters\n    will be updated with the contents of the body.\n    \"\"\"\n    # The standard allows for the boundary to be quoted in the header,\n    # although it's rare (it happens at least for google app engine\n    # xmpp).  I think we're also supposed to handle backslash-escapes\n    # here but I'll save that until we see a client that uses them\n    # in the wild.\n    if boundary.startswith(b'\"') and boundary.endswith(b'\"'):\n        boundary = boundary[1:-1]\n    final_boundary_index = data.rfind(b\"--\" + boundary + b\"--\")\n    if final_boundary_index == -1:\n        gen_log.warning(\"Invalid multipart/form-data: no final boundary\")\n        return\n    parts = data[:final_boundary_index].split(b\"--\" + boundary + b\"\\r\\n\")\n    for part in parts:\n        if not part:\n            continue\n        eoh = part.find(b\"\\r\\n\\r\\n\")\n        if eoh == -1:\n            gen_log.warning(\"multipart/form-data missing headers\")\n            continue\n        headers = HTTPHeaders.parse(part[:eoh].decode(\"utf-8\"))\n        disp_header = headers.get(\"Content-Disposition\", \"\")\n        disposition, disp_params = _parse_header(disp_header)\n        if disposition != \"form-data\" or not part.endswith(b\"\\r\\n\"):\n            gen_log.warning(\"Invalid multipart/form-data\")\n            continue\n        value = part[eoh + 4:-2]\n        if not disp_params.get(\"name\"):\n            gen_log.warning(\"multipart/form-data value missing name\")\n            continue\n        name = disp_params[\"name\"]\n        if disp_params.get(\"filename\"):\n            ctype = headers.get(\"Content-Type\", \"application/unknown\")\n            files.setdefault(name, []).append(HTTPFile(  # type: ignore\n                filename=disp_params[\"filename\"], body=value,\n                content_type=ctype))\n        else:\n            arguments.setdefault(name, []).append(value)\n\n\ndef format_timestamp(ts):\n    \"\"\"Formats a timestamp in the format used by HTTP.\n\n    The argument may be a numeric timestamp as returned by `time.time`,\n    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`\n    object.\n\n    >>> format_timestamp(1359312200)\n    'Sun, 27 Jan 2013 18:43:20 GMT'\n    \"\"\"\n    if isinstance(ts, numbers.Real):\n        pass\n    elif isinstance(ts, (tuple, time.struct_time)):\n        ts = calendar.timegm(ts)\n    elif isinstance(ts, datetime.datetime):\n        ts = calendar.timegm(ts.utctimetuple())\n    else:\n        raise TypeError(\"unknown timestamp type: %r\" % ts)\n    return email.utils.formatdate(ts, usegmt=True)\n\n\nRequestStartLine = collections.namedtuple(\n    'RequestStartLine', ['method', 'path', 'version'])\n\n\ndef parse_request_start_line(line):\n    \"\"\"Returns a (method, path, version) tuple for an HTTP 1.x request line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_request_start_line(\"GET /foo HTTP/1.1\")\n    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')\n    \"\"\"\n    try:\n        method, path, version = line.split(\" \")\n    except ValueError:\n        # https://tools.ietf.org/html/rfc7230#section-3.1.1\n        # invalid request-line SHOULD respond with a 400 (Bad Request)\n        raise HTTPInputError(\"Malformed HTTP request line\")\n    if not re.match(r\"^HTTP/1\\.[0-9]$\", version):\n        raise HTTPInputError(\n            \"Malformed HTTP version in HTTP Request-Line: %r\" % version)\n    return RequestStartLine(method, path, version)\n\n\nResponseStartLine = collections.namedtuple(\n    'ResponseStartLine', ['version', 'code', 'reason'])\n\n\ndef parse_response_start_line(line):\n    \"\"\"Returns a (version, code, reason) tuple for an HTTP 1.x response line.\n\n    The response is a `collections.namedtuple`.\n\n    >>> parse_response_start_line(\"HTTP/1.1 200 OK\")\n    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')\n    \"\"\"\n    line = native_str(line)\n    match = re.match(\"(HTTP/1.[0-9]) ([0-9]+) ([^\\r]*)\", line)\n    if not match:\n        raise HTTPInputError(\"Error parsing response start line\")\n    return ResponseStartLine(match.group(1), int(match.group(2)),\n                             match.group(3))\n\n# _parseparam and _parse_header are copied and modified from python2.7's cgi.py\n# The original 2.7 version of this code did not correctly support some\n# combinations of semicolons and double quotes.\n# It has also been modified to support valueless parameters as seen in\n# websocket extension negotiations.\n\n\ndef _parseparam(s):\n    while s[:1] == ';':\n        s = s[1:]\n        end = s.find(';')\n        while end > 0 and (s.count('\"', 0, end) - s.count('\\\\\"', 0, end)) % 2:\n            end = s.find(';', end + 1)\n        if end < 0:\n            end = len(s)\n        f = s[:end]\n        yield f.strip()\n        s = s[end:]\n\n\ndef _parse_header(line):\n    \"\"\"Parse a Content-type like header.\n\n    Return the main content-type and a dictionary of options.\n\n    \"\"\"\n    parts = _parseparam(';' + line)\n    key = next(parts)\n    pdict = {}\n    for p in parts:\n        i = p.find('=')\n        if i >= 0:\n            name = p[:i].strip().lower()\n            value = p[i + 1:].strip()\n            if len(value) >= 2 and value[0] == value[-1] == '\"':\n                value = value[1:-1]\n                value = value.replace('\\\\\\\\', '\\\\').replace('\\\\\"', '\"')\n            pdict[name] = value\n        else:\n            pdict[p] = None\n    return key, pdict\n\n\ndef _encode_header(key, pdict):\n    \"\"\"Inverse of _parse_header.\n\n    >>> _encode_header('permessage-deflate',\n    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})\n    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'\n    \"\"\"\n    if not pdict:\n        return key\n    out = [key]\n    # Sort the parameters just to make it easy to test.\n    for k, v in sorted(pdict.items()):\n        if v is None:\n            out.append(k)\n        else:\n            # TODO: quote if necessary.\n            out.append('%s=%s' % (k, v))\n    return '; '.join(out)\n\n\ndef doctests():\n    import doctest\n    return doctest.DocTestSuite()\n\n\ndef split_host_and_port(netloc):\n    \"\"\"Returns ``(host, port)`` tuple from ``netloc``.\n\n    Returned ``port`` will be ``None`` if not present.\n\n    .. versionadded:: 4.1\n    \"\"\"\n    match = re.match(r'^(.+):(\\d+)$', netloc)\n    if match:\n        host = match.group(1)\n        port = int(match.group(2))\n    else:\n        host = netloc\n        port = None\n    return (host, port)\n\n\ndef qs_to_qsl(qs):\n    \"\"\"Generator rewinding a result of ``parse_qs`` back to name-value pairs. \n    \"\"\"\n    for k, vs in qs.items():\n        for v in vs:\n            yield (k, v)\n\n\n_OctalPatt = re.compile(r\"\\\\[0-3][0-7][0-7]\")\n_QuotePatt = re.compile(r\"[\\\\].\")\n_nulljoin = ''.join\n\n\ndef _unquote_cookie(str):\n    \"\"\"Handle double quotes and escaping in cookie values.\n\n    This method is copied verbatim from the Python 3.5 standard\n    library (http.cookies._unquote) so we don't have to depend on\n    non-public interfaces.\n    \"\"\"\n    # If there aren't any doublequotes,\n    # then there can't be any special characters.  See RFC 2109.\n    if str is None or len(str) < 2:\n        return str\n    if str[0] != '\"' or str[-1] != '\"':\n        return str\n\n    # We have to assume that we must decode this string.\n    # Down to work.\n\n    # Remove the \"s\n    str = str[1:-1]\n\n    # Check for special sequences.  Examples:\n    #    \\012 --> \\n\n    #    \\\"   --> \"\n    #\n    i = 0\n    n = len(str)\n    res = []\n    while 0 <= i < n:\n        o_match = _OctalPatt.search(str, i)\n        q_match = _QuotePatt.search(str, i)\n        if not o_match and not q_match:              # Neither matched\n            res.append(str[i:])\n            break\n        # else:\n        j = k = -1\n        if o_match:\n            j = o_match.start(0)\n        if q_match:\n            k = q_match.start(0)\n        if q_match and (not o_match or k < j):     # QuotePatt matched\n            res.append(str[i:k])\n            res.append(str[k + 1])\n            i = k + 2\n        else:                                      # OctalPatt matched\n            res.append(str[i:j])\n            res.append(chr(int(str[j + 1:j + 4], 8)))\n            i = j + 4\n    return _nulljoin(res)\n\n\ndef parse_cookie(cookie):\n    \"\"\"Parse a ``Cookie`` HTTP header into a dict of name/value pairs.\n\n    This function attempts to mimic browser cookie parsing behavior;\n    it specifically does not follow any of the cookie-related RFCs\n    (because browsers don't either).\n\n    The algorithm used is identical to that used by Django version 1.9.10.\n\n    .. versionadded:: 4.4.2\n    \"\"\"\n    cookiedict = {}\n    for chunk in cookie.split(str(';')):\n        if str('=') in chunk:\n            key, val = chunk.split(str('='), 1)\n        else:\n            # Assume an empty name per\n            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091\n            key, val = str(''), chunk\n        key, val = key.strip(), val.strip()\n        if key or val:\n            # unquote using Python's algorithm.\n            cookiedict[key] = _unquote_cookie(val)\n    return cookiedict\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** HTTPServerRequest `repr` Includes Headers, Risking Sensitive Information Exposure

**Description:**
When creating an instance of `HTTPServerRequest`, printing its representation includes all HTTP headers. This results in overly verbose logs and poses a security risk by potentially exposing sensitive user information.

**Example Code:**
```python
from tornado.httputil import HTTPServerRequest

request = HTTPServerRequest(uri='/', headers={'Authorization': 'Bearer secret_token'})
print(repr(request))
```

**Expected Behavior:**
The representation of `HTTPServerRequest` should exclude headers to keep logs concise and prevent leaking sensitive information.

**Actual Behavior:**
The `repr` of `HTTPServerRequest` includes all headers, such as the `Authorization` header, which can expose sensitive data in application logs.
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### tornado/httputil.py
#!/usr/bin/env python
#
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

"""HTTP utility code shared by clients and servers.

This module also defines the `HTTPServerRequest` class which is exposed
via `tornado.web.RequestHandler.request`.
"""

from __future__ import absolute_import, division, print_function

import calendar
import collections
import copy
import datetime
import email.utils
import numbers
import re
import time

from tornado.escape import native_str, parse_qs_bytes, utf8
from tornado.log import gen_log
from tornado.util import ObjectDict, PY3

if PY3:
    import http.cookies as Cookie
    from http.client import responses
    from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl
else:
    import Cookie
    from httplib import responses
    from urllib import urlencode
    from urlparse import urlparse, urlunparse, parse_qsl


# responses is unused in this file, but we re-export it to other files.
# Reference it so pyflakes doesn't complain.
responses

try:
    from ssl import SSLError
except ImportError:
    # ssl is unavailable on app engine.
    class _SSLError(Exception):
        pass
    # Hack around a mypy limitation. We can't simply put "type: ignore"
    # on the class definition itself; must go through an assignment.
    SSLError = _SSLError  # type: ignore

try:
    import typing
except ImportError:
    pass


# RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line
# terminator and ignore any preceding CR.
_CRLF_RE = re.compile(r'\r?\n')


class _NormalizedHeaderCache(dict):
    """Dynamic cached mapping of header names to Http-Header-Case.

    Implemented as a dict subclass so that cache hits are as fast as a
    normal dict lookup, without the overhead of a python function
    call.

    >>> normalized_headers = _NormalizedHeaderCache(10)
    >>> normalized_headers["coNtent-TYPE"]
    'Content-Type'
    """
    def __init__(self, size):
        super(_NormalizedHeaderCache, self).__init__()
        self.size = size
        self.queue = collections.deque()

    def __missing__(self, key):
        normalized = "-".join([w.capitalize() for w in key.split("-")])
        self[key] = normalized
        self.queue.append(key)
        if len(self.queue) > self.size:
            # Limit the size of the cache.  LRU would be better, but this
            # simpler approach should be fine.  In Python 2.7+ we could
            # use OrderedDict (or in 3.2+, @functools.lru_cache).
            old_key = self.queue.popleft()
            del self[old_key]
        return normalized


_normalized_headers = _NormalizedHeaderCache(1000)


class HTTPHeaders(collections.MutableMapping):
    """A dictionary that maintains ``Http-Header-Case`` for all keys.

    Supports multiple values per key via a pair of new methods,
    `add()` and `get_list()`.  The regular dictionary interface
    returns a single value per key, with multiple values joined by a
    comma.

    >>> h = HTTPHeaders({"content-type": "text/html"})
    >>> list(h.keys())
    ['Content-Type']
    >>> h["Content-Type"]
    'text/html'

    >>> h.add("Set-Cookie", "A=B")
    >>> h.add("Set-Cookie", "C=D")
    >>> h["set-cookie"]
    'A=B,C=D'
    >>> h.get_list("set-cookie")
    ['A=B', 'C=D']

    >>> for (k,v) in sorted(h.get_all()):
    ...    print('%s: %s' % (k,v))
    ...
    Content-Type: text/html
    Set-Cookie: A=B
    Set-Cookie: C=D
    """
    def __init__(self, *args, **kwargs):
        self._dict = {}  # type: typing.Dict[str, str]
        self._as_list = {}  # type: typing.Dict[str, typing.List[str]]
        self._last_key = None
        if (len(args) == 1 and len(kwargs) == 0 and
                isinstance(args[0], HTTPHeaders)):
            # Copy constructor
            for k, v in args[0].get_all():
                self.add(k, v)
        else:
            # Dict-style initialization
            self.update(*args, **kwargs)

    # new public methods

    def add(self, name, value):
        # type: (str, str) -> None
        """Adds a new value for the given key."""
        norm_name = _normalized_headers[name]
        self._last_key = norm_name
        if norm_name in self:
            self._dict[norm_name] = (native_str(self[norm_name]) + ',' +
                                     native_str(value))
            self._as_list[norm_name].append(value)
        else:
            self[norm_name] = value

    def get_list(self, name):
        """Returns all values for the given header as a list."""
        norm_name = _normalized_headers[name]
        return self._as_list.get(norm_name, [])

    def get_all(self):
        # type: () -> typing.Iterable[typing.Tuple[str, str]]
        """Returns an iterable of all (name, value) pairs.

        If a header has multiple values, multiple pairs will be
        returned with the same name.
        """
        for name, values in self._as_list.items():
            for value in values:
                yield (name, value)

    def parse_line(self, line):
        """Updates the dictionary with a single header line.

        >>> h = HTTPHeaders()
        >>> h.parse_line("Content-Type: text/html")
        >>> h.get('content-type')
        'text/html'
        """
        if line[0].isspace():
            # continuation of a multi-line header
            new_part = ' ' + line.lstrip()
            self._as_list[self._last_key][-1] += new_part
            self._dict[self._last_key] += new_part
        else:
            name, value = line.split(":", 1)
            self.add(name, value.strip())

    @classmethod
    def parse(cls, headers):
        """Returns a dictionary from HTTP header text.

        >>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n")
        >>> sorted(h.items())
        [('Content-Length', '42'), ('Content-Type', 'text/html')]
        """
        h = cls()
        for line in _CRLF_RE.split(headers):
            if line:
                h.parse_line(line)
        return h

    # MutableMapping abstract method implementations.

    def __setitem__(self, name, value):
        norm_name = _normalized_headers[name]
        self._dict[norm_name] = value
        self._as_list[norm_name] = [value]

    def __getitem__(self, name):
        # type: (str) -> str
        return self._dict[_normalized_headers[name]]

    def __delitem__(self, name):
        norm_name = _normalized_headers[name]
        del self._dict[norm_name]
        del self._as_list[norm_name]

    def __len__(self):
        return len(self._dict)

    def __iter__(self):
        return iter(self._dict)

    def copy(self):
        # defined in dict but not in MutableMapping.
        return HTTPHeaders(self)

    # Use our overridden copy method for the copy.copy module.
    # This makes shallow copies one level deeper, but preserves
    # the appearance that HTTPHeaders is a single container.
    __copy__ = copy

    def __str__(self):
        lines = []
        for name, value in self.get_all():
            lines.append("%s: %s\n" % (name, value))
        return "".join(lines)

    __unicode__ = __str__


class HTTPServerRequest(object):
    """A single HTTP request.

    All attributes are type `str` unless otherwise noted.

    .. attribute:: method

       HTTP request method, e.g. "GET" or "POST"

    .. attribute:: uri

       The requested uri.

    .. attribute:: path

       The path portion of `uri`

    .. attribute:: query

       The query portion of `uri`

    .. attribute:: version

       HTTP version specified in request, e.g. "HTTP/1.1"

    .. attribute:: headers

       `.HTTPHeaders` dictionary-like object for request headers.  Acts like
       a case-insensitive dictionary with additional methods for repeated
       headers.

    .. attribute:: body

       Request body, if present, as a byte string.

    .. attribute:: remote_ip

       Client's IP address as a string.  If ``HTTPServer.xheaders`` is set,
       will pass along the real IP address provided by a load balancer
       in the ``X-Real-Ip`` or ``X-Forwarded-For`` header.

    .. versionchanged:: 3.1
       The list format of ``X-Forwarded-For`` is now supported.

    .. attribute:: protocol

       The protocol used, either "http" or "https".  If ``HTTPServer.xheaders``
       is set, will pass along the protocol used by a load balancer if
       reported via an ``X-Scheme`` header.

    .. attribute:: host

       The requested hostname, usually taken from the ``Host`` header.

    .. attribute:: arguments

       GET/POST arguments are available in the arguments property, which
       maps arguments names to lists of values (to support multiple values
       for individual names). Names are of type `str`, while arguments
       are byte strings.  Note that this is different from
       `.RequestHandler.get_argument`, which returns argument values as
       unicode strings.

    .. attribute:: query_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the query string.

       .. versionadded:: 3.2

    .. attribute:: body_arguments

       Same format as ``arguments``, but contains only arguments extracted
       from the request body.

       .. versionadded:: 3.2

    .. attribute:: files

       File uploads are available in the files property, which maps file
       names to lists of `.HTTPFile`.

    .. attribute:: connection

       An HTTP request is attached to a single HTTP connection, which can
       be accessed through the "connection" attribute. Since connections
       are typically kept open in HTTP/1.1, multiple requests can be handled
       sequentially on a single connection.

    .. versionchanged:: 4.0
       Moved from ``tornado.httpserver.HTTPRequest``.
    """
    def __init__(self, method=None, uri=None, version="HTTP/1.0", headers=None,
                 body=None, host=None, files=None, connection=None,
                 start_line=None, server_connection=None):
        if start_line is not None:
            method, uri, version = start_line
        self.method = method
        self.uri = uri
        self.version = version
        self.headers = headers or HTTPHeaders()
        self.body = body or b""

        # set remote IP and protocol
        context = getattr(connection, 'context', None)
        self.remote_ip = getattr(context, 'remote_ip', None)
        self.protocol = getattr(context, 'protocol', "http")

        self.host = host or self.headers.get("Host") or "127.0.0.1"
        self.host_name = split_host_and_port(self.host.lower())[0]
        self.files = files or {}
        self.connection = connection
        self.server_connection = server_connection
        self._start_time = time.time()
        self._finish_time = None

        self.path, sep, self.query = uri.partition('?')
        self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
        self.query_arguments = copy.deepcopy(self.arguments)
        self.body_arguments = {}

    def supports_http_1_1(self):
        """Returns True if this request supports HTTP/1.1 semantics.

        .. deprecated:: 4.0
           Applications are less likely to need this information with the
           introduction of `.HTTPConnection`.  If you still need it, access
           the ``version`` attribute directly.
        """
        return self.version == "HTTP/1.1"

    @property
    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self, "_cookies"):
            self._cookies = Cookie.SimpleCookie()
            if "Cookie" in self.headers:
                try:
                    parsed = parse_cookie(self.headers["Cookie"])
                except Exception:
                    pass
                else:
                    for k, v in parsed.items():
                        try:
                            self._cookies[k] = v
                        except Exception:
                            # SimpleCookie imposes some restrictions on keys;
                            # parse_cookie does not. Discard any cookies
                            # with disallowed keys.
                            pass
        return self._cookies

    def write(self, chunk, callback=None):
        """Writes the given chunk to the response stream.

        .. deprecated:: 4.0
           Use ``request.connection`` and the `.HTTPConnection` methods
           to write the response.
        """
        assert isinstance(chunk, bytes)
        assert self.version.startswith("HTTP/1."), \
            "deprecated interface only supported in HTTP/1.x"
        self.connection.write(chunk, callback=callback)

    def finish(self):
        """Finishes this HTTP request on the open connection.

        .. deprecated:: 4.0
           Use ``request.connection`` and the `.HTTPConnection` methods
           to write the response.
        """
        self.connection.finish()
        self._finish_time = time.time()

    def full_url(self):
        """Reconstructs the full URL for this request."""
        return self.protocol + "://" + self.host + self.uri

    def request_time(self):
        """Returns the amount of time it took for this request to execute."""
        if self._finish_time is None:
            return time.time() - self._start_time
        else:
            return self._finish_time - self._start_time

    def get_ssl_certificate(self, binary_form=False):
        """Returns the client's SSL certificate, if any.

        To use client certificates, the HTTPServer's
        `ssl.SSLContext.verify_mode` field must be set, e.g.::

            ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
            ssl_ctx.load_cert_chain("foo.crt", "foo.key")
            ssl_ctx.load_verify_locations("cacerts.pem")
            ssl_ctx.verify_mode = ssl.CERT_REQUIRED
            server = HTTPServer(app, ssl_options=ssl_ctx)

        By default, the return value is a dictionary (or None, if no
        client certificate is present).  If ``binary_form`` is true, a
        DER-encoded form of the certificate is returned instead.  See
        SSLSocket.getpeercert() in the standard library for more
        details.
        http://docs.python.org/library/ssl.html#sslsocket-objects
        """
        try:
            return self.connection.stream.socket.getpeercert(
                binary_form=binary_form)
        except SSLError:
            return None

    def _parse_body(self):
        parse_body_arguments(
            self.headers.get("Content-Type", ""), self.body,
            self.body_arguments, self.files,
            self.headers)

        for k, v in self.body_arguments.items():
            self.arguments.setdefault(k, []).extend(v)

    def __repr__(self):
        attrs = ("protocol", "host", "method", "uri", "version", "remote_ip")
        args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs])
        return "%s(%s, headers=%s)" % (
            self.__class__.__name__, args, dict(self.headers))


class HTTPInputError(Exception):
    """Exception class for malformed HTTP requests or responses
    from remote sources.

    .. versionadded:: 4.0
    """
    pass


class HTTPOutputError(Exception):
    """Exception class for errors in HTTP output.

    .. versionadded:: 4.0
    """
    pass


class HTTPServerConnectionDelegate(object):
    """Implement this interface to handle requests from `.HTTPServer`.

    .. versionadded:: 4.0
    """
    def start_request(self, server_conn, request_conn):
        """This method is called by the server when a new request has started.

        :arg server_conn: is an opaque object representing the long-lived
            (e.g. tcp-level) connection.
        :arg request_conn: is a `.HTTPConnection` object for a single
            request/response exchange.

        This method should return a `.HTTPMessageDelegate`.
        """
        raise NotImplementedError()

    def on_close(self, server_conn):
        """This method is called when a connection has been closed.

        :arg server_conn: is a server connection that has previously been
            passed to ``start_request``.
        """
        pass


class HTTPMessageDelegate(object):
    """Implement this interface to handle an HTTP request or response.

    .. versionadded:: 4.0
    """
    def headers_received(self, start_line, headers):
        """Called when the HTTP headers have been received and parsed.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`
            depending on whether this is a client or server message.
        :arg headers: a `.HTTPHeaders` instance.

        Some `.HTTPConnection` methods can only be called during
        ``headers_received``.

        May return a `.Future`; if it does the body will not be read
        until it is done.
        """
        pass

    def data_received(self, chunk):
        """Called when a chunk of data has been received.

        May return a `.Future` for flow control.
        """
        pass

    def finish(self):
        """Called after the last chunk of data has been received."""
        pass

    def on_connection_close(self):
        """Called if the connection is closed without finishing the request.

        If ``headers_received`` is called, either ``finish`` or
        ``on_connection_close`` will be called, but not both.
        """
        pass


class HTTPConnection(object):
    """Applications use this interface to write their responses.

    .. versionadded:: 4.0
    """
    def write_headers(self, start_line, headers, chunk=None, callback=None):
        """Write an HTTP header block.

        :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`.
        :arg headers: a `.HTTPHeaders` instance.
        :arg chunk: the first (optional) chunk of data.  This is an optimization
            so that small responses can be written in the same call as their
            headers.
        :arg callback: a callback to be run when the write is complete.

        The ``version`` field of ``start_line`` is ignored.

        Returns a `.Future` if no callback is given.
        """
        raise NotImplementedError()

    def write(self, chunk, callback=None):
        """Writes a chunk of body data.

        The callback will be run when the write is complete.  If no callback
        is given, returns a Future.
        """
        raise NotImplementedError()

    def finish(self):
        """Indicates that the last body data has been written.
        """
        raise NotImplementedError()


def url_concat(url, args):
    """Concatenate url and arguments regardless of whether
    url has existing query parameters.

    ``args`` may be either a dictionary or a list of key-value pairs
    (the latter allows for multiple values with the same key.

    >>> url_concat("http://example.com/foo", dict(c="d"))
    'http://example.com/foo?c=d'
    >>> url_concat("http://example.com/foo?a=b", dict(c="d"))
    'http://example.com/foo?a=b&c=d'
    >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")])
    'http://example.com/foo?a=b&c=d&c=d2'
    """
    if args is None:
        return url
    parsed_url = urlparse(url)
    if isinstance(args, dict):
        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)
        parsed_query.extend(args.items())
    elif isinstance(args, list) or isinstance(args, tuple):
        parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True)
        parsed_query.extend(args)
    else:
        err = "'args' parameter should be dict, list or tuple. Not {0}".format(
            type(args))
        raise TypeError(err)
    final_query = urlencode(parsed_query)
    url = urlunparse((
        parsed_url[0],
        parsed_url[1],
        parsed_url[2],
        parsed_url[3],
        final_query,
        parsed_url[5]))
    return url


class HTTPFile(ObjectDict):
    """Represents a file uploaded via a form.

    For backwards compatibility, its instance attributes are also
    accessible as dictionary keys.

    * ``filename``
    * ``body``
    * ``content_type``
    """
    pass


def _parse_request_range(range_header):
    """Parses a Range header.

    Returns either ``None`` or tuple ``(start, end)``.
    Note that while the HTTP headers use inclusive byte positions,
    this method returns indexes suitable for use in slices.

    >>> start, end = _parse_request_range("bytes=1-2")
    >>> start, end
    (1, 3)
    >>> [0, 1, 2, 3, 4][start:end]
    [1, 2]
    >>> _parse_request_range("bytes=6-")
    (6, None)
    >>> _parse_request_range("bytes=-6")
    (-6, None)
    >>> _parse_request_range("bytes=-0")
    (None, 0)
    >>> _parse_request_range("bytes=")
    (None, None)
    >>> _parse_request_range("foo=42")
    >>> _parse_request_range("bytes=1-2,6-10")

    Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed).

    See [0] for the details of the range header.

    [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges
    """
    unit, _, value = range_header.partition("=")
    unit, value = unit.strip(), value.strip()
    if unit != "bytes":
        return None
    start_b, _, end_b = value.partition("-")
    try:
        start = _int_or_none(start_b)
        end = _int_or_none(end_b)
    except ValueError:
        return None
    if end is not None:
        if start is None:
            if end != 0:
                start = -end
                end = None
        else:
            end += 1
    return (start, end)


def _get_content_range(start, end, total):
    """Returns a suitable Content-Range header:

    >>> print(_get_content_range(None, 1, 4))
    bytes 0-0/4
    >>> print(_get_content_range(1, 3, 4))
    bytes 1-2/4
    >>> print(_get_content_range(None, None, 4))
    bytes 0-3/4
    """
    start = start or 0
    end = (end or total) - 1
    return "bytes %s-%s/%s" % (start, end, total)


def _int_or_none(val):
    val = val.strip()
    if val == "":
        return None
    return int(val)


def parse_body_arguments(content_type, body, arguments, files, headers=None):
    """Parses a form request body.

    Supports ``application/x-www-form-urlencoded`` and
    ``multipart/form-data``.  The ``content_type`` parameter should be
    a string and ``body`` should be a byte string.  The ``arguments``
    and ``files`` parameters are dictionaries that will be updated
    with the parsed contents.
    """
    if headers and 'Content-Encoding' in headers:
        gen_log.warning("Unsupported Content-Encoding: %s",
                        headers['Content-Encoding'])
        return
    if content_type.startswith("application/x-www-form-urlencoded"):
        try:
            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)
        except Exception as e:
            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)
            uri_arguments = {}
        for name, values in uri_arguments.items():
            if values:
                arguments.setdefault(name, []).extend(values)
    elif content_type.startswith("multipart/form-data"):
        try:
            fields = content_type.split(";")
            for field in fields:
                k, sep, v = field.strip().partition("=")
                if k == "boundary" and v:
                    parse_multipart_form_data(utf8(v), body, arguments, files)
                    break
            else:
                raise ValueError("multipart boundary not found")
        except Exception as e:
            gen_log.warning("Invalid multipart/form-data: %s", e)


def parse_multipart_form_data(boundary, data, arguments, files):
    """Parses a ``multipart/form-data`` body.

    The ``boundary`` and ``data`` parameters are both byte strings.
    The dictionaries given in the arguments and files parameters
    will be updated with the contents of the body.
    """
    # The standard allows for the boundary to be quoted in the header,
    # although it's rare (it happens at least for google app engine
    # xmpp).  I think we're also supposed to handle backslash-escapes
    # here but I'll save that until we see a client that uses them
    # in the wild.
    if boundary.startswith(b'"') and boundary.endswith(b'"'):
        boundary = boundary[1:-1]
    final_boundary_index = data.rfind(b"--" + boundary + b"--")
    if final_boundary_index == -1:
        gen_log.warning("Invalid multipart/form-data: no final boundary")
        return
    parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")
    for part in parts:
        if not part:
            continue
        eoh = part.find(b"\r\n\r\n")
        if eoh == -1:
            gen_log.warning("multipart/form-data missing headers")
            continue
        headers = HTTPHeaders.parse(part[:eoh].decode("utf-8"))
        disp_header = headers.get("Content-Disposition", "")
        disposition, disp_params = _parse_header(disp_header)
        if disposition != "form-data" or not part.endswith(b"\r\n"):
            gen_log.warning("Invalid multipart/form-data")
            continue
        value = part[eoh + 4:-2]
        if not disp_params.get("name"):
            gen_log.warning("multipart/form-data value missing name")
            continue
        name = disp_params["name"]
        if disp_params.get("filename"):
            ctype = headers.get("Content-Type", "application/unknown")
            files.setdefault(name, []).append(HTTPFile(  # type: ignore
                filename=disp_params["filename"], body=value,
                content_type=ctype))
        else:
            arguments.setdefault(name, []).append(value)


def format_timestamp(ts):
    """Formats a timestamp in the format used by HTTP.

    The argument may be a numeric timestamp as returned by `time.time`,
    a time tuple as returned by `time.gmtime`, or a `datetime.datetime`
    object.

    >>> format_timestamp(1359312200)
    'Sun, 27 Jan 2013 18:43:20 GMT'
    """
    if isinstance(ts, numbers.Real):
        pass
    elif isinstance(ts, (tuple, time.struct_time)):
        ts = calendar.timegm(ts)
    elif isinstance(ts, datetime.datetime):
        ts = calendar.timegm(ts.utctimetuple())
    else:
        raise TypeError("unknown timestamp type: %r" % ts)
    return email.utils.formatdate(ts, usegmt=True)


RequestStartLine = collections.namedtuple(
    'RequestStartLine', ['method', 'path', 'version'])


def parse_request_start_line(line):
    """Returns a (method, path, version) tuple for an HTTP 1.x request line.

    The response is a `collections.namedtuple`.

    >>> parse_request_start_line("GET /foo HTTP/1.1")
    RequestStartLine(method='GET', path='/foo', version='HTTP/1.1')
    """
    try:
        method, path, version = line.split(" ")
    except ValueError:
        # https://tools.ietf.org/html/rfc7230#section-3.1.1
        # invalid request-line SHOULD respond with a 400 (Bad Request)
        raise HTTPInputError("Malformed HTTP request line")
    if not re.match(r"^HTTP/1\.[0-9]$", version):
        raise HTTPInputError(
            "Malformed HTTP version in HTTP Request-Line: %r" % version)
    return RequestStartLine(method, path, version)


ResponseStartLine = collections.namedtuple(
    'ResponseStartLine', ['version', 'code', 'reason'])


def parse_response_start_line(line):
    """Returns a (version, code, reason) tuple for an HTTP 1.x response line.

    The response is a `collections.namedtuple`.

    >>> parse_response_start_line("HTTP/1.1 200 OK")
    ResponseStartLine(version='HTTP/1.1', code=200, reason='OK')
    """
    line = native_str(line)
    match = re.match("(HTTP/1.[0-9]) ([0-9]+) ([^\r]*)", line)
    if not match:
        raise HTTPInputError("Error parsing response start line")
    return ResponseStartLine(match.group(1), int(match.group(2)),
                             match.group(3))

# _parseparam and _parse_header are copied and modified from python2.7's cgi.py
# The original 2.7 version of this code did not correctly support some
# combinations of semicolons and double quotes.
# It has also been modified to support valueless parameters as seen in
# websocket extension negotiations.


def _parseparam(s):
    while s[:1] == ';':
        s = s[1:]
        end = s.find(';')
        while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2:
            end = s.find(';', end + 1)
        if end < 0:
            end = len(s)
        f = s[:end]
        yield f.strip()
        s = s[end:]


def _parse_header(line):
    """Parse a Content-type like header.

    Return the main content-type and a dictionary of options.

    """
    parts = _parseparam(';' + line)
    key = next(parts)
    pdict = {}
    for p in parts:
        i = p.find('=')
        if i >= 0:
            name = p[:i].strip().lower()
            value = p[i + 1:].strip()
            if len(value) >= 2 and value[0] == value[-1] == '"':
                value = value[1:-1]
                value = value.replace('\\\\', '\\').replace('\\"', '"')
            pdict[name] = value
        else:
            pdict[p] = None
    return key, pdict


def _encode_header(key, pdict):
    """Inverse of _parse_header.

    >>> _encode_header('permessage-deflate',
    ...     {'client_max_window_bits': 15, 'client_no_context_takeover': None})
    'permessage-deflate; client_max_window_bits=15; client_no_context_takeover'
    """
    if not pdict:
        return key
    out = [key]
    # Sort the parameters just to make it easy to test.
    for k, v in sorted(pdict.items()):
        if v is None:
            out.append(k)
        else:
            # TODO: quote if necessary.
            out.append('%s=%s' % (k, v))
    return '; '.join(out)


def doctests():
    import doctest
    return doctest.DocTestSuite()


def split_host_and_port(netloc):
    """Returns ``(host, port)`` tuple from ``netloc``.

    Returned ``port`` will be ``None`` if not present.

    .. versionadded:: 4.1
    """
    match = re.match(r'^(.+):(\d+)$', netloc)
    if match:
        host = match.group(1)
        port = int(match.group(2))
    else:
        host = netloc
        port = None
    return (host, port)


def qs_to_qsl(qs):
    """Generator rewinding a result of ``parse_qs`` back to name-value pairs. 
    """
    for k, vs in qs.items():
        for v in vs:
            yield (k, v)


_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
_QuotePatt = re.compile(r"[\\].")
_nulljoin = ''.join


def _unquote_cookie(str):
    """Handle double quotes and escaping in cookie values.

    This method is copied verbatim from the Python 3.5 standard
    library (http.cookies._unquote) so we don't have to depend on
    non-public interfaces.
    """
    # If there aren't any doublequotes,
    # then there can't be any special characters.  See RFC 2109.
    if str is None or len(str) < 2:
        return str
    if str[0] != '"' or str[-1] != '"':
        return str

    # We have to assume that we must decode this string.
    # Down to work.

    # Remove the "s
    str = str[1:-1]

    # Check for special sequences.  Examples:
    #    \012 --> \n
    #    \"   --> "
    #
    i = 0
    n = len(str)
    res = []
    while 0 <= i < n:
        o_match = _OctalPatt.search(str, i)
        q_match = _QuotePatt.search(str, i)
        if not o_match and not q_match:              # Neither matched
            res.append(str[i:])
            break
        # else:
        j = k = -1
        if o_match:
            j = o_match.start(0)
        if q_match:
            k = q_match.start(0)
        if q_match and (not o_match or k < j):     # QuotePatt matched
            res.append(str[i:k])
            res.append(str[k + 1])
            i = k + 2
        else:                                      # OctalPatt matched
            res.append(str[i:j])
            res.append(chr(int(str[j + 1:j + 4], 8)))
            i = j + 4
    return _nulljoin(res)


def parse_cookie(cookie):
    """Parse a ``Cookie`` HTTP header into a dict of name/value pairs.

    This function attempts to mimic browser cookie parsing behavior;
    it specifically does not follow any of the cookie-related RFCs
    (because browsers don't either).

    The algorithm used is identical to that used by Django version 1.9.10.

    .. versionadded:: 4.4.2
    """
    cookiedict = {}
    for chunk in cookie.split(str(';')):
        if str('=') in chunk:
            key, val = chunk.split(str('='), 1)
        else:
            # Assume an empty name per
            # https://bugzilla.mozilla.org/show_bug.cgi?id=169091
            key, val = str(''), chunk
        key, val = key.strip(), val.strip()
        if key or val:
            # unquote using Python's algorithm.
            cookiedict[key] = _unquote_cookie(val)
    return cookiedict

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user