internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: pallets/werkzeug

Issue:
SameSite=None missing from debugger cookie
When entering the debugger pin into the debugger when running in an iframe, Chrome states that "Because a cookie's SameSite attribute was not set or is invalid, it defaults to SameSite=Lax, which prevents the cookie from being set in a cross-site context."
The debugger accepts the pin but then silently returns a 405 error when you try and interact with the console

To replicate: Run the debugger in an iframe, using Chrome with SameSite checking enabled, enter the pin then try and interact with the console

Environment:

- Python version: 3.6.9
- Werkzeug version: 1.0.1



Discussion:

Resolving patch:
diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py
--- a/src/werkzeug/debug/__init__.py
+++ b/src/werkzeug/debug/__init__.py
@@ -438,6 +438,7 @@ def pin_auth(self, request):
                 self.pin_cookie_name,
                 f"{int(time.time())}|{hash_pin(self.pin)}",
                 httponly=True,
+                samesite="None",
             )
         elif bad_cookie:
             rv.delete_cookie(self.pin_cookie_name)


Test patch:
Repository: pallets/werkzeug

Issue:
[current default branch] werkzeug always raises a warning on import
```console
$ python -Werror -c 'import werkzeug'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/tmp/werkzeug/src/werkzeug/__init__.py", line 2, in <module>
    from .test import Client
  File "/tmp/werkzeug/src/werkzeug/test.py", line 46, in <module>
    from .utils import get_content_type
  File "/tmp/werkzeug/src/werkzeug/utils.py", line 303, in <module>
    html = HTMLBuilder("html")
  File "/tmp/werkzeug/src/werkzeug/utils.py", line 234, in __init__
    warnings.warn(
DeprecationWarning: 'utils.HTMLBuilder' is deprecated and will be removed in 2.1.
```

Environment:

- Python version:
  ```console
  $ python --version --version
  Python 3.8.2 (default, Jul 16 2020, 14:00:26) 
  [GCC 9.3.0]
  ```

- Werkzeug version: d7eebd2054842334804e74ec7ad465bc78d7b2e6

This appears to be caused by #1772



Discussion:
I'm not sure what's going on here. If you run `pytest` or `tox -e py38` locally, they both succeed, but it's failing in CI here and in Flask.
I think what you're saying is that regardless of the weird test failure, it shouldn't be raising a warning on import. That seems reasonable, I'll remove the warning from `HTMLBuilder.__init__` and leave the warning on its other methods.

Resolving patch:
diff --git a/src/werkzeug/utils.py b/src/werkzeug/utils.py
--- a/src/werkzeug/utils.py
+++ b/src/werkzeug/utils.py
@@ -231,11 +231,6 @@ class HTMLBuilder:
     _c_like_cdata = {"script", "style"}
 
     def __init__(self, dialect):
-        warnings.warn(
-            "'utils.HTMLBuilder' is deprecated and will be removed in 2.1.",
-            DeprecationWarning,
-            stacklevel=2,
-        )
         self._dialect = dialect
 
     def __call__(self, s):


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -22,7 +22,7 @@ jobs:
           - {name: 'PyPy', python: pypy3, os: ubuntu-latest, tox: pypy3}
           - {name: Style, python: '3.8', os: ubuntu-latest, tox: style}
           - {name: Docs, python: '3.8', os: ubuntu-latest, tox: docs}
-          - {name: Typing, python: '3.8', os: ubuntu-latest, tox: mypy}
+          - {name: Typing, python: '3.8', os: ubuntu-latest, tox: typing}
           - {name: Windows, python: '3.8', os: windows-latest, tox: py38}
           - {name: Mac, python: '3.8', os: macos-latest, tox: py38}
     steps:
Repository: pallets/werkzeug

