Skip to content

Commit

Permalink
appservice: Hack around broken 3scale Connection: header
Browse files Browse the repository at this point in the history
That sole `Connection: upgrade` header gets attached to all requests on
/wss/* paths, even for normal HTTP requests which don't have an
`Upgrade:` header. uvicorn rejects these with "Unsupported upgrade
request".

Monkey-patch the h11 module to deliver patched headers.

See https://issues.redhat.com/browse/RHCLOUD-21326
  • Loading branch information
martinpitt committed Sep 21, 2022
1 parent 0896c45 commit 32befda
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions appservice/multiplexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,38 @@ async def update_session(session_id, status):
await REDIS.publish('sessions', dumped_sessions)


# Terrifying hack around broken 3scale Connection: header; see https://issues.redhat.com/browse/RHCLOUD-21326
# uvicorn's H11Protocol.handle_events() can't be tapped into, so we need to monkey-patch
# h11.Connection.next_event() to deliver non-broken headers; otherwise uvicorn refuses these paths with
# "Unsupported upgrade request".
import h11 # noqa: E402
h11.Connection.next_event_real = h11.Connection.next_event


def hack_h11_con_next_event(self):
res = h11.Connection.next_event_real(self)
if type(res) == h11.Request:
connection_idx = None
has_upgrade = False
for i, (name, value) in enumerate(res.headers):
if name == b"connection" and b'upgrade' in value:
connection_idx = i
if name == b"upgrade":
has_upgrade = True

if connection_idx is not None and not has_upgrade:
res.headers._full_items[connection_idx] = (
res.headers._full_items[connection_idx][0], # raw name
res.headers._full_items[connection_idx][1], # normalized name
res.headers._full_items[connection_idx][2].replace(b'upgrade', b'')) # value
logger.debug("hack_h11_con_next_event on %s: fixing broken Connection: header", res.target)

return res


h11.Connection.next_event = hack_h11_con_next_event
# End hack

if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
uvicorn.run(app, host='0.0.0.0', port=8080)

0 comments on commit 32befda

Please sign in to comment.