Bug 475200

Summary: File associations are inherited in the incorrect order
Product: [Applications] systemsettings Reporter: Adam Fontenot <adam.m.fontenot+kde>
Component: kcm_filetypesAssignee: Plasma Bugs List <plasma-bugs>
Status: RESOLVED FIXED    
Severity: normal CC: faure, kde, nate
Priority: NOR    
Version: 5.27.7   
Target Milestone: ---   
Platform: Arch Linux   
OS: Linux   
Latest Commit: Version Fixed In: 6.0
Sentry Crash Report:
Attachments: plot of multiply inheriting mime types

Description Adam Fontenot 2023-10-04 03:12:40 UTC
SUMMARY
In the course of discussing Bug 425154, we discovered several inheritance issues that make having a fallback association much more irritating than it is supposed to be. One of these issues was fixed, the other got missed. I'm filing this report so that the defect is clearly documented and doesn't slip through the cracks.

File associations form a directed acyclic graph (DAG), not a tree, which means that there's not a obvious right answer for the order to traverse the graph (which matters when determining priority for file associations). Right now KDE appears to traverse it in depth-first order, which means that some associations intended to be fallbacks will be hit before some associations that are not.

For correct behavior, KDE needs to special-case certain fallback associations so that they always appear last, move to breadth-first graph traversal, or both. (Or potentially other workarounds for the issue that I'm not seeing.)

The reproduction steps below reference the following file association inheritance graph, turned into a tree (with duplicate nodes):

>                 application/json
>                         │
>                 text/javascript
>                         │
>             application/ecmascript
>                         │
>            ┌────────────┴────────────┐
>            │                         │
> application/x-executable         text/plain
>            │                         │
> application/octet-stream  application/octet-stream

STEPS TO REPRODUCE
1. Have an application like Kate set to open text/plain, and a fallback application like Okteta set to open application/octet-stream.
2. Don't have any applications set to open JS / JSON files directly.
3. Click to open a JSON file in Dolphin.

OBSERVED RESULT
The file opens in Okteta.

EXPECTED RESULT
Given the configuration stated above, JSON files should open with the text/plain association, not with application/octet-stream. 

Given the structure above, traversing the graph in breadth-first order would give the correct associations, and it seems like a much better default.

Note however that there is no guarantee of this always holding true. For example, if application/ecmascript inherited something like text/script instead, and *that* inherited text/plain, then breadth first order would still result in application/octet-stream being hit first.

SOFTWARE/OS VERSIONS
Operating System: Arch Linux 
KDE Plasma Version: 5.27.7
KDE Frameworks Version: 5.109.0
Qt Version: 5.15.10
Kernel Version: 6.4.12-arch1-1 (64-bit)
Graphics Platform: X11

ADDITIONAL INFORMATION

This is made more annoying by the fact that some applications (e.g. Firefox) are reported to sometimes tamper with the system file associations. Users have ended up with Okular (in particular) set to open application/octet-stream as a result of PDFs not always having a mimetype available, which has led to a lot of confusion. Bug 425154 is about the pain points that result from having an application/octet-stream association set, this bug is specifically about inheritance ordering that sometimes results in this association being preferred even when a better association is available.
Comment 1 David Redondo 2023-10-17 11:38:52 UTC
I think you are right. The spec says in the section about selecting an application


"The above process is repeated for each mimetype from the most specific to the least specific. Note in particular that an application that can handle a more specific type will be used in preference to an application explicitly marked as the default for a less-specific type."

In the example text/plain is more specific then octet-stream
Comment 2 Bug Janitor Service 2023-10-18 08:29:50 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kservice/-/merge_requests/167
Comment 3 Adam Fontenot 2023-10-18 21:20:21 UTC
Created attachment 162411 [details]
plot of multiply inheriting mime types

I'm attaching a directed graph I generated showing all mimetypes installed on my system that involve multiple inheritance, to make debugging potential issues with these easier. The problem with application/json is shown clearly.
Comment 4 David Redondo 2023-10-19 07:28:14 UTC
Thanks!
Comment 5 David Redondo 2023-10-24 08:22:53 UTC
Git commit f424bd3aab78bf1e3a6c93aed7f4562d56c776a7 by David Redondo.
Committed on 24/10/2023 at 10:19.
Pushed by davidre into branch 'master'.

Fix preferred apps order for multiple level mime inheritance

We should prefer more specific mime types to less specific for that
reason offers are sorted by inheritance level first.
When constructing the offers for inherited types, the associated
services for parent types are queried. However these can already
contain services that are associated with a parent type of the
parent type as the offers are build from the bottom-up starting
with the least specific mime type.
For example when constructing offers for a mime-type that inherits
text/plain, the returned offers for text/plain will already contain
services associated with application/octet-stream.
By incrementing the inheritance levels instead of overwriting the
relative ordering of inherited mime types is preserved.

M  +24   -0    autotests/kmimeassociationstest.cpp
M  +4    -4    src/sycoca/kbuildservicefactory.cpp
M  +1    -1    src/sycoca/kbuildservicefactory_p.h

https://invent.kde.org/frameworks/kservice/-/commit/f424bd3aab78bf1e3a6c93aed7f4562d56c776a7