Issue:
werkzeug.datastructures.Headers interface is not dict-like
Documentation says (https://werkzeug.palletsprojects.com/en/master/datastructures/#werkzeug.datastructures.Headers):
> An object that stores some headers. It has a dict-like interface but is ordered and can store the same keys multiple times.

but that assertion is misleading, since looking at the code

https://github.com/pallets/werkzeug/blob/d05ee59d18b895bf204431a501bf6621f3077d5c/src/werkzeug/datastructures.py#L1165-L1167

`Headers.__iter__` returns a list of items (key-value tuples) instead of the keys, rendering it not dict-like.

As this is a quirk already causing trouble to people but fixing it would be API breaking, at least this quirk should be noted on the documentation (and maybe replacing dict-like mentions with the more generic mapping interface).


Discussion:
Please submit your suggested PR.

Resolving patch:
diff --git a/src/werkzeug/datastructures.py b/src/werkzeug/datastructures.py
--- a/src/werkzeug/datastructures.py
+++ b/src/werkzeug/datastructures.py
@@ -908,8 +908,9 @@ def _unicodify_header_value(value: UnicodeEncodable) -> str:
 
 
 class Headers:
-    """An object that stores some headers.  It has a dict-like interface
-    but is ordered and can store the same keys multiple times.
+    """An object that stores some headers. It has a dict-like interface,
+    but is ordered, can store the same key multiple times, and iterating
+    yields ``(key, value)`` pairs instead of only keys.
 
     This data structure is useful if you want a nicer way to handle WSGI
     headers which are stored as tuples in a list.


Test patch:
Repository: pallets/werkzeug

Issue:
Werkzeug useragent parsing is off for Motorola One Macro Android phone
I noticed this in a flask app but that uses werkzeug to parse useragent info and saw the same behavior in both the flask request object and standalone werkzeug useragent parser.

It looks like the presence of the substring "mac" in "macro" (the device model) is throwing it off. However, I feel like that should be overridden by the clear "Linux" and/or "Android 9".

```
>>> from werkzeug.useragents import UserAgent
>>> UserAgent("Mozilla/5.0 (Linux; Android 9; motorola one macro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.111 Mobile Safari/537.36").platform
'macos'
```

I would expect the `platform` for this useragent string to be "android".

Environment: Linux

- Python version: 3.7.3
- Werkzeug version: 1.01



Discussion:
The issue is that `UserAgentParser` finds the platform by naively searching for keywords.

Here's the relevant code snippet:
```python
    platforms: Any = (
        (" cros ", "chromeos"),
        ("iphone|ios", "iphone"),
        ("ipad", "ipad"),
        (r"darwin|mac|os\s*x", "macos"),
        ("win", "windows"),
        (r"android", "android"),
        ...
```
In your case, `"darwin|mac|os\s*x"` finds a match before `"android"` is searched. From what I've seen of user agent headers, they can vary wildly. Perhaps someone who has more experience can suggest better regex patterns. I'm concerned that our simple keyword search is inadequate and that there could be more unnoticed bugs like yours.

Resolving patch:
diff --git a/src/werkzeug/useragents.py b/src/werkzeug/useragents.py
--- a/src/werkzeug/useragents.py
+++ b/src/werkzeug/useragents.py
@@ -12,7 +12,7 @@ class UserAgentParser:
         (" cros ", "chromeos"),
         ("iphone|ios", "iphone"),
         ("ipad", "ipad"),
-        (r"darwin|mac|os\s*x", "macos"),
+        (r"darwin\b|mac\b|os\s*x", "macos"),
         ("win", "windows"),
         (r"android", "android"),
         ("netbsd", "netbsd"),
@@ -20,7 +20,7 @@ class UserAgentParser:
         ("freebsd", "freebsd"),
         ("dragonfly", "dragonflybsd"),
         ("(sun|i86)os", "solaris"),
-        (r"x11|lin(\b|ux)?", "linux"),
+        (r"x11\b|lin(\b|ux)?", "linux"),
         (r"nintendo\s+wii", "wii"),
         ("irix", "irix"),
         ("hp-?ux", "hpux"),


Test patch:
diff --git a/tests/test_useragents.py b/tests/test_useragents.py
--- a/tests/test_useragents.py
+++ b/tests/test_useragents.py
@@ -36,6 +36,13 @@
             "84.0.499.0",
             None,
         ),
+        (
+            "Mozilla/5.0 (Linux; Android 9; motorola one macro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.111 Mobile Safari/537.36",  # noqa B950
+            "android",
+            "chrome",
+            "84.0.4147.111",
+            None,
+        ),
     ),
 )
 def test_edge_browsers(user_agent, platform, browser, version, language):
Repository: pallets/werkzeug

Issue:
FileStorage.mode attribute should be rb+
When receiving files, `werkzeug.datastructures.FileStorage` is used. The underlying stream is determined by the default stream factory.

