HttpClientProxy generator unescapes string query values before escaping them, so %XX in a value loses one level of encoding
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 74/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- csharp
- Área
- backend-api-design
Línea de trabajo
Empieza con HttpClientProxySourceGenerator.cs y revisa la plantilla encodeStringRouteParameters que aparece en el issue. Comprueba si hay pruebas existentes del generador que cubran parámetros de cadena de consulta y valores que contengan escapes de porcentaje, y luego ejecuta las pruebas pertinentes. El trabajo estará terminado cuando los valores de cadena de consulta de tipo string que contengan %XX lleguen al servidor sin cambios y pasen las pruebas existentes de generación del proxy.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.)
- Lenguaje dominante
- C#
- Estrellas
- 1.4k
- Forks
- 264
- Merge medio
- 13 h 15 min
- PR fusionados (30 d)
- 344
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de bitfoundation/bitplatform
-
BitSwipeTrap sets itself up again on every render while its first setup is pendingPosiblemente ocupada @yasmoradi la tomó hoy. Abierto
bitfoundation/bitplatform#14143 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
bit BlazorUI's trimming tests fail on LinuxPosiblemente ocupada @yasmoradi la tomó hoy. Abierto
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
bitfoundation/bitplatform#14132 ·
Los mantenedores suelen responder en 1 día
-
BbScanner improvementsPosiblemente ocupada @msynk la tomó hace 1 día. Abiertoarea / bbscanner
bitfoundation/bitplatform#14128 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
BitTimeZonePicker builds its whole time zone list while it is closedPosiblemente ocupada @yasmoradi la tomó hace 1 día. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 35/100
bitfoundation/bitplatform#14125 ·
Los mantenedores suelen responder en 1 día
-
Balette improvementsPosiblemente ocupada @msynk la tomó hace 1 día. Abiertoarea / balette
bitfoundation/bitplatform#14121 · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de bitfoundation/bitplatform
Issues similares
-
area-multitenancy area-security p1-recommended priority-high technical-debt
Dificultad 2/5 Menos de una hora Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
-
help wanted needs-unity ready for a contributor
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
eyalgolan/statecraft-israel#1542 ·
Los mantenedores suelen responder en 1 día
-
kind/enhancement Provider Upgrade pulumi/pulumi-azure R1 Task
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
pulumi/pulumi-azure#3669 ·
-
type/bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día