Skip to content

Commit 60fc7af

Browse files
author
Mattias Loverot
committed
Prohibiting null character in String field
1 parent 4ee6510 commit 60fc7af

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

src/marshmallow/fields.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,14 @@ class String(Field):
831831
"invalid_utf8": "Not a valid utf-8 string.",
832832
}
833833

834+
def __init__(self, *args, **kwargs):
835+
super().__init__(*args, **kwargs)
836+
# Insert validation into self.validators so that multiple errors can be stored.
837+
validator = validate.ProhibitNullCharactersValidator(
838+
error=self.error_messages["invalid"]
839+
)
840+
self.validators.insert(0, validator)
841+
834842
def _serialize(self, value, attr, obj, **kwargs) -> typing.Optional[str]:
835843
if value is None:
836844
return None

src/marshmallow/validate.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,32 @@ def __call__(self, value) -> typing.Any:
185185
return value
186186

187187

188+
class ProhibitNullCharactersValidator(Validator):
189+
"""Validate string not having Null Character
190+
191+
:param error: Error message to raise in case of a validation error. Can be
192+
interpolated with `{input}`.
193+
"""
194+
195+
NULL_REGEX = re.compile(
196+
r"\0",
197+
)
198+
199+
def __init__(self, *, error: typing.Optional[str] = None):
200+
self.error = error or self.default_message # type: str
201+
202+
def _format_error(self, value) -> typing.Any:
203+
return self.error.format(input=value)
204+
205+
def __call__(self, value) -> typing.Any:
206+
message = self._format_error(value)
207+
208+
if value and self.NULL_REGEX.search(str(value)):
209+
raise ValidationError(message)
210+
211+
return value
212+
213+
188214
class Range(Validator):
189215
"""Validator which succeeds if the value passed to it is within the specified
190216
range. If ``min`` is not specified, or is specified as `None`,

tests/test_fields.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ class MySchema(Schema):
9292
result = MySchema().dump({"name": "Monty", "foo": 42})
9393
assert result == {"_NaMe": "Monty"}
9494

95+
def test_string_field_null_char(self):
96+
class MySchema(Schema):
97+
name = fields.String()
98+
99+
with pytest.raises(ValidationError):
100+
MySchema().load({"name": "a\0b"})
101+
95102

96103
class TestParentAndName:
97104
class MySchema(Schema):

0 commit comments

Comments
 (0)