HttpClientProxy generator unescapes string query values before escaping them, so %XX in a value loses one level of encoding
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 74/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- csharp
- Ambito
- backend-api-design
Direzione di ricerca
Inizia da HttpClientProxySourceGenerator.cs ed esamina il template encodeStringRouteParameters mostrato nell’issue. Verifica se esistono test del generatore che coprono i parametri della stringa di query e i valori contenenti escape percentuali, quindi esegui i test pertinenti. Il lavoro è completato quando i valori stringa della query contenenti %XX raggiungono il server senza modifiche e i test esistenti di generazione del proxy passano.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Summary
When a string parameter of an IAppController interface is bound from the query string, the generated HttpClient proxy unescapes the value before it escapes it:
// HttpClientProxySourceGenerator.cs, encodeStringRouteParameters
{p.Name} = Uri.EscapeDataString(Uri.UnescapeDataString({p.Name} ?? string.Empty));
So any %XX sequence that is part of the value itself is decoded once on the client, and the server receives a different string from the one the caller passed. A value can't carry a literal %26, %2F, %3D or %25.
This matters most for return urls, which routinely carry an encoded query of their own.
Repro (bit-bp 10.6.2, Bit.SourceGenerators 10.6.2)
[Route("api/v1/[controller]/[action]/"), ApiController]
public interface IDemoController : IAppController
{
[HttpGet("{?returnUrl}")]
Task<string> Echo(string? returnUrl = null, CancellationToken cancellationToken = default);
}
// Server
[HttpGet]
public Task<string> Echo(string? returnUrl = null, CancellationToken cancellationToken = default) => Task.FromResult(returnUrl ?? "");
var value = "/products?filter=a%26b&page=2"; // the inner page's own query: filter = "a&b"
var echoed = await demoController.Echo(value, cancellationToken);
- Expected:
echoed == "/products?filter=a%26b&page=2". - Sent:
GET api/v1/Demo/Echo?returnUrl=%2Fproducts%3Ffilter%3Da%26b%26page%3D2. The%26inside the value has become&before escaping, so it is now indistinguishable from the real&. - Received:
"/products?filter=a&b&page=2". When the app later navigates there,filteris"a"and a straybparameter appears.
A simpler case: "page?then=%2Fdashboard" arrives as "page?then=/dashboard". That one happens to work, but the value is no longer the one that was sent.
Where it shows up in the template
SignInPanel and SignUpPage pass returnUrl to IIdentityController.GetExternalSignInUri(provider, returnUrl, ...). A return url with an encoded & (or %25, %2F, ...) in its own query loses one level of encoding on that call. After the external sign-in round trip the user lands on a url whose query is split differently from the one she started on.
Workaround
Callers can escape the value once themselves before calling (Uri.EscapeDataString(value)). The generated code then unescapes it back to the original before escaping it again. But that only works because of this behaviour, and it would silently double-encode if the behaviour changed.
Suggestion
Escape the value as given:
{p.Name} = Uri.EscapeDataString({p.Name} ?? string.Empty);
This is what RFC 6570's {?var} expansion does: % becomes %25. If the UnescapeDataString is there so that callers who pre-encode don't get double encoding, it may be worth documenting that values must be passed raw, since a pre-encoded value and a raw value that contains %XX can't be told apart.
(Seen on 10.6.2. The line is unchanged on develop as of 2026-10-19, commit 26a808a.)
- Lingua principale
- C#
- Stelle
- 1.4k
- Fork
- 264
- Merge medio
- 13h 15m
- PR unite (30g)
- 344
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di bitfoundation/bitplatform
-
BitSwipeTrap sets itself up again on every render while its first setup is pendingForse già presa @yasmoradi l’ha presa oggi. Aperta
bitfoundation/bitplatform#14143 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
bit BlazorUI's trimming tests fail on LinuxForse già presa @yasmoradi l’ha presa oggi. Aperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
bitfoundation/bitplatform#14132 ·
I maintainer di solito rispondono entro 1 giorno
-
BbScanner improvementsForse già presa @msynk l’ha presa oggi. Apertaarea / bbscanner
bitfoundation/bitplatform#14128 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
BitTimeZonePicker builds its whole time zone list while it is closedForse già presa @yasmoradi l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 35/100
bitfoundation/bitplatform#14125 ·
I maintainer di solito rispondono entro 1 giorno
-
Balette improvementsForse già presa @msynk l’ha presa oggi. Apertaarea / balette
bitfoundation/bitplatform#14121 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di bitfoundation/bitplatform
Issue simili
-
dev/release: verify-release-candidate.sh runs 0 Java tests with Debian's MavenForse già presa @kou l’ha presa oggi. ApertaType: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
apache/arrow-adbc#4947 ·
I maintainer di solito rispondono entro 1 giorno
-
:watch: Not Triaged CAC
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
dotnet/AspNetCore.Docs#38001 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
Nimblesite/SharpLsp#468 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 88/100
elastic/ecs-dotnet#575 ·
-
alerts bug effort:S P2
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
nightscout/nocturne#2511 ·
I maintainer di solito rispondono entro 1 giorno