Je viens de trouver un bogue dans Osmose, sur son serveur Backend. ==== Premier problème (le plus sérieux) ===
Cela se situe ici: https://gitorious.org/~frodrigo/osmose/frodrigo-osmose-backend/blobs/master/modules/OsmSax.py Aux deux lignes suivantes du module SaxWriter lorsqu'il génère le code des valeurs d'attributs des élements XML : 369 self._write(' %s=%s' % (name, quoteattr(value))) 378 self._write(' %s=%s' % (name, quoteattr(value))) En effet, la fonction Python quoteattr() ne représente pas correctement le caractère "&" qu'il laisse sous cette forme, alors qu'il FAUT le réencoder sous la forme "&" La fonction quoteattr() est importée depuis le module Python "sax.saxutils", absent dans les sources GIT d'Osmose. C'est elle qui est ici en cause. Cela affecte la modification des éléments contenant un caractère "&" dans leur valeur (par exemple les relations contenant un tag "url", ou certains tags "name" parfaitement valides). L'effet de ce bogue est que le XML reçu par le client et éditable par "rawedit" est invalide, et ne peut pas être revalidé tel quel ! Sinon on reçoit un message affiché en rouge en haut de l'écran rawedit: "XML parser can't parse this data", et les données ne sont pas enregistrées. Pour contourner le problème, il faut soit même corriger le code XML qui a été reçu en remplaçant les "&" affichés dans l'éditeur dans les valeurs de tags par "&" avant de valider, même si on n'a pas réellement touché à la valeur. Le risque subsiste que même sans y toucher, l'absence de modification manuelle pour faire la correction risque parfois d'être acceptés comme du XML valide (par exemple quand un "&" littéral est suivi de quelquechose qui ressemble à une référence numérique de caractère ou une référene d'entité XML définie dans le schéma XML utilisé), ce qui corrompra les données qui n'avaient pas lieu d'être modifiées. Je ne sais pas si c'est la fonction quoteattr() du module sax.saxutils qui devrait être corrigée, ou si une autre fonction devrait plutôt être définie ou utilisée ici, ou si un paramètre supplémentaire optionnel de quoteattr() permet de préciser la conformité avec XML (car quoteattr() n'est pas obligé de remplacer ces "&" si la fonction est utilisée pour générer du HTML ou du SGML): dans ce cas il faut passer ce paramètre oublié. A ce sujet, quoteattr() recode toutes les apostrophes ASCII (') sous la forme ' alors que c'est inutile (et peu lisible) ici, étant donné que la chaine retournée sera encadrée de guillemets doubles ASCII ("). En revanche les quatre caractères suivants doivent être mis sous forme de référence à une des quatre seules entité de caractères XML prédéfinie : - les guillemets doubles ASCII (") sous la forme " - le signe inférieur (<) sous la forme < - le signe supérieur (>) sous la forme > - le signe et commercial (&) sous la forme & Et c'est tout ! Tout le reste peut (et devrait) rester sous leur forme littérale (même l'apostrophe ici, bien que XML prédéfinisse aussi une cinquième entité "'" puisque la syntaxe XML permet aussi aux valeurs d'attributs d'être encadrées par des apostrophes ASCII au lieu de guillemets ASCII). ==== Deuxième problème (lié au premier) === Enfin je note que le code Javascript envoyé au client utilise le constructeur: new XMLHttpRequest(), mais sans préciser le jeu de caractères qui sera utilisé pour dialoguer avec le serveur : function ApiDo(action) { var myReq = new XMLHttpRequest(); if (myReq) { myReq.onreadystatechange = function (evnt) { if(myReq.readyState == 4) { res = myReq.responseText.split('\n'); document.getElementById('osm_msg').innerHTML = res[0]; tmp = res.shift(); document.getElementById('osm_data').value = res.join('\n'); } } myReq.open('POST', '/' + action + '/' + osm_type + '/' + osm_id, true); myReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); poststr = "osm_data=" + encodeURIComponent(document.getElementById("osm_data").value ); myReq.send(poststr); } } Rien n'oblige actuellement le navigateur à supposer que cette requête se fera en codage UTF-8, même si la page web et le code javascript sont eux-même codés en UTF-8. Dans les faits, cette requête telle qu'elle est envoyée au serveur ne précise rien du tout, ce qui demande alors que les données incluses dans la valeur "osm_data=" ne soient que de l'ASCII pur. Ici le problème est que pour s'assurer que ce sera uniquement de l'ASCII, ce javascript utilise encodeURIComponent(), dont le comportement dépend du navigateur : la source est bien de l'UTF-16, son résultat sera bien de l'ASCII compatible avec une syntaxe de composant URI, mais asolument rien n'indique dans quel jeu de caractères se fera la conversion de la chaine source UTF-16 vers un jeu restreint à 8 bits (avant ensuite de convertir les espaces ASCII sous la forme "+", et les octets non ASCII et non imprimables ou réservés par la syntaxe des URI sous la forme "%nn"). En effet, le constructeur XMLHttpRequest crée un nouveau document totalement séparé du document source (hormi son domaine de sécurité) et communique même avec un serveur backend distinct du serveur frontend affichant la carte Osmose et l'interface d'édition. Il n'y a strictement rien dans le code qui indique que le backend utilise UTF-8, et cela pourrait expliquer pourquoi la base OSM contient maintenant des caractères mal réencodés (il suffit par exemple qu'un utilisateur utilise un navigateur configuré tel que UTF-8 n'est pas son codage par défaut, mais utilise par défaut ISO-8859-1, Windows-1252 voire aussi Mac-Roman). Il faudrait donc que le javascript précise bien le codage utilisé avant de les mettre dans les données qu'il envoie en POST-Data dans la valeur "osmdata", sous forme URL-encodée (même si la requête ici indique au serveur que les données sont supposées bien être au format "application/x-www-form-urlencoded", cela ne dispense pas le javascript de coder correctement sour cette forme). Ce problème existe même avec les navigateurs récents, pour peu que l'utilisateur n'a pas configuré son navigateur pour utiliser UTF-8 comme codage par défaut, et selon d'autres réglages possibles de la façon d'interpréter les URI présentes dans de vieilles pages HTML non conformes XML/XHTML ni HTML5. Il n'est pas inintéressant de lire la doc officielle de la norme ECMAScript au sujet des mises en garde sur l'effet et la compatibilité de la fonction encodeURIComponent(), dès lors que la chaîne source en paramètre ne contient PAS UNIQUEMENT des caractères ASCII mais n'importe quel autre "caractère" === Note 1 : question de compatiblité des chaines en Javascript/ECMAScript === Note : les "caractères" en Javascript, ceux qu'on énumère dans une chaine avec la méthode .charAt(n), ou qu'on compte avec la méthode .length(), ne sont PAS les caractères au sens Unicode, mais seulement des "unités de code" arbitraires sur 16 bits. Javascript n'oblige même pas en fait à ce que ses chaines soit nécessairement codées de façon interne en UTF-16, car ce pourrait aussi bien être un codage JIS sur 16 bits, voire n'importe quelle valeur binaire non textuelle, comme aussi en Java : il est parfaitement valide en Javascript d'insérer des codets nuls dans ces "chaines" ou un codet égal à 0xFFFF, qui ne correspond à rien de valide en UTF-16, ou encode d'y mettre un codet égal à 0xD800 isolé non suivi d'un codet entre 0xDC00 et DFFF, là encore invalide en UTF-16, et les chaines Javascript font la distinction entre différents codages de sauts de lignes. Javascript initialement n'obligeait même pas à ce que son codage interne soit avec des unités de code sur au moins 16 bits (ce n'est plus le cas depuis la norme ECMAScript qui précise bien que ces unités de code DOIVENT être sur 16 bits, mais n'oblige toujours pas à ce que ce soit uniquement de l'UTF-16 valide). Bref attention à la fonction encodeURIComponent(string) ! Lire à ce sujet ce qui a été fait dans jQuery pour résoudre ce problème de compatibilité entre navigateurs et selon leur configuration: je suggère donc d'utiliser jQuery dans le frontend, car il résoud bien des difficultés, et fournit une bibliothèque standard pour effectuer des requêtes XML fiables avec un serveur backend. === Note 2 : XMLHTtpRequest, et suggestion pour la sécurité === D'ailleurs le constructeur XMLHtppRequest() a aussi des problèmes de sécurité répertoriés, comme aussi des problèmes mieux connus de compatiblité avec différents types de navigateurs. jQuery fournit une solution stable et sure, et même les organismes de surveillance de la sécurité sur le web recommandent de ne plus l'utiliser du tout et de passer aux requêtes JSON dès que possible car elles incluent une implémentation native avec des contraintes bien plus forte de sécurité (qui évitent par exemple des attaques de type "XSS", Cross-Site Scripting, ou des attaques directement sur la plateforme native du navigateur client, surtout avec les vieilles versions d'Internet Explorer où XMLHttpRequest n'existait que par un composant externe ActiveX). _______________________________________________ Talk-fr mailing list Talk-fr@openstreetmap.org http://lists.openstreetmap.org/listinfo/talk-fr