Repository: pallets/werkzeug

Issue:
Inconsistent handling of newlines in Headers object
Werkzeug's `Headers` object is inconsistent in its handling of newline characters.  These characters are allowed in the constructor but forbidden in the `add()` method.

**Steps to reproduce:**
```
>>> from werkzeug import Headers
>>> h1 = Headers([('X-Example', 'foo\r\n bar')])
>>> h2 = Headers()
>>> h2.add('X-Example', 'foo\r\n bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1166, in add
    self._validate_value(_value)
  File "/home/.../venv3/lib/python3.6/site-packages/werkzeug/datastructures.py", line 1173, in _validate_value
    raise ValueError('Detected newline in header value.  This is '
ValueError: Detected newline in header value.  This is a potential security problem
```

**Expected result:**
Both operations have the same result, whether a `ValueError` or success.

**Actual result:**
`Headers` constructor allows newlines while `Headers.add()` raises `ValueError`.


Discussion:
It is possible to validate headers in the constructor as well; however the form parser has a [use case that requires them not to be validated](https://github.com/pallets/werkzeug/blob/0.16.x/tests/test_formparser.py#L484). I'm not certain if this is a required use case or if it can now be removed - hopefully someone more knowledgeable can comment.

Facing similar situation
@aeroaks the fact that you get this error isn't an issue with Werkzeug, it's an issue with your data. This issue is about showing this error consistently, not fixing anything. If you're getting this error, you need to fix the values you're trying to put into the header, or address whatever's sending the bad headers.

Resolving patch:
diff --git a/src/werkzeug/datastructures.py b/src/werkzeug/datastructures.py
--- a/src/werkzeug/datastructures.py
+++ b/src/werkzeug/datastructures.py
@@ -857,12 +857,15 @@ class Headers:
     `None` for ``headers['missing']``, whereas :class:`Headers` will raise
     a :class:`KeyError`.
 
-    To create a new :class:`Headers` object pass it a list or dict of headers
-    which are used as default values.  This does not reuse the list passed
-    to the constructor for internal usage.
+    To create a new ``Headers`` object, pass it a list, dict, or
+    other ``Headers`` object with default values. These values are
+    validated the same way values added later are.
 
     :param defaults: The list of default values for the :class:`Headers`.
 
+    .. versionchanged:: 2.1.0
+        Default values are validated the same as values added later.
+
     .. versionchanged:: 0.9
        This data structure now stores unicode values similar to how the
        multi dicts do it.  The main difference is that bytes can be set as
@@ -876,10 +879,7 @@ class Headers:
     def __init__(self, defaults=None):
         self._list = []
         if defaults is not None:
-            if isinstance(defaults, (list, Headers)):
-                self._list.extend(defaults)
-            else:
-                self.extend(defaults)
+            self.extend(defaults)
 
     def __getitem__(self, key, _get_mode=False):
         if not _get_mode:


Test patch:
diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py
--- a/tests/test_datastructures.py
+++ b/tests/test_datastructures.py
@@ -621,6 +621,9 @@ def test_basic_interface(self):
         assert "x-Foo" in headers
         assert "Content-type" in headers
 
+        with pytest.raises(ValueError):
+            headers.add("X-Example", "foo\r\n bar")
+
         headers["Content-Type"] = "foo/bar"
         assert headers["Content-Type"] == "foo/bar"
         assert len(headers.getlist("Content-Type")) == 1
@@ -637,6 +640,10 @@ def test_basic_interface(self):
         headers.add("x", "y", z='"')
         assert headers["x"] == r'y; z="\""'
 
+        # string conversion
+        headers.add("a", 1)
+        assert headers["a"] == "1"
+
     def test_defaults_and_conversion(self):
         # defaults
         headers = self.storage_class(
@@ -657,6 +664,10 @@ def test_defaults_and_conversion(self):
         assert headers.setdefault("X-Baz", "nope") == "quux"
         headers.pop("X-Baz")
 
+        # newlines are not allowed in values
+        with pytest.raises(ValueError):
+            self.storage_class([("X-Example", "foo\r\n bar")])
+
         # type conversion
         assert headers.get("x-bar", type=int) == 1
         assert headers.getlist("x-bar", type=int) == [1, 2]
@@ -677,8 +688,10 @@ def test_copying(self):
 
     def test_popping(self):
         headers = self.storage_class([("a", 1)])
-        assert headers.pop("a") == 1
-        assert headers.pop("b", 2) == 2
+        # headers object expect string values. If a non string value
+        # is passed, it tries converting it to a string
+        assert headers.pop("a") == "1"
+        assert headers.pop("b", "2") == "2"
 
         with pytest.raises(KeyError):
             headers.pop("c")