由于 Apache mod_rewrite 代理未转义 %2F 斜杠,Collabora“未知资源”

Collabora “Unknown resource” because of Apache mod_rewrite proxy unescaping %2F slashes

我正在尝试使用 Apache 2.4 设置反向代理。

看来我不能直接使用可怕的mod_proxy,因为它不支持websockets(除非为每个URL手动配置),所以我必须使用可怕的可怕mod_rewrite 代替。

到目前为止,我的配置如下所示:

<VirtualHost *:80>
    ServerName collabora.example.com
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} =websocket
    RewriteRule ^(/.*)?$ wss://collabora-backend [P]
    RewriteCond %{HTTP:Upgrade} !=websocket
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/?
    RewriteRule ^(/.*)?$ https://collabora-backend [P]
</VirtualHost>

我正在尝试 运行(可怕的³ Collabora Online in combination with NextCloud)的一个应用程序将尝试向 URL 开放 WebSocket,如下所示:ws://collabora.example.com/lool/https%253A%252F%252Fcloud.example.com%252Fapps%252Frichdocuments%252Fwopi%252Ffiles%252F51040%3Faccess_token%3DABCDEF%26permission%3Dedit/ws。不幸的是,使用上面的配置,这些 URL 将到达后端,所有 %25 部分都解码为 %(以及其他部分):ws://collabora.example.com/lool/https%3A%2F%2Fcloud.example.com%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F51040?access_token=ABCDEF&permission=edit/ws.

Collabora 将报告如下错误消息:

wsd-00026-0195 0:01:27.448231 [ client_ws_0003 ] ERR Unknown resource: /lool//ws/lool/https%253A%252F%252Fowncloud.mydomain.fr%252Findex.php%252Fapps%252Frichdocuments%252Fwopi%252Ffiles%252F5%3Faccess_token=R...c&permission=edit/ws| LOOLWSD.cpp:1154

并且 WebSocket 连接将失败并在浏览器中出现 400 Bad Request 错误。

AllowEncodedSlashes 设置为 OnNoDecode 不会改变这一点。 (据我了解,这只会影响 PATH_INFO 的值。)

通读RewriteRule flags[B] flag好像说的和我的问题有关。那里写着“mod_rewrite has to unescape URLs before mapping them”(我假设这样做的唯一原因是为了最大限度地增加烦恼),所以 [B] 标志将再次对它们进行转义映射后。这在这种情况下当然不起作用,并且会转义所有斜线,甚至是之前没有转义的斜线:"ws://collabora.example.com%2Flool%2Fhttps%253A%252F%252Fcloud.example.com%252Fapps%252Frichdocuments%252Fwopi%252Ffiles%252F51040%3Faccess_token%3DABCDEF%26permission%3Dedit%2Fws"

有没有办法解决这个问题,或者这是我最终必须永远摆脱 Apache 的地步吗?

这方面的一个技巧是使用 %{THE_REQUEST} 的捕获而不是反向引用,因为它将使用请求的原始编码,例如:

<VirtualHost *:80>
    ServerName collabora.example.com
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} =websocket
    RewriteCond %{THE_REQUEST} "^GET /(.*) HTTP/1.?$"
    RewriteRule ^(/.*)?$ wss://collabora-backend/%1 [P]
    RewriteCond %{HTTP:Upgrade} !=websocket
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/?
    RewriteRule ^(/.*)?$ https://collabora-backend [P]
</VirtualHost>

我只添加了带捕获的新条件并将 $1 更改为 %1。我只是进行了桌面检查,但我怀疑它让你通过一些小的调整就解决了编码问题。

根据 covener 的回答,我现在想出了以下可行的配置:

<VirtualHost *:80>
    ServerName collabora.example.com
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteCond %{THE_REQUEST} "^[a-zA-Z]+ /(.*) HTTP/\d+(\.\d+)?$"
    RewriteRule .? wss://collabora-backend/%1 [P,NE]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/?
    RewriteCond %{THE_REQUEST} "^[a-zA-Z]+ /(.*) HTTP/\d+(\.\d+)?$"
    RewriteRule .? https://collabora-backend/%1 [P,NE]
</VirtualHost>

我调整了 covener 的答案以支持所有类型的 HTTP 请求,我不得不添加 NE 标志(否则请求 URI 将再次被转义)。

Collabora 更新了文档,我 运行 在同一期。

所以有一个更好的解决方案(在 https://www.collaboraoffice.com/code/ 找到)

  AllowEncodedSlashes NoDecode
  ProxyPassMatch "/lool/(.*)/ws$" wss://127.0.0.1:9980/lool//ws nocanon