mirror of
https://github.com/openembedded/meta-openembedded.git
synced 2026-11-07 13:44:50 +00:00
This patch applies the upstream stable-branch fix in [1], which backports the original upstream commit in [2]. The advisory identifying the fix is referenced in [3]. [1] https://github.com/aio-libs/aiohttp/commit/53b35a2f8869c37a133e60bf1a82a1c01642ba2b [2] https://github.com/aio-libs/aiohttp/commit/18510482de080bf741c560bf2a190fdc54b4eed4 [3] https://nvd.nist.gov/vuln/detail/CVE-2026-34519 Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com> Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
639 lines
28 KiB
Diff
639 lines
28 KiB
Diff
From 0eb0a867fe5a9071b885c60ada894dc11da5f858 Mon Sep 17 00:00:00 2001
|
|
From: Sam Bull <git@sambull.org>
|
|
Date: Sat, 7 Mar 2026 19:00:02 +0000
|
|
Subject: [PATCH] Restrict reason (#12209) (#12212)
|
|
|
|
CVE: CVE-2026-34519
|
|
Upstream-Status: Backport [https://github.com/aio-libs/aiohttp/commit/53b35a2f8869c37a133e60bf1a82a1c01642ba2b]
|
|
|
|
Backport Changes:
|
|
- Replaced the upstream _write_str_raise_on_nlcr() call with the
|
|
existing _safe_header(status_line) implementation because
|
|
aiohttp 3.9.5 does not provide _write_str_raise_on_nlcr().
|
|
- Added CR/LF validation in web_response.py because aiohttp 3.9.5
|
|
lacks the upstream LF-only reason check, while retaining its existing
|
|
HTTPStatus phrase lookup and set_status implementation.
|
|
- Adapted the upstream regression tests to the aiohttp 3.9.5 imports
|
|
and test signatures, and added coverage for status-line
|
|
serialization.
|
|
- Regenerated _http_writer.c with Cython 3.0.5 because the accelerated
|
|
build uses the checked-in generated source.
|
|
|
|
(cherry picked from commit 18510482de080bf741c560bf2a190fdc54b4eed4)
|
|
|
|
---------
|
|
|
|
Co-authored-by: Dhiral Vyas <dhiral@users.noreply.github.com>
|
|
(cherry picked from commit 53b35a2f8869c37a133e60bf1a82a1c01642ba2b)
|
|
Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
|
|
---
|
|
aiohttp/_http_writer.c | 147 ++++++++++++++++++++++++++-----------------------
|
|
aiohttp/_http_writer.pyx | 1 +
|
|
aiohttp/http_writer.py | 1 +
|
|
aiohttp/web_exceptions.py | 2 ++
|
|
aiohttp/web_response.py | 2 ++
|
|
tests/test_web_exceptions.py | 15 +++++++++++++++
|
|
tests/test_web_response.py | 26 ++++++++++++++++++++++++++
|
|
7 files changed, 130 insertions(+), 70 deletions(-)
|
|
|
|
diff --git a/aiohttp/_http_writer.pyx b/aiohttp/_http_writer.pyx
|
|
index eff852195..24e5bb752 100644
|
|
--- a/aiohttp/_http_writer.pyx
|
|
+++ b/aiohttp/_http_writer.pyx
|
|
@@ -131,6 +131,7 @@ def _serialize_headers(str status_line, headers):
|
|
_safe_header(to_str(key))
|
|
_safe_header(to_str(val))
|
|
|
|
+ _safe_header(status_line)
|
|
try:
|
|
if _write_str(&writer, status_line) < 0:
|
|
raise
|
|
diff --git a/aiohttp/_http_writer.c b/aiohttp/_http_writer.c
|
|
index 74bc210ea..7eecc2940 100644
|
|
--- a/aiohttp/_http_writer.c
|
|
+++ b/aiohttp/_http_writer.c
|
|
@@ -3852,7 +3852,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
* _safe_header(to_str(key))
|
|
* _safe_header(to_str(val)) # <<<<<<<<<<<<<<
|
|
*
|
|
- * try:
|
|
+ * _safe_header(status_line)
|
|
*/
|
|
__pyx_t_6 = __pyx_f_7aiohttp_12_http_writer_to_str(__pyx_v_val); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 132, __pyx_L1_error)
|
|
__Pyx_GOTREF(__pyx_t_6);
|
|
@@ -3864,34 +3864,43 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
/* "aiohttp/_http_writer.pyx":134
|
|
* _safe_header(to_str(val))
|
|
*
|
|
+ * _safe_header(status_line) # <<<<<<<<<<<<<<
|
|
+ * try:
|
|
+ * if _write_str(&writer, status_line) < 0:
|
|
+ */
|
|
+ __pyx_f_7aiohttp_12_http_writer__safe_header(__pyx_v_status_line); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 134, __pyx_L1_error)
|
|
+
|
|
+ /* "aiohttp/_http_writer.pyx":135
|
|
+ *
|
|
+ * _safe_header(status_line)
|
|
* try: # <<<<<<<<<<<<<<
|
|
* if _write_str(&writer, status_line) < 0:
|
|
* raise
|
|
*/
|
|
/*try:*/ {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":135
|
|
- *
|
|
+ /* "aiohttp/_http_writer.pyx":136
|
|
+ * _safe_header(status_line)
|
|
* try:
|
|
* if _write_str(&writer, status_line) < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
*/
|
|
- __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), __pyx_v_status_line); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 135, __pyx_L6_error)
|
|
+ __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), __pyx_v_status_line); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 136, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_4 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":136
|
|
+ /* "aiohttp/_http_writer.pyx":137
|
|
* try:
|
|
* if _write_str(&writer, status_line) < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 136, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 137, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":135
|
|
- *
|
|
+ /* "aiohttp/_http_writer.pyx":136
|
|
+ * _safe_header(status_line)
|
|
* try:
|
|
* if _write_str(&writer, status_line) < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
@@ -3899,27 +3908,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":137
|
|
+ /* "aiohttp/_http_writer.pyx":138
|
|
* if _write_str(&writer, status_line) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
*/
|
|
- __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 137, __pyx_L6_error)
|
|
+ __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 138, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_4 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":138
|
|
+ /* "aiohttp/_http_writer.pyx":139
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 138, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 139, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":137
|
|
+ /* "aiohttp/_http_writer.pyx":138
|
|
* if _write_str(&writer, status_line) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
@@ -3928,27 +3937,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":139
|
|
+ /* "aiohttp/_http_writer.pyx":140
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
*
|
|
*/
|
|
- __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 139, __pyx_L6_error)
|
|
+ __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 140, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_4 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":140
|
|
+ /* "aiohttp/_http_writer.pyx":141
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
*
|
|
* for key, val in headers.items():
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 140, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 141, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":139
|
|
+ /* "aiohttp/_http_writer.pyx":140
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
@@ -3957,7 +3966,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":142
|
|
+ /* "aiohttp/_http_writer.pyx":143
|
|
* raise
|
|
*
|
|
* for key, val in headers.items(): # <<<<<<<<<<<<<<
|
|
@@ -3967,9 +3976,9 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
__pyx_t_3 = 0;
|
|
if (unlikely(__pyx_v_headers == Py_None)) {
|
|
PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%.30s'", "items");
|
|
- __PYX_ERR(0, 142, __pyx_L6_error)
|
|
+ __PYX_ERR(0, 143, __pyx_L6_error)
|
|
}
|
|
- __pyx_t_6 = __Pyx_dict_iterator(__pyx_v_headers, 0, __pyx_n_s_items, (&__pyx_t_2), (&__pyx_t_4)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 142, __pyx_L6_error)
|
|
+ __pyx_t_6 = __Pyx_dict_iterator(__pyx_v_headers, 0, __pyx_n_s_items, (&__pyx_t_2), (&__pyx_t_4)); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 143, __pyx_L6_error)
|
|
__Pyx_GOTREF(__pyx_t_6);
|
|
__Pyx_XDECREF(__pyx_t_1);
|
|
__pyx_t_1 = __pyx_t_6;
|
|
@@ -3977,7 +3986,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
while (1) {
|
|
__pyx_t_7 = __Pyx_dict_iter_next(__pyx_t_1, __pyx_t_2, &__pyx_t_3, &__pyx_t_6, &__pyx_t_5, NULL, __pyx_t_4);
|
|
if (unlikely(__pyx_t_7 == 0)) break;
|
|
- if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 142, __pyx_L6_error)
|
|
+ if (unlikely(__pyx_t_7 == -1)) __PYX_ERR(0, 143, __pyx_L6_error)
|
|
__Pyx_GOTREF(__pyx_t_6);
|
|
__Pyx_GOTREF(__pyx_t_5);
|
|
__Pyx_XDECREF_SET(__pyx_v_key, __pyx_t_6);
|
|
@@ -3985,30 +3994,30 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
__Pyx_XDECREF_SET(__pyx_v_val, __pyx_t_5);
|
|
__pyx_t_5 = 0;
|
|
|
|
- /* "aiohttp/_http_writer.pyx":143
|
|
+ /* "aiohttp/_http_writer.pyx":144
|
|
*
|
|
* for key, val in headers.items():
|
|
* if _write_str(&writer, to_str(key)) < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b':') < 0:
|
|
*/
|
|
- __pyx_t_5 = __pyx_f_7aiohttp_12_http_writer_to_str(__pyx_v_key); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 143, __pyx_L6_error)
|
|
+ __pyx_t_5 = __pyx_f_7aiohttp_12_http_writer_to_str(__pyx_v_key); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 144, __pyx_L6_error)
|
|
__Pyx_GOTREF(__pyx_t_5);
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), ((PyObject*)__pyx_t_5)); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 143, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), ((PyObject*)__pyx_t_5)); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 144, __pyx_L6_error)
|
|
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":144
|
|
+ /* "aiohttp/_http_writer.pyx":145
|
|
* for key, val in headers.items():
|
|
* if _write_str(&writer, to_str(key)) < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b':') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 144, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 145, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":143
|
|
+ /* "aiohttp/_http_writer.pyx":144
|
|
*
|
|
* for key, val in headers.items():
|
|
* if _write_str(&writer, to_str(key)) < 0: # <<<<<<<<<<<<<<
|
|
@@ -4017,27 +4026,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":145
|
|
+ /* "aiohttp/_http_writer.pyx":146
|
|
* if _write_str(&writer, to_str(key)) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b':') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b' ') < 0:
|
|
*/
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), ':'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 145, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), ':'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 146, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":146
|
|
+ /* "aiohttp/_http_writer.pyx":147
|
|
* raise
|
|
* if _write_byte(&writer, b':') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b' ') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 146, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 147, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":145
|
|
+ /* "aiohttp/_http_writer.pyx":146
|
|
* if _write_str(&writer, to_str(key)) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b':') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4046,27 +4055,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":147
|
|
+ /* "aiohttp/_http_writer.pyx":148
|
|
* if _write_byte(&writer, b':') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b' ') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_str(&writer, to_str(val)) < 0:
|
|
*/
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), ' '); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 147, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), ' '); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 148, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":148
|
|
+ /* "aiohttp/_http_writer.pyx":149
|
|
* raise
|
|
* if _write_byte(&writer, b' ') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_str(&writer, to_str(val)) < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 148, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 149, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":147
|
|
+ /* "aiohttp/_http_writer.pyx":148
|
|
* if _write_byte(&writer, b':') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b' ') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4075,30 +4084,30 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":149
|
|
+ /* "aiohttp/_http_writer.pyx":150
|
|
* if _write_byte(&writer, b' ') < 0:
|
|
* raise
|
|
* if _write_str(&writer, to_str(val)) < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
*/
|
|
- __pyx_t_5 = __pyx_f_7aiohttp_12_http_writer_to_str(__pyx_v_val); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 149, __pyx_L6_error)
|
|
+ __pyx_t_5 = __pyx_f_7aiohttp_12_http_writer_to_str(__pyx_v_val); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 150, __pyx_L6_error)
|
|
__Pyx_GOTREF(__pyx_t_5);
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), ((PyObject*)__pyx_t_5)); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 149, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_str((&__pyx_v_writer), ((PyObject*)__pyx_t_5)); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 150, __pyx_L6_error)
|
|
__Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":150
|
|
+ /* "aiohttp/_http_writer.pyx":151
|
|
* raise
|
|
* if _write_str(&writer, to_str(val)) < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 150, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 151, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":149
|
|
+ /* "aiohttp/_http_writer.pyx":150
|
|
* if _write_byte(&writer, b' ') < 0:
|
|
* raise
|
|
* if _write_str(&writer, to_str(val)) < 0: # <<<<<<<<<<<<<<
|
|
@@ -4107,27 +4116,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":151
|
|
+ /* "aiohttp/_http_writer.pyx":152
|
|
* if _write_str(&writer, to_str(val)) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
*/
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 151, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 152, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":152
|
|
+ /* "aiohttp/_http_writer.pyx":153
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 152, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 153, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":151
|
|
+ /* "aiohttp/_http_writer.pyx":152
|
|
* if _write_str(&writer, to_str(val)) < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4136,27 +4145,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":153
|
|
+ /* "aiohttp/_http_writer.pyx":154
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
*
|
|
*/
|
|
- __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 153, __pyx_L6_error)
|
|
+ __pyx_t_7 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_7 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 154, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_7 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":154
|
|
+ /* "aiohttp/_http_writer.pyx":155
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
*
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 154, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 155, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":153
|
|
+ /* "aiohttp/_http_writer.pyx":154
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4167,27 +4176,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
}
|
|
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
|
|
|
|
- /* "aiohttp/_http_writer.pyx":156
|
|
+ /* "aiohttp/_http_writer.pyx":157
|
|
* raise
|
|
*
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
*/
|
|
- __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 156, __pyx_L6_error)
|
|
+ __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\r'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 157, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_4 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":157
|
|
+ /* "aiohttp/_http_writer.pyx":158
|
|
*
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 157, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 158, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":156
|
|
+ /* "aiohttp/_http_writer.pyx":157
|
|
* raise
|
|
*
|
|
* if _write_byte(&writer, b'\r') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4196,27 +4205,27 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":158
|
|
+ /* "aiohttp/_http_writer.pyx":159
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
* raise
|
|
*
|
|
*/
|
|
- __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 158, __pyx_L6_error)
|
|
+ __pyx_t_4 = __pyx_f_7aiohttp_12_http_writer__write_byte((&__pyx_v_writer), '\n'); if (unlikely(__pyx_t_4 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 159, __pyx_L6_error)
|
|
__pyx_t_8 = (__pyx_t_4 < 0);
|
|
if (unlikely(__pyx_t_8)) {
|
|
|
|
- /* "aiohttp/_http_writer.pyx":159
|
|
+ /* "aiohttp/_http_writer.pyx":160
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0:
|
|
* raise # <<<<<<<<<<<<<<
|
|
*
|
|
* return PyBytes_FromStringAndSize(writer.buf, writer.pos)
|
|
*/
|
|
- __Pyx_ReraiseException(); __PYX_ERR(0, 159, __pyx_L6_error)
|
|
+ __Pyx_ReraiseException(); __PYX_ERR(0, 160, __pyx_L6_error)
|
|
|
|
- /* "aiohttp/_http_writer.pyx":158
|
|
+ /* "aiohttp/_http_writer.pyx":159
|
|
* if _write_byte(&writer, b'\r') < 0:
|
|
* raise
|
|
* if _write_byte(&writer, b'\n') < 0: # <<<<<<<<<<<<<<
|
|
@@ -4225,7 +4234,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
*/
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":161
|
|
+ /* "aiohttp/_http_writer.pyx":162
|
|
* raise
|
|
*
|
|
* return PyBytes_FromStringAndSize(writer.buf, writer.pos) # <<<<<<<<<<<<<<
|
|
@@ -4233,14 +4242,14 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
* _release_writer(&writer)
|
|
*/
|
|
__Pyx_XDECREF(__pyx_r);
|
|
- __pyx_t_1 = PyBytes_FromStringAndSize(__pyx_v_writer.buf, __pyx_v_writer.pos); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 161, __pyx_L6_error)
|
|
+ __pyx_t_1 = PyBytes_FromStringAndSize(__pyx_v_writer.buf, __pyx_v_writer.pos); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 162, __pyx_L6_error)
|
|
__Pyx_GOTREF(__pyx_t_1);
|
|
__pyx_r = __pyx_t_1;
|
|
__pyx_t_1 = 0;
|
|
goto __pyx_L5_return;
|
|
}
|
|
|
|
- /* "aiohttp/_http_writer.pyx":163
|
|
+ /* "aiohttp/_http_writer.pyx":164
|
|
* return PyBytes_FromStringAndSize(writer.buf, writer.pos)
|
|
* finally:
|
|
* _release_writer(&writer) # <<<<<<<<<<<<<<
|
|
@@ -4264,7 +4273,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
__Pyx_XGOTREF(__pyx_t_15);
|
|
__pyx_t_4 = __pyx_lineno; __pyx_t_7 = __pyx_clineno; __pyx_t_9 = __pyx_filename;
|
|
{
|
|
- __pyx_f_7aiohttp_12_http_writer__release_writer((&__pyx_v_writer)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 163, __pyx_L22_error)
|
|
+ __pyx_f_7aiohttp_12_http_writer__release_writer((&__pyx_v_writer)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L22_error)
|
|
}
|
|
if (PY_MAJOR_VERSION >= 3) {
|
|
__Pyx_XGIVEREF(__pyx_t_13);
|
|
@@ -4295,7 +4304,7 @@ static PyObject *__pyx_pf_7aiohttp_12_http_writer__serialize_headers(CYTHON_UNUS
|
|
__pyx_L5_return: {
|
|
__pyx_t_15 = __pyx_r;
|
|
__pyx_r = 0;
|
|
- __pyx_f_7aiohttp_12_http_writer__release_writer((&__pyx_v_writer)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 163, __pyx_L1_error)
|
|
+ __pyx_f_7aiohttp_12_http_writer__release_writer((&__pyx_v_writer)); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L1_error)
|
|
__pyx_r = __pyx_t_15;
|
|
__pyx_t_15 = 0;
|
|
goto __pyx_L0;
|
|
diff --git a/aiohttp/http_writer.py b/aiohttp/http_writer.py
|
|
index d6b02e6f5..37cdc06e6 100644
|
|
--- a/aiohttp/http_writer.py
|
|
+++ b/aiohttp/http_writer.py
|
|
@@ -181,6 +181,7 @@ def _safe_header(string: str) -> str:
|
|
|
|
|
|
def _py_serialize_headers(status_line: str, headers: "CIMultiDict[str]") -> bytes:
|
|
+ _safe_header(status_line)
|
|
headers_gen = (_safe_header(k) + ": " + _safe_header(v) for k, v in headers.items())
|
|
line = status_line + "\r\n" + "\r\n".join(headers_gen) + "\r\n\r\n"
|
|
return line.encode("utf-8")
|
|
diff --git a/aiohttp/web_exceptions.py b/aiohttp/web_exceptions.py
|
|
index ee2c1e72d..30792c281 100644
|
|
--- a/aiohttp/web_exceptions.py
|
|
+++ b/aiohttp/web_exceptions.py
|
|
@@ -101,6 +101,8 @@ class HTTPException(Response, Exception):
|
|
"body argument is deprecated for http web exceptions",
|
|
DeprecationWarning,
|
|
)
|
|
+ if reason is not None and ("\r" in reason or "\n" in reason):
|
|
+ raise ValueError("Reason cannot contain \\r or \\n")
|
|
Response.__init__(
|
|
self,
|
|
status=self.status_code,
|
|
diff --git a/aiohttp/web_response.py b/aiohttp/web_response.py
|
|
index 40d6f01ec..3bd9d45b5 100644
|
|
--- a/aiohttp/web_response.py
|
|
+++ b/aiohttp/web_response.py
|
|
@@ -140,6 +140,8 @@ class StreamResponse(BaseClass, HeadersMixin):
|
|
reason = HTTPStatus(self._status).phrase
|
|
except ValueError:
|
|
reason = ""
|
|
+ elif "\r" in reason or "\n" in reason:
|
|
+ raise ValueError("Reason cannot contain \\r or \\n")
|
|
self._reason = reason
|
|
|
|
@property
|
|
diff --git a/tests/test_web_exceptions.py b/tests/test_web_exceptions.py
|
|
index 69deb27a0..5a98d0f94 100644
|
|
--- a/tests/test_web_exceptions.py
|
|
+++ b/tests/test_web_exceptions.py
|
|
@@ -270,3 +270,18 @@ def test_unicode_text_body_unauthorized() -> None:
|
|
):
|
|
resp = web.HTTPUnauthorized(body="text")
|
|
assert resp.status == 401
|
|
+
|
|
+
|
|
+def test_multiline_reason() -> None:
|
|
+ with pytest.raises(ValueError, match=r"Reason cannot contain"):
|
|
+ web.HTTPOk(reason="Bad\r\nInjected-header: foo")
|
|
+
|
|
+
|
|
+def test_reason_with_cr() -> None:
|
|
+ with pytest.raises(ValueError, match=r"Reason cannot contain"):
|
|
+ web.HTTPOk(reason="OK\rSet-Cookie: evil=1")
|
|
+
|
|
+
|
|
+def test_reason_with_lf() -> None:
|
|
+ with pytest.raises(ValueError, match=r"Reason cannot contain"):
|
|
+ web.HTTPOk(reason="OK\nSet-Cookie: evil=1")
|
|
diff --git a/tests/test_web_response.py b/tests/test_web_response.py
|
|
index d1b407c09..84018bbfb 100644
|
|
--- a/tests/test_web_response.py
|
|
+++ b/tests/test_web_response.py
|
|
@@ -916,6 +916,27 @@ def test_set_status_with_reason() -> None:
|
|
assert "Everything is fine!" == resp.reason
|
|
|
|
|
|
+def test_set_status_reason_with_cr() -> None:
|
|
+ resp = StreamResponse()
|
|
+
|
|
+ with pytest.raises(ValueError, match="Reason cannot contain"):
|
|
+ resp.set_status(200, "OK\rSet-Cookie: evil=1")
|
|
+
|
|
+
|
|
+def test_set_status_reason_with_lf() -> None:
|
|
+ resp = StreamResponse()
|
|
+
|
|
+ with pytest.raises(ValueError, match="Reason cannot contain"):
|
|
+ resp.set_status(200, "OK\nSet-Cookie: evil=1")
|
|
+
|
|
+
|
|
+def test_set_status_reason_with_crlf() -> None:
|
|
+ resp = StreamResponse()
|
|
+
|
|
+ with pytest.raises(ValueError, match="Reason cannot contain"):
|
|
+ resp.set_status(200, "OK\r\nSet-Cookie: evil=1")
|
|
+
|
|
+
|
|
async def test_start_force_close() -> None:
|
|
req = make_request("GET", "/")
|
|
resp = StreamResponse()
|
|
@@ -1168,6 +1189,16 @@ async def test_render_with_body(buf, writer) -> None:
|
|
)
|
|
|
|
|
|
+async def test_multiline_reason(buf, writer) -> None:
|
|
+ with pytest.raises(ValueError, match=r"Reason cannot contain \\r or \\n"):
|
|
+ Response(reason="Bad\r\nInjected-header: foo")
|
|
+
|
|
+
|
|
+def test_serialize_headers_rejects_crlf_status_line() -> None:
|
|
+ with pytest.raises(ValueError, match="Newline or carriage return"):
|
|
+ _serialize_headers("HTTP/1.1 200 OK\r\nInjected: yes", CIMultiDict())
|
|
+
|
|
+
|
|
async def test_send_set_cookie_header(buf, writer) -> None:
|
|
resp = Response()
|
|
resp.cookies["name"] = "value"
|
|
--
|
|
2.35.6
|