0

Am having a bit of trouble understanding how to pass encoded data in a request using flurl. We have an api that looks like:

https://servicename.com/domain/api/{identifier}?parameter=value

And in some specific cases we have identifiers which contain a forward-slash /

We are building the request using the following code:

var clientRequest = this.configuration.Client
            .Request(this.configuration.RequestPath)
            .AppendPathSegment(identifier)
            .WithHeader("Requesting-System", "api");

And we call it using:

using (var response = await clientRequest.GetAsync(cancellationToken))
{
    return await response.Content.ReadAsStringAsync();
}

Now. Taking the straightforward approach of just passing in the identifier with the forward-slash; let's say abc/123. The above code generates a clientRequest with a path of

https://servicename.com/domain/api/abc/123?parameter=value

Which, expectedly, fails with a 400 error. So the solution for this, based on our api specifications, is to encode the forward-slash as %2F, and pass that in the url. Thankfully, Flurl makes this pretty easy in theory by allowing an optional parameter in the AppendPathSegment method, which will cause the encoding. So we amend the above to use

.AppendPathSegment(identifier, true)

Which generates a clientRequest with a path of

https://servicename.com/domain/api/abc%2F123?parameter=value

Exactly what I'd expect to see. If I call to this URL using postman, then I can see the correct response that I'm expecting from the API.

However, when I call it using the GetAsync method (same as above), then I still receive the 400 Sub-Resource not recognised error; and in my logs I can see that the actual request was made to

https://servicename.com/domain/api/abc/123?parameter=value

Is there a point during the service call that Flurl decodes the url string? If so, how do I pass the %2F in?

Have tried double-encoding, so that the request contains the identifier abc%252F123. Given the above, I would have expected this to be decoded to abc%2F123, which will then be sent to our API. But in this case no decoding takes place, and the request url is

https://servicename.com/domain/api/abc%252F123?parameter=value

Many thanks in advance for the help.

The Aurochs
  • 103
  • 3
  • Sorry for the delay. "in my logs I can see the actual request..." How exactly are your logging this? I set up your exact scenario and followed the request to the [precise point](https://github.com/tmenier/Flurl/blob/master/src/Flurl.Http/FlurlRequest.cs#L136) where the `HttpRequestMessage` is finalized and handed off to `HttpClient`, and can assure that the URL is not un-encoded nor double-encoded. The path segment is `abc%2F123` at this point. – Todd Menier Oct 12 '18 at 12:52
  • No apology necessary; really appreciate you taking the time to look at all these problems in the first place. We use Serilog & SEQ for our logging solutions, but we're pretty sure that's not the issue here- fiddler for example shows the same url with abc/123 – The Aurochs Oct 12 '18 at 13:37

1 Answers1

1

This appears to be a bug or quirk (depending on who you ask) with System.Uri, which HttpClient uses deep down in the call stack. The work-around is to add this to app.config or web.config:

<uri>
  <schemeSettings>
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
  </schemeSettings>
</uri>

All credit for this goes to this answer.

If at all possible, I'd avoid allowing reserved URL characters in your identifiers in the first place. It just seems to be inviting quirks. If that's not possible, perhaps come up with your own escape sequence to represent forward slashes.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • This seems like it will probably be the cause eventually; I had a play around with flurl directly & through unit tests and you're right; I couldn't replicate the issue. Thanks for the help and for giving us some different angles to attack this from – The Aurochs Oct 15 '18 at 08:00
  • Was this answer helpful? – Todd Menier Nov 19 '18 at 13:53
  • 1
    Thank you for your time and patience Todd; this was helpful. In the end our issue was that our runtime TargetFramework was not set to 4.7 after having upgraded our projects to use this version. This answer did point us away from a few dead ends of investigation. Will accept in the hopes that this is helpful to other users. Cheers – The Aurochs Nov 19 '18 at 13:56