Error WOPI src Collabora Code 26.04.3.1

Summary

When the WOPISrc URL registered in storage.wopi.alias_groups already contains a query string (e.g. an opaque fp parameter used by the WOPI host to resolve the file), the outbound CheckFileInfo request built by coolwsd appends access_token inside the existing query parameter’s value instead of adding it as its own top-level query parameter joined with &.

As a result the WOPI host never receives a real, separate access_token parameter — it only sees its own parameter corrupted with an embedded, percent-encoded ?access_token=... string — and the document fails to open.

Environment

  • coolwsd version: 26.04.3.1 (Docker image collabora/code:26.04.3.1)
  • Deployment: Kubernetes (self-hosted), coolwsd behind an nginx Ingress with TLS termination
  • storage.wopi.alias_groups mode: groups, explicit bare-hostname allow-list (unrelated to this issue)

Steps to reproduce

  1. Configure a WOPI host whose file URLs use a query string for an internal opaque parameter, e.g.:

    https://wopihost.example.com/wopi/files/<FILE_ID>?fp=<OPAQUE_PARAM>==
    
    

    (note the base64-style == padding at the end of the parameter value — this seems to matter, see “Additional context” below.)

  2. Register this pattern as an allowed WOPI host in coolwsd.xml.

  3. Open a document served through this WOPI host from the Collabora editor (cool.html).

  4. Observe the outgoing CheckFileInfo request in the wsd logs.

Expected result

coolwsd should call:

https://wopihost.example.com/wopi/files/<FILE_ID>?fp=<OPAQUE_PARAM>==&access_token=<ACCESS_TOKEN>&access_token_ttl=0

i.e. access_token and access_token_ttl both added as distinct, top-level query parameters (joined with &, since a query string already exists).

Actual result

The wsd log shows (anonymized, real hostname/tokens replaced with placeholders):

ERR  #43: WOPI::CheckFileInfo returned 500 (Internal Server Error) Internal Server Error for URI
[https://wopihost.example.com/wopi/files/<FILE_ID>?fp=<OPAQUE_PARAM>%3D%3D%3Faccess_token%3D<ACCESS_TOKEN>&access_token_ttl=0].
...
Body: [Internal server error]
|.../wsd/wopi/CheckFileInfo.cpp:98

ERR  #43: Failed or timed-out CheckFileInfo [https://wopihost.example.com/wopi/files/<FILE_ID>?fp=<OPAQUE_PARAM>%3D%3D%3Faccess_token%3D<ACCESS_TOKEN>&access_token_ttl=0]
|.../wsd/wopi/CheckFileInfo.cpp:112

ERR  #43: CheckFileInfo failed for [https%3A%2F%2Fwopihost.example.com%3A443%2Fwopi%2Ffiles%2F<FILE_ID>], State::Fail
|.../wsd/RequestVettingStation.cpp:349

Decoding the query string of the outgoing request URI shows there is in fact only one top-level parameter, fp, whose decoded value is:

fp              = <OPAQUE_PARAM>==?access_token=<ACCESS_TOKEN>
access_token_ttl = 0

access_token is not a parameter at all — it has been concatenated onto the end of the fp value using a literal ? (later percent-encoded to %3F because it now lives inside another parameter’s value), while access_token_ttl is correctly added afterwards as its own parameter using &. This inconsistency (one parameter appended correctly, the very next one appended incorrectly) strongly suggests two different code paths are used to attach these two values to the WOPISrc URL, and only one of them checks for/handles a pre-existing query string correctly.

The backend WOPI host, receiving no usable access_token, cannot authenticate the request and returns its own HTTP 500, which is then surfaced by coolwsd as WOPI::CheckFileInfo returned 500.

Additional context

  • This only became visible after fixing an unrelated, correctly-behaving storage.wopi.alias_groups configuration issue (host allow-list now matches bare hostnames in 26.04, without scheme/port — which is intentional/expected behavior change from 25.04 and not part of this report). Before that fix, requests never reached CheckFileInfo, so this URL-construction issue may have been present for longer without being observed.
  • The relevant code paths appear to live in the new wsd/wopi/ subfolder introduced as part of the WOPI handling refactor in 26.04 (wsd/wopi/CheckFileInfo.cpp, wsd/RequestVettingStation.cpp).
  • As a workaround on our side, we are considering moving the WOPI host’s opaque fp parameter out of the query string (e.g. into the URL path) so the WOPISrc has no pre-existing query string when coolwsd appends access_token/access_token_ttl — this should avoid the bug entirely if confirmed correct, since it would make access_token the first parameter added rather than the second one merged into an existing value.

Request

Could someone confirm whether this is a known regression in the 26.04 WOPI request-building code (vs. the pre-26.04 implementation), and if a fix already exists or is planned? Happy to provide further (anonymized) logs or test a patched build if useful.

This looks similar to Nested WOPISrc query string breaks access_token parsing, causing missing Authorization header · Issue #16040 · CollaboraOnline/online · GitHub which was fixed today.