Skip to content

Commit

Permalink
#12155 Speed up twisted.web server, part 2 (#12157)
Browse files Browse the repository at this point in the history
  • Loading branch information
itamarst committed May 3, 2024
2 parents a7fa835 + 6c2ea7c commit 55ef3dc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 27 deletions.
11 changes: 8 additions & 3 deletions src/twisted/web/_http2.py
Expand Up @@ -1073,10 +1073,15 @@ def writeHeaders(self, version, code, reason, headers):
@type reason: L{bytes}
@param headers: The HTTP response headers.
@type headers: Any iterable of two-tuples of L{bytes}, representing header
names and header values.
@type headers: L{twisted.web.http_headers.Headers}
"""
self._conn.writeHeaders(version, code, reason, headers, self.streamID)
self._conn.writeHeaders(
version,
code,
reason,
[(k, v) for (k, values) in headers.getAllRawHeaders() for v in values],
self.streamID,
)

def requestDone(self, request):
"""
Expand Down
48 changes: 24 additions & 24 deletions src/twisted/web/http.py
Expand Up @@ -1200,7 +1200,6 @@ def write(self, data):
version = self.clientproto
code = b"%d" % (self.code,)
reason = self.code_message
headers = []

# if we don't have a content length, we send data in
# chunked mode, so that we can support pipelining in
Expand All @@ -1211,7 +1210,7 @@ def write(self, data):
and self.method != b"HEAD"
and self.code not in NO_BODY_CODES
):
headers.append((b"Transfer-Encoding", b"chunked"))
self.responseHeaders.setRawHeaders("Transfer-Encoding", [b"chunked"])
self.chunked = 1

if self.lastModified is not None:
Expand All @@ -1228,14 +1227,10 @@ def write(self, data):
if self.etag is not None:
self.responseHeaders.setRawHeaders(b"ETag", [self.etag])

for name, values in self.responseHeaders.getAllRawHeaders():
for value in values:
headers.append((name, value))
if self.cookies:
self.responseHeaders.setRawHeaders(b"Set-Cookie", self.cookies)

for cookie in self.cookies:
headers.append((b"Set-Cookie", cookie))

self.channel.writeHeaders(version, code, reason, headers)
self.channel.writeHeaders(version, code, reason, self.responseHeaders)

# if this is a "HEAD" request, we shouldn't return any data
if self.method == b"HEAD":
Expand Down Expand Up @@ -2636,8 +2631,7 @@ def isSecure(self):
return False

def writeHeaders(self, version, code, reason, headers):
"""
Called by L{Request} objects to write a complete set of HTTP headers to
"""Called by L{Request} objects to write a complete set of HTTP headers to
a transport.
@param version: The HTTP version in use.
Expand All @@ -2650,19 +2644,25 @@ def writeHeaders(self, version, code, reason, headers):
@type reason: L{bytes}
@param headers: The headers to write to the transport.
@type headers: L{twisted.web.http_headers.Headers}
"""
sanitizedHeaders = Headers()
for name, value in headers:
sanitizedHeaders.addRawHeader(name, value)

responseLine = version + b" " + code + b" " + reason + b"\r\n"
headerSequence = [responseLine]
headerSequence.extend(
name + b": " + value + b"\r\n"
for name, values in sanitizedHeaders.getAllRawHeaders()
for value in values
)
@type headers: L{twisted.web.http_headers.Headers}, or (for backwards
compatibility purposes only) any iterable of two-tuples of
L{bytes}, representing header names and header values. The latter
option is not actually used by Twisted.
"""
if not isinstance(headers, Headers):
# Turn into Headers instance for security reasons, to make sure we
# quite and sanitize everything. This variant should be removed
# eventually, it's only here for backwards compatibility.
sanitizedHeaders = Headers()
for name, value in headers:
sanitizedHeaders.addRawHeader(name, value)
headers = sanitizedHeaders

headerSequence = [version, b" ", code, b" ", reason, b"\r\n"]
for name, values in headers.getAllRawHeaders():
for value in values:
headerSequence.extend((name, b": ", value, b"\r\n"))
headerSequence.append(b"\r\n")
self.transport.writeSequence(headerSequence)

Expand Down
1 change: 1 addition & 0 deletions src/twisted/web/newsfragments/12155.feature
@@ -0,0 +1 @@
twisted.web's HTTP 1.1 server is an additional 5% faster.
4 changes: 4 additions & 0 deletions src/twisted/web/test/requesthelper.py
Expand Up @@ -118,6 +118,10 @@ def requestDone(self, request):
pass

def writeHeaders(self, version, code, reason, headers):
if isinstance(headers, Headers):
headers = [
(k, v) for (k, values) in headers.getAllRawHeaders() for v in values
]
response_line = version + b" " + code + b" " + reason + b"\r\n"
headerSequence = [response_line]
headerSequence.extend(name + b": " + value + b"\r\n" for name, value in headers)
Expand Down

0 comments on commit 55ef3dc

Please sign in to comment.