uap-csharp icon indicating copy to clipboard operation
uap-csharp copied to clipboard

Handling of empty string replacement values differs between implementations

Open longzheng opened this issue 4 years ago • 0 comments

I'm not sure if this is the right place to ask this question since it affects multiple implementations, including this. I cross-posted to the uap-core project but sharing here just in case it is a bug with the specific implementation.

Background

There are certain user-agents where it is not possible to derive or infer the device family, brand or model from the user-agent alone.

In our application, we want to explicitly distinguish between user-agents we recognise but we don't know of the device family (which we want to output as an empty string), and user-agents we don't recognise (fallback to the "Other" value as defined in the specification).

We've observed a difference between the uap-ref-impl Javascript and uap-csharp C# implementations of ua-parser.

Even though the Javascript is described as the "reference" implementation, we're not sure if this is a bug or the intention of the specification since it is vague about how to handle a replacement value that is an empty string "".

The specification writes,

In case that no replacement for a match is given, the first match defines the family and the model. If a *_replacement string is specified it shall overwrite or replace the match.

One could interpret "no replacement" to mean either

  • undefined or null
  • undefined or null or empty string

Repro

The regex YAML is defined as

device_parsers:
  - regex: '(radiocomandroid)'
    brand_replacement: ''
    device_replacement: ''
    model_replacement: ''

Testing with the user-agent string of radiocomandroid

The Javascript implementation outputs

{
    "family": "radiocomandroid",
    "brand": null,
    "model": "radiocomandroid"
}

The C# implementation outputs

{
    "IsSpider": false,
    "Brand": "",
    "Family": "",
    "Model": ""
}

Side-by-side

Javascript .NET
Device family "radiocomandroid" ""
Device brand null ""
Device model "radiocomandroid" ""

Question

The JavaScript implementation uses a conditional (ternary) operator which will treat an empty string "" as false, which means it will fallback to the first match value.

https://github.com/ua-parser/uap-ref-impl/blob/f038cf5ddd7b9b52c724fe2b6c4d949d2ef8e6b8/lib/device.js#L24

The C# implementation uses a == null condition which will use an empty string "" as the final value.

https://github.com/ua-parser/uap-csharp/blob/master/UAParser/UAParser.cs#L523

Which of these implementations is the intent of the specification? Is an empty string considered "no replacement"?

longzheng avatar Nov 10 '21 00:11 longzheng