I assume that for most people (if not all?), [`tempfile.SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) will exists, so [the following line of code](https://github.com/pallets/werkzeug/blob/8fe59c949ad67e12af93cab9c2faec27beefb1e4/src/werkzeug/formparser.py#L69) will be executed.

Setting the mode to `wb+`, thus using an `io.BytesIO` instance underneath.

When accessing the mode attribute from `werkzeug.datastructures.FileStorage`, the one from `tempfile.SpooledTemporaryFile` will be used, and as there is no mode for `io.BytesIO`, the one set in the constructor will be used, resulting in a write-only mode being returned.

To my knowledge, FileStorage is only returned to read files, so **the mode exposed to clients should be read-only**.

You can reproduce the bug by checking filestorage.mode while executing [this test case](https://github.com/pallets/werkzeug/blob/8fe59c949ad67e12af93cab9c2faec27beefb1e4/tests/test_formparser.py#L162).

The impact I see is that [pandas seems to rely on mode to determine if a file is readable or not](https://github.com/pandas-dev/pandas/issues/31819#issuecomment-722320769). Changing it to "rb+" instead of "wb+" in the stream factory solves the issue (and avoid sending misleading information to client).

Environment:

- Python version: 3.8.6 (Windows 10, 64 bits python)
- Werkzeug version: 1.0.1



Discussion:
I guess the distinction that `w+` means truncate and `r+` means don't isn't relevant when opening these tempfiles, so changing it seems fine.

That said, if Pandas isn't recognizing `+` as meaning the file is open for reading (and writing), then that's a bug in Pandas. You should report that to them.
It looks like you never reported this issue to Pandas. You need to report it to them as well, they should be recognizing that `wb+` allows reading.

Resolving patch:
diff --git a/src/werkzeug/formparser.py b/src/werkzeug/formparser.py
--- a/src/werkzeug/formparser.py
+++ b/src/werkzeug/formparser.py
@@ -51,9 +51,9 @@ def default_stream_factory(
     max_size = 1024 * 500
 
     if SpooledTemporaryFile is not None:
-        return t.cast(t.BinaryIO, SpooledTemporaryFile(max_size=max_size, mode="wb+"))
+        return t.cast(t.BinaryIO, SpooledTemporaryFile(max_size=max_size, mode="rb+"))
     elif total_content_length is None or total_content_length > max_size:
-        return t.cast(t.BinaryIO, TemporaryFile("wb+"))
+        return t.cast(t.BinaryIO, TemporaryFile("rb+"))
 
     return BytesIO()
 


Test patch:
Repository: pallets/werkzeug

Issue:
Update docs: werkzeug escape utility also translates single quotes
This is a bit nitpicky. The escape utility now uses python's built-in html library for escaping. This will also escape single quotes (') in addition to double quotes ("). It would be helpful if someone could update the docs as escaping single quotes can have implications for XSS vulnerabilities in html.

Environment:

- Python version: >=3.5
- Werkzeug version: latest



Discussion:

Resolving patch:
diff --git a/src/werkzeug/utils.py b/src/werkzeug/utils.py
--- a/src/werkzeug/utils.py
+++ b/src/werkzeug/utils.py
@@ -446,7 +446,8 @@ def secure_filename(filename: str) -> str:
 
 
 def escape(s):
-    """Replace ``&``, ``<``, ``>``, and ``"`` with HTML-safe sequences.
+    """Replace ``&``, ``<``, ``>``, ``"``, and ``'`` with HTML-safe
+    sequences.
 
     ``None`` is escaped to an empty string.
 


Test patch:
Repository: pallets/werkzeug

Issue:
Debugger's library detection doesn't work with symlinks
The debugger's stacktrace nicely colors lines differently if they come from your own code vs library code.  However, this doesn't work correctly if the library path (virtualenv) is a symlink.

I am not 100% sure how to replicate this simply because my environment is part of a fairly complex build system.  But `sysconfig.get_paths()` returns paths like `/var/local/venv/...` and that is a symlink to `/other/path/venv/`

Environment:

- Python version: 3.7
- Werkzeug version: 1.0.1



Discussion:

Resolving patch:
diff --git a/src/werkzeug/debug/tbtools.py b/src/werkzeug/debug/tbtools.py
--- a/src/werkzeug/debug/tbtools.py
+++ b/src/werkzeug/debug/tbtools.py
@@ -461,7 +461,8 @@ def render(self, mark_lib: bool = True) -> str:
     @cached_property
     def is_library(self) -> bool:
         return any(
-            self.filename.startswith(path) for path in sysconfig.get_paths().values()
+            self.filename.startswith(os.path.realpath(path))
+            for path in sysconfig.get_paths().values()
         )
 
     def render_text(self) -> str:


Test patch:
Repository: pallets/werkzeug

Issue:
threading.Thread.setDaemon has been deprecated in favor of setting daemon attribute directly in Python 3.10
Describe how to replicate the bug.

I am not sure if this part is covered by tests since the deprecation warning is not emitted unless I set `WERKZEUG_RUN_MAIN=true` in environment before running tests/test_serving.py but that causes test failures.

```
rg -t py -w 'currentThread|notifyAll|activeCount|isDaemon|setDaemon'
src/werkzeug/_reloader.py
420:            t.setDaemon(True)

examples/cupoftee/application.py
87:        self.updater.setDaemon(True)
```

```
------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------
/root/checked_repos_clone/werkzeug/.pytest_cache/d/.xprocess/dev_server-test_reloader_sys_path[watchdog]$ /root/py310-dev-venv/bin/python /root/checked_repos_clone/werkzeug/tests/live_apps/run.py reloader {"reloader_type": "watchdog", "port": 49153}
process 'dev_server-test_reloader_sys_path[watchdog]' started pid=11334
/root/checked_repos_clone/werkzeug/src/werkzeug/_reloader.py:420: DeprecationWarning: setDaemon() is deprecated, set the daemon attribute instead
```

Ref : python/cpython#25174

Describe the expected behavior that should have happened but didn't.

Use daemon attribute as suggested.

Environment:

- Python version: CPython master branch
- Werkzeug version: master branch



Discussion:

Resolving patch:
diff --git a/examples/cupoftee/application.py b/examples/cupoftee/application.py
--- a/examples/cupoftee/application.py
+++ b/examples/cupoftee/application.py
@@ -84,7 +84,7 @@ def __init__(self, database, interval=120):
         self.db = Database(database)
         self.master = ServerBrowser(self)
         self.updater = Thread(None, self.update_master)
-        self.updater.setDaemon(True)
+        self.updater.daemon = True
         self.updater.start()
 
     def update_master(self):
diff --git a/src/werkzeug/_reloader.py b/src/werkzeug/_reloader.py
--- a/src/werkzeug/_reloader.py
+++ b/src/werkzeug/_reloader.py
@@ -417,7 +417,7 @@ def run_with_reloader(
         if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
             ensure_echo_on()
             t = threading.Thread(target=main_func, args=())
-            t.setDaemon(True)
+            t.daemon = True
 
             # Enter the reloader to set up initial state, then start
             # the app thread and reloader update loop.


Test patch:
Repository: pallets/werkzeug

Issue:
2.0.0rc5 cannot iterate over CombinedMultiDict keys
Today I upgraded my Flask project to 2.0 for testing purposes, and Flask-WTF broke in some situations. After a little debugging I found out that it caused by CombinedMultiDict. Since this behavior change is not mentioned in the 2.0.0 changelog, I assume this is a bug.

If I understand git log correctly, it's caused by this change: https://github.com/pallets/werkzeug/commit/3ed73015106f61ca979ae30eb9d76edee7f2055d#diff-143c70ac9c8b70912211bd835f0c9dceb28ccaf02ea065da4a0e3d643bc7686dL1503

```python
from werkzeug.datastructures import CombinedMultiDict, MultiDict
c = CombinedMultiDict([MultiDict([('foo', 'bar')])])
for k in c: print(k)
```

```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iter() returned non-iterator of type 'set'
```


Discussion:

Resolving patch:
diff --git a/src/werkzeug/datastructures.py b/src/werkzeug/datastructures.py
--- a/src/werkzeug/datastructures.py
+++ b/src/werkzeug/datastructures.py
@@ -726,7 +726,8 @@ def __delitem__(self, key):
     def keys(self):
         return (key for key, value in self.items())
 
-    __iter__ = keys
+    def __iter__(self):
+        return iter(self.keys())
 
     def values(self):
         return (value for key, value in self.items())
@@ -1476,7 +1477,8 @@ def _keys_impl(self):
     def keys(self):
         return self._keys_impl()
 
-    __iter__ = keys
+    def __iter__(self):
+        return iter(self.keys())
 
     def items(self, multi=False):
         found = set()


Test patch:
Repository: pallets/werkzeug

Issue:
Stronger typing for `request.headers.get` method
Since v2 and the typing stubs, the `get` method of the `Headers` data structure always returns a `Optional[str]`. However in some cases we can know statically that it will return a `str`. Indeed when a default string parameter is given, then the function always return a `str`.

Here's a preview of my code before v2:

```py
auth_token = flask.request.headers.get('Authorization', '').replace('Bearer ', '')
```
Now that `werkzeug` is typed, the `.replace` will raise an typing error when analyzed with `mypy`.

```
error: Item "None" of "Optional[str]" has no attribute "replace"
```

I can fix it like this:
```py
auth_token = typing.cast(str, flask.request.headers.get('Authorization', '')).replace('Bearer ', '')
```
or even like this
```py
auth_header = flask.request.headers.get('Authorization', '')
if auth_header:
  auth_token = auth_header.replace('Bearer ', '')
else:
  auth_token = ''
```

But I feel like all of those patches shouldn't be required. I'll send a type fix.


Discussion:
I guess we need an `@overload` definition for `get` and similar methods... like here: https://github.com/python/typeshed/blob/a7302dc6cb9527ba8cb014327e29c035d991550f/stdlib/typing.pyi#L443-L446

Resolving patch:
diff --git a/src/werkzeug/sansio/request.py b/src/werkzeug/sansio/request.py
--- a/src/werkzeug/sansio/request.py
+++ b/src/werkzeug/sansio/request.py
@@ -491,7 +491,7 @@ def user_agent(self) -> UserAgent:
             Werkzeug 2.1. A ``UserAgent`` subclass must be set to parse
             data from the string.
         """
-        return self.user_agent_class(t.cast(str, self.headers.get("User-Agent", "")))
+        return self.user_agent_class(self.headers.get("User-Agent", ""))
 
     # Authorization
 


Test patch:
Repository: pallets/werkzeug

Issue:
WebSocket requests from Firefox fail with a 400 error
Firefox issues their WebSocket requests with the following connection header:

    Connection: keep-alive, Upgrade

While Chrome and other browsers do:

    Connection: Upgrade

The WebSocket routing logic needs to be made more robust to accept the general format of the Connection header. I will work on this fix and submit a PR in the next few days.

Environment:

- Python version: Any
- Werkzeug version: 2.0.0



Discussion:

Resolving patch:
diff --git a/src/werkzeug/routing.py b/src/werkzeug/routing.py
--- a/src/werkzeug/routing.py
+++ b/src/werkzeug/routing.py
@@ -1650,11 +1650,12 @@ def bind_to_environ(
         environ = _get_environ(environ)
         wsgi_server_name = get_host(environ).lower()
         scheme = environ["wsgi.url_scheme"]
+        upgrade = any(
+            v.strip() == "upgrade"
+            for v in environ.get("HTTP_CONNECTION", "").lower().split(",")
+        )
 
-        if (
-            environ.get("HTTP_CONNECTION", "").lower() == "upgrade"
-            and environ.get("HTTP_UPGRADE", "").lower() == "websocket"
-        ):
+        if upgrade and environ.get("HTTP_UPGRADE", "").lower() == "websocket":
             scheme = "wss" if scheme == "https" else "ws"
 
         if server_name is None:


Test patch:
diff --git a/tests/test_routing.py b/tests/test_routing.py
--- a/tests/test_routing.py
+++ b/tests/test_routing.py
@@ -73,6 +73,17 @@ def test_basic_routing():
     with pytest.raises(r.WebsocketMismatch):
         adapter.match("/ws", websocket=False)
 
+    adapter = map.bind_to_environ(
+        create_environ(
+            "/ws?foo=bar",
+            "http://example.org/",
+            headers=[("Connection", "keep-alive, Upgrade"), ("upgrade", "websocket")],
+        )
+    )
+    assert adapter.match("/ws") == ("ws", {})
+    with pytest.raises(r.WebsocketMismatch):
+        adapter.match("/ws", websocket=False)
+
 
 def test_merge_slashes_match():
     url_map = r.Map(
Repository: pallets/werkzeug

Issue:
`generate_adhoc_ssl_pair()` uses hardcoded subject alternative name of `*`
Steps to reproduce:
 * Use a development server created with `werkzeug.service.generate_adhoc_ssl_pair(cn="localhost")` (I'm using pytest-httpserver)
 * Connect with Python built-in methods (making sure to provide the adhoc certificate as a CA file)

Actual results:
 * A hardcoded SAN of `*` is added to the certificate, leading to `ssl.SSLCertVerificationError: ("sole wildcard without additional labels are not support: '*'.",)`

Expected results:
 * The cn value should also be the single DNS name in the SAN

Environment:

- Python version: Python 3.8.5
- Werkzeug version: 2.0.1



Discussion:

Resolving patch:
diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py
--- a/src/werkzeug/serving.py
+++ b/src/werkzeug/serving.py
@@ -495,7 +495,7 @@ def generate_adhoc_ssl_pair(
         .not_valid_before(dt.now(timezone.utc))
         .not_valid_after(dt.now(timezone.utc) + timedelta(days=365))
         .add_extension(x509.ExtendedKeyUsage([x509.OID_SERVER_AUTH]), critical=False)
-        .add_extension(x509.SubjectAlternativeName([x509.DNSName("*")]), critical=False)
+        .add_extension(x509.SubjectAlternativeName([x509.DNSName(cn)]), critical=False)
         .sign(pkey, hashes.SHA256(), backend)
     )
     return cert, pkey


Test patch: