Repository: twisted/twisted

Issue:
Add support for HTTP status code 418 to twisted.web
**Describe the incorrect behavior you saw**
Creating a HTTP response with status code 418 will return the reason `Unknown Status` instead of `I'm a teapot`.

**Describe how to cause this behavior**
The issue can be observed by creating an arbitrary HTTP response with status code 418.

In my case specifically, I encountered the issue while using `Django` with `daphne`, but I suspect that it also happens with other packages that internally use `twisted.web`.

Here is an example response I encountered:

```
HTTP/1.1 418 Unknown Status
Content-Type: application/json
X-Frame-Options: DENY
Vary: Cookie, origin, Accept-Language
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Access-Control-Allow-Origin: http://localhost:3001
Access-Control-Allow-Credentials: true
Server: daphne
Allow: GET, POST, PATCH, DELETE, OPTIONS
Content-Language: de
Content-Length: 27
```

**Describe the correct behavior you'd like to see**
I'd like to see the status phrase `I'm a teapot` instead of `Unknown Status`, as in the following example:

```
HTTP/1.1 418 I'm a teapot
Content-Type: application/json
X-Frame-Options: DENY
Vary: Cookie, origin, Accept-Language
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Access-Control-Allow-Origin: http://localhost:3001
Access-Control-Allow-Credentials: true
Server: daphne
Allow: GET, POST, PATCH, DELETE, OPTIONS
Content-Language: de
Content-Length: 27
```

**Testing environment**
 - Operating System and Version: Microsoft Windows 11 Pro
 - Twisted version: 23.10.0
 - pip freeze:
```
asgiref==3.7.2
attrs==23.2.0
autobahn==23.6.2
Automat==22.10.0
cffi==1.16.0
channels==4.0.0
channels-redis==4.2.0
constantly==23.10.4
cryptography==42.0.3
daphne==4.1.0
Django==5.0.2
django-cors-headers==4.3.1
djangorestframework==3.14.0
hyperlink==21.0.0
idna==3.6
incremental==22.10.0
msgpack==1.0.7
mysqlclient==2.2.4
pillow==10.2.0
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycparser==2.21
PyJWT==2.8.0
pyOpenSSL==24.0.0
python-magic==0.4.27
python-magic-bin==0.4.14
pytz==2024.1
redis==5.0.1
service-identity==24.1.0
six==1.16.0
sqlparse==0.4.4
Twisted==23.10.0
twisted-iocpsupport==1.0.4
txaio==23.1.1
typing_extensions==4.9.0
tzdata==2024.1
zope.interface==6.2
```

**Additional context**
I am fully aware that the status code 418 is part of an April Fool's joke (see [RFC 2324 Section 2.3.2](https://datatracker.ietf.org/doc/html/rfc2324#section-2.3.2)), so this is technically not a bug. Nonetheless, many browsers and package developers have included this status code and I see no reason to stop the fun in `twisted`.


Discussion:
Thanks for the report. I would be happy to review and accept a PR for this :)

Resolving patch:
diff --git a/src/twisted/web/_responses.py b/src/twisted/web/_responses.py
--- a/src/twisted/web/_responses.py
+++ b/src/twisted/web/_responses.py
@@ -46,6 +46,7 @@
 UNSUPPORTED_MEDIA_TYPE = 415
 REQUESTED_RANGE_NOT_SATISFIABLE = 416
 EXPECTATION_FAILED = 417
+IM_A_TEAPOT = 418
 
 INTERNAL_SERVER_ERROR = 500
 NOT_IMPLEMENTED = 501
@@ -98,6 +99,7 @@
     UNSUPPORTED_MEDIA_TYPE: b"Unsupported Media Type",
     REQUESTED_RANGE_NOT_SATISFIABLE: b"Requested Range not satisfiable",
     EXPECTATION_FAILED: b"Expectation Failed",
+    IM_A_TEAPOT: b"I'm a teapot",
     # 500
     INTERNAL_SERVER_ERROR: b"Internal Server Error",
     NOT_IMPLEMENTED: b"Not Implemented",
diff --git a/src/twisted/web/http.py b/src/twisted/web/http.py
--- a/src/twisted/web/http.py
+++ b/src/twisted/web/http.py
@@ -69,6 +69,7 @@
     "UNSUPPORTED_MEDIA_TYPE",
     "REQUESTED_RANGE_NOT_SATISFIABLE",
     "EXPECTATION_FAILED",
+    "IM_A_TEAPOT",
     "INTERNAL_SERVER_ERROR",
     "NOT_IMPLEMENTED",
     "BAD_GATEWAY",
@@ -144,6 +145,7 @@
     GATEWAY_TIMEOUT,
     GONE,
     HTTP_VERSION_NOT_SUPPORTED,
+    IM_A_TEAPOT,
     INSUFFICIENT_STORAGE_SPACE,
     INTERNAL_SERVER_ERROR,
     LENGTH_REQUIRED,


Test patch:
diff --git a/src/twisted/web/test/test_http.py b/src/twisted/web/test/test_http.py
--- a/src/twisted/web/test/test_http.py
+++ b/src/twisted/web/test/test_http.py
@@ -2890,6 +2890,22 @@ def test_setResponseCodeAcceptsLongIntegers(self):
         req = http.Request(DummyChannel(), False)
         req.setResponseCode(1)
 
+    def test_setResponseCode418(self):
+        """
+        L{http.Request.setResponseCode} supports RFC 2324 section 2.3.2
+        418 response code and will automatically set the associated message.
+        """
+        channel = DummyChannel()
+        req = http.Request(channel, False)
+
+        req.setResponseCode(http.IM_A_TEAPOT)
+        req.write(b"")
+
+        self.assertEqual(
+            channel.transport.written.getvalue().splitlines()[0],
+            b"(no clientproto yet) 418 I'm a teapot",
+        )
+
     def test_setLastModifiedNeverSet(self):
         """
         When no previous value was set and no 'if-modified-since' value was