JSON is fragile

La livebox Orange bugge. Après avoir fait le tour de mes browsers, même ceux du côté obscur, j’ai cherché dans les forums pour voir si d’autres avaient de problème d’interface de configuration indisponible sur livebox play. Me sentant décidément très seul, j’ai sorti mon firebug et me suis lancé dans un gros travail d’inspection.

Lors de JSON.parse il me dit:
[bus] error handling ajax request

SyntaxError: JSON.parse: bad control character in string literal

Ce sur plusieurs pages, les autres browsers loguant des choses tout à fait similaires.

Le JSON  en question ne semblait pas suspect dans la console mais, à le lire, observe que l’erreur de situe lorsqu’il récupère les infos sur les devices connectés. Un petit coup de JSONLint (http://jsonlint.com/) me révèle bel et bien une erreur dans la section relative à mon smart screen Samsung. J’ai cru au début à un problème d’encodage mais rien d’évident à la vue.

Ce n’est qu’en copiant la ligne dans un éditeur de texte orienté caractère comme pspad que je n’ai enfin compris quoi qu’en copiant la ligne dans mon terminal j’avais déjà un début de réponse.

« userClassID »: «  »,

Là on ne devine rien mais un prenant le même segment dans un éditeur précis (Sublime Text 2 sur mon mac) je vois non des doubles quotes vides mais contenant un caractère de contrôle S0H !! Je ne comprends pas vraiment la notation de Sublime mais il s’agit d’un caractère de contrôle que les gars d’Orange.fr ont oublié de filtrer, reste à savoir lequel. SOH est en fait le premier caractère de la table ascii, Start of Header pour être précis.

Je ne sais pas trop comment contourner ce bug pour le moment mais je l’ai identifié. Avec du XML l’erreur aurait été la même mais cela aurait été à mon avis plus simple à identifier.

29 réflexions au sujet de « JSON is fragile »

  1. Salut,

    Quelle merde cette Livebox play ! J’ai le même problème depuis 2-3 semaines, date à laquelle j’ai installé une caméra IP sur le réseau…
    En ouvrant firebug, la console m’affiche 2 erreurs dans la page DHCP: SyntaxError: JSON.parse: bad control character in string literal at line X column XXXX of the JSON data.
    J’ai réinitialisé la box, re-rentré tous les paramètres à la main: rien a faire, ça marche 5 minutes puis quand je reviens sur la page tout est replanté, plus aucun device s’affiche et ces erreurs reviennent…

    Avez-vous trouvé une solution ? Peut être que le bug est arrivé avec une des dernières mises à jour de la box ?

    1. Le contournement est de passer par un browser qui ne dispose par d’un parser JSON natif (ou dispose d’un parser JSON buggé). Le problème est intimement lié au format JSON qui est trop faible sur ce genre d’erreur. Avec IE6 par exemple, pas de parser JSON donc alternative dans le code de la livebox d’orange qui supporte encore ce browser donc usable. Je réfléchis à une solution avec un greasemonkey actuellement mais je n’ai pas fini. En attendant j’ai mis la vielle tablette droid de mon père sur le réseau WiFi partagé orange, mais là encore c’est un contournement. Je posterai mon Greasemonkey quand il sera prêt, car je ne me sent pas de mettre en place un proxy juste pour cet usage.

    2. Un petit tour dans mon JSON et apparemment c’est mon imprimante sans fil qui fait tout dérailler:
      « userClassID »: »Mfg=HPTyp=MFPMod=HP Officejet Pro 8620Ser=CN443B4176″
      Notepad++ m’affiche apparemment des caractères spéciaux [BEL] [EM] et [SO] dans user class id.
      Je vais essayer de renommer l’imprimante via son interface de configuration voir ce que ça donne.

  2. Ce sont ces caractères spéciaux qui en font du JSON illégal. Dans le cas de la tablette qui me posait problème, impossible de changer sont hostname donc c’est cuit mais si vous avec la main sur le champ problématique vous avez une solution. Imprimante HP ?

      1. Ce qui est dingue c’est que le code JS d’Orange est tolérant de cette erreur donc que leurs codeurs savent qu’il existe un problème:

        function evalJSON(sanitize) {
        var json = this.unfilterJSON(),
        cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        if (cx.test(json)) {
        json = json.replace(cx, function (a) {
        return ‘\\u’ + (‘0000’ + a.charCodeAt(0).toString(16)).slice(-4);
        });
        }
        try {
        if (!sanitize || json.isJSON()) return eval(‘(‘ + json + ‘)’);
        } catch (e) { }
        throw new SyntaxError(‘Badly formed JSON string: ‘ + this.inspect());
        }

      2. Vous pouvez tester en faisant un GreaseMonkey dont le listing consisterai uniquement en la ligne suivante ?

        window.NATIVE_JSON_PARSE_SUPPORT = false;

        1. Oui effectivement au vu du code, ils savent très bien que les caractères spéciaux posent problème…
          J’ai essayé de trouver le champ userClassId dans l’imprimante mais je ne peux modifier que le hostname donc je n’avance pas de ce côté là…
          Par contre si j’éteins l’imprimante, l’interface de la Livebox fonctionne, plus d’erreur JSON quand elle est pas connectée.
          GreaseMonkey, je l’ai installé sur mon FF mais vu que j’ai jamais utilisé faudrait me détailler un peu plus.

  3. // ==UserScript==
    // @name JasonLiveboxBug
    // @namespace oha
    // @include http://192.168.1.1/*
    // @version 1
    // @grant none
    // ==/UserScript==
    cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

    var JASON = JSON;
    JASON.parse = JSON.parse;
    window.JSON.parse = function(obo) { return JASON.parse(obo,function(key,val) {
    if (typeof val === "string") {
    return val.replace(cx,'');
    }
    return val;
    }); };

    1. Vous copiez cela dans un fichier orange.user.js puis, après avoir installé et activé GreaseMonkey (son icône doit être colorée), vous déposez le script orange.user.js dans la fenêtre Firefox qui doit vous prompter pour confirmer que vous voulez installer ce script.

      1. Au final j’ai trouvé une parade sans le script.
        j’ai configuré l’imprimante (via son panneaux tactile) en IPFixe, ainsi elle ne négocie pas avec la livebox par le protocole DHCP. Les champs « vendorClassID », »clientID », »userClassID » sont apparemment propre au protocole DHCP. si on configure le device de son côté en IPFIXE il n’envoie pas ces champs à la livebox (donc pas le userID qui contenait des caractères spéciaux).
        Par contre il faut rentrer aussi l’adresse mac et l’ip fixe côté livebox mais on peut laisser le DHCP de la celle-ci activé.
        Si ça peut vous être utile je peux toujours reproduire l’erreur pour tester votre script 🙂

        1. Par exemple, la page d’accueil de la livebox est-elle correcte dans le sens où vous liste-t-elle bien tout votre matériel ?
          C’était un de mes problèmes et cela est corrigé par mon script. Le bug d’Orange m’empéchait de fixer mes règles NAT/PAT. Testez mon script si vous pouvez, cela aidera peut-être d’autres utilisateurs bloqués….

          1. Oui la page d’accueil me semblait plutôt correcte. Maintenant j’ai reproduit le bug en réactivant le dhcp sur mon imprimante mais malheureusement votre script ne semble pas fonctionner. Ni sur la liste des équipements en page d’accueil ni sur la page DHCP ou NAT/PAT.

          2. En relisant votre liste de caractères de contrôle bloquants, essayez avec cette ligne dans le script. Remplacez juste la ligne en question.
            cx = /[\u0000-\u001f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

        2. Je ne suis pas un spécialiste des regexp et de l’exadécimal mais pourtant en unicode [EM] correspond à 0019, [BEL] à 0007 et [SO] à 000E. donc \u0000-\u001f ça devrait les englober…

          1. Peut-être que les espaces posent aussi problème la chaine est:
            « userClassID »: »Mfg=HP[BEL]Typ=MFP[EM]Mod=HP Officejet Pro 8620[SO]Ser=CN443B4176″
            (J’ai mis les caractères spéciaux entre crochet)

  4. // ==UserScript==
    // @name JasonLivebox
    // @namespace oha
    // @include http://192.168.1.1/*
    // @include http://livebox.*
    // @version 1.5
    // @grant none
    // ==/UserScript==

    cx = /[\u0000-\u001f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    var JASON = JSON;
    JASON.parse = JSON.parse;
    window.JSON.parse = function(obo) {
    return JASON.parse(obo.replace(cx,''),function(key,val) {
    if (typeof val === "string") {
    neu = val.replace(/Orange/gi,'Dummies');
    return neu;
    }
    return val;
    });
    };

        1. Pas d’erreurs dans la console, je supprime l’ancien et le recharge bien à chaque fois mais effectivement le script ne semble pas être chargé car j’ai essayé de glisser un petit alert(« hello »); dedans et rien ne s’est affiché…

      1. J’ai parlé trop vite:
        Sur la page d’accueil tout s’affiche bien malgrès une multitudes d’erreurs dans la console ([default] Unrecognized service event reason: device_added).
        Sur la page DHCP les adresses IP dynamiques s’affichent bien
        Par contre on ne peut pas assigner d’adresse IP fixe dans la page DHCP, j’ai deux nouvelles erreurs:
        TypeError: this.objects.Users.each is not a function
        this.objects.Users.each(function (user) {
        [Lan/Static] unable to execute objectsLoaded callback
        TypeError: this.objects.Hosts.select is not a function
        this.objects.HostDevices = this.objects.Hosts.select(function (h) {

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *