BUG : updatepanel et encoding ISO (non UTF-8)
EDIT : hotfix dispo par Ms voir : Updatepanel et encoding non UTF-8 - la suite
Actuellement je bosse sur un site qui utilise l'encoding ISO-8859-15 plutôt que UTF-8. Cela est définit au niveau du web.config via la balise globalization :
<globalization requestEncoding="ISO-8859-15" responseEncoding="ISO-8859-15"
fileEncoding="ISO-8859-15" culture="fr-FR" uiCulture="fr-FR" />
Tout fonctionnait bien jusqu'au jour où j'ai décidé de mettre un UpdatePanel ...
<script type="text/C#">
protected void btn1_Click(object sender, EventArgs e)
{
lit1.Text = Server.HtmlEncode(tb1.Text);
}
</script>
<asp:TextBox ID="tb1" runat="server" />
<asp:UpdatePanel ID="up1" runat="server">
<ContentTemplate>
<asp:Literal ID="lit1" runat="server" />
<asp:Button ID="Button1" runat="server" Text="toto" OnClick="btn1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
Lorsque je faisais des tests avec mon éfélant, il se transformait en éfélant, vraiment pas cool pour un éfélant !
Je regarde sur google et je tombe sur plusieurs post décrivant le problème, principalement celui-ci : http://forums.asp.net/p/1020399/1379727.aspx. Mais bien sur aucune réponse ...
Après avoir sortis Fiddler, je vois que les paramètres passé en POST lors de la requête ne sont pas encodé comme il faut. Ni une, ni deux, je sors l'artillerie lourde : notepad2 et je regarde les sources de Atlas, je tombe alors sur le code qui génère le contenu de la requête POST :
if (tagName === 'INPUT') {
var type = element.type;
if ((type === 'text') ||
(type === 'password') ||
(type === 'hidden') ||
(((type === 'checkbox') || (type === 'radio')) && element.checked)) {
formBody.append(name);
formBody.append('=');
formBody.append(encodeURIComponent(element.value));
formBody.append('&');
}
}
else if (tagName === 'SELECT') {
var optionCount = element.options.length;
for (var j = 0; j < optionCount; j++) {
var option = element.options[j];
if (option.selected) {
formBody.append(name);
formBody.append('=');
formBody.append(encodeURIComponent(option.value));
formBody.append('&');
}
}
}
else if (tagName === 'TEXTAREA') {
formBody.append(name);
formBody.append('=');
formBody.append(encodeURIComponent(element.value));
formBody.append('&');
}
Apparemment le encodeURIComponent n'encode pas les caractères spéciaux comme il faudrait pour ISO-8859-15 (ou tout autre ISO je suppose). A quoi sert cette méthode ? Regardons dans les specs : http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
15.1.3.4 encodeURIComponent (uriComponent)
The encodeURIComponent function computes a new version of a URI in which each instance of
certain characters is replaced by one, two or three escape sequences representing the UTF-8 encoding
of the character.
When the encodeURIComponent function is called with one argument uriComponent, the
following steps are taken:
- Call ToString(uriComponent).
- Let unescapedURIComponentSet be a string containing one instance of each character valid in
- uriUnescaped.
- Call Encode(Result(1), unescapedURIComponentSet)
- Return Result(3).
La solution est donc de redéfinir la méthode encodeURIComponent (ce que c'est beau JavaScript quand même). A force de bidouille et d'analyse avec Fiddler j'obtiens cette nouvelle fonction.
// corrige des bugs d'atlas lié à l'encoding non utf-8 et les caractères spéciaux
var CS_encodeURIComponent = encodeURIComponent;
var CS_decodeURIComponent = decodeURIComponent;
encodeURIComponent = function(s){
s = escape(s);
while (s.indexOf('/') >= 0) {
s = s.replace('/', '%2F');
}
while (s.indexOf('+') >= 0) {
s = s.replace('+', '%2B');
}
return s;
}
decodeURIComponent = function(s){
while (s.indexOf('%2B') >= 0) {
s = s.replace('%2B', '+');
}
while (s.indexOf('%2F') >= 0) {
s = s.replace('%2F', '/');
}
return unescape(s);
}
Il suffit alors de placer cette fonction quelques part dans votre site, par exemple fixAtlas.js (ben oui vu le nombre de fix faut bien les rassembler quelque part ...) et vous pourrez utiliser l'encoding que vous souhaitez avec un UpdatePanel.
Attention ! Je ne connais pas assez le fonctionnement de l'encoding au niveau d'une requête HTTP pour garantir le bon fonctionnement de cette bidouille. Si vous l'utilisez, il faut bien avoir conscience que cela redéfinit une fonction native de JavaScript, cela peut donc avoir des conséquences inatendu ailleurs dans votre site ! Cette bidouille fonctionne seulement si vous utilisez de l'ISO, en UTF-8 la méthode ne fonctionne pas.
Si vous modifiez la bidouille ou si vous trouvez des bugs, n'hésitez pas à me le dire via les commentaires.