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

957 views Asked by At

I am trying to set up a reverse proxy with Apache 2.4.

It looks like I cannot use the horrible mod_proxy directly, as it does not support websockets (unless manually configured for every single URL), so I have to use the horrible horrible mod_rewrite instead.

My configuration looks as follows so far:

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

One application that I’m trying to run (the horrible³ Collabora Online in combination with NextCloud) will try to open WebSockets to URLs like this: ws://collabora.example.com/lool/https%253A%252F%252Fcloud.example.com%252Fapps%252Frichdocuments%252Fwopi%252Ffiles%252F51040%3Faccess_token%3DABCDEF%26permission%3Dedit/ws. Unfortunately, with the configuration above, these URLs will arrive at the backend with all the %25 parts decoded to % (and others as well): ws://collabora.example.com/lool/https%3A%2F%2Fcloud.example.com%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F51040?access_token=ABCDEF&permission=edit/ws.

Collabora will report error messages like this:

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

and the WebSocket connections will fail with a 400 Bad Request error in the browser.

Setting AllowEncodedSlashes to On or NoDecode doesn’t change this. (As far as I understand, this only affects the value of PATH_INFO.)

Reading through the RewriteRule flags, the [B] flag seems to talk about something related to my problem. There it says “mod_rewrite has to unescape URLs before mapping them” (I assume the sole reason for that being to maximise annoyance), so the [B] flag will re-escape them again after the mapping. This of course doesn’t work in this case and will escape all the slashes, even the ones that were not escaped before: "ws://collabora.example.com%2Flool%2Fhttps%253A%252F%252Fcloud.example.com%252Fapps%252Frichdocuments%252Fwopi%252Ffiles%252F51040%3Faccess_token%3DABCDEF%26permission%3Dedit%2Fws"

Is there a way to fix this issue or is this the point where I finally have to get rid of Apache for good?

3

There are 3 answers

0
cdauth On BEST ANSWER

Based on covener’s answer, I have now come up with the following configuration that works:

<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>

I adjusted covener’s answer to support all kinds of HTTP requests, and I had to add the NE flag (otherwise the request URI would be escaped once more).

1
covener On

One trick in this area is to use a capture of %{THE_REQUEST} instead of a backreference, because it will use the requests original encoding, such as:

<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$1 [P]
</VirtualHost>

I only added the new condition w/ capture and changed $1 to %1. I only desk-checked, but I suspect it gets you passed the encoding issue with only a few small tweaks.

1
PascalPflaum On

Collabora updated the documentation and I ran in the same issue.

So there is a much nicer solution (found at https://www.collaboraoffice.com/code/)

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