Format des cookies sur instinctive.eu

Sur ce site, je propose d'enregistrer des informations dans un cookie pour préremplir le formulaire de commentaire.

Comme on entend tout et n'importe quoi sur les cookies, et comme ça reste des données qui sont chez vous mais son mon contrôle, il me semble que c'est la moindre des choses d'essayer de vous expliquer en quoi consistent ces informations.

Le code source du moteur du présent site est publié sous une licence permissive, et est disponible aussi bien sur github que sur mon fossil personnel, mais je ne vous en imposerai pas la lecture si vous voulez juste savoir ce que je dépose chez vous, fût-ce numériquement.

En résumé, j'enregistre dans un cookie nommé c_info ce que vous avez rempli dans les champs nom, adresse e-mail, site web, et le format de commentaire choisi (historique ou markdown). J'applique plusieurs transformations à ces données pour faire en sorte qu'elles prennent le moins de place possible. Lorsque vous chargez une page de mon site avec un formulaire de commentaire, ces informations sont décodées pour préremplir le formulaire.

La toute première lettre du cookie identifie la suite de transformations, pour que si un jour j'en trouve une autre plus efficace, je puisse distinguer les cookies dans l'ancien format de ceux au nouveau format. Donc pour le moment, comme il n'existe qu'un seul format, tous les cookies commencent par A.

Je vais prendre comme exemple un cookie pour moi : je rentre comme nom « Natacha », pas d'adresse e-mail parce que je ne m'écris jamais à moi-même, le site web « //instinctive.eu/ », et les commentaires au format Markdown. Je me retrouve avec un cookie qui contient la chaîne de caractères « AB+OBEFaNEucVVrOFrHFP3CQCUV ».

Sérialisation

Comme il y a quatre morceaux d'information à faire rentrer dans un seul cookie, la première étape est de les combiner en une seule chaîne de caractères, de sorte qu'il soit possible ensuite de retrouver les quatre morceaux.

J'utilise des petits noms internes pour identifier les formats de commentaires : legacy-comment pour les commentaires au format historique, et comment-markdown pour les commentaires au format markdown. Ce sont des identifiants que j'utilise déjà à d'autres endroits du code, ça a été plus pratique de les reprendre directement.

Les quatre chaines de caractères sont combinées en une seule en en faisant une S-expression. En clair, s'il n'y a que des lettres et des chiffres et des caractères « gentils », je les écrits à la suite les uns des autres, séparés par des espaces. S'il y a des espaces ou de la ponctuation simple, je mets des guillemets (") autour. S'il y a trop de bizarreries dedans, je mets le nombre d'octets, suivi d'un double-point, suivi directement du contenu.

Pour gagner de la place, je ne mets pas d'espace à la fin, et je ne mets pas une chaîne vide à la fin, autant ne rien mettre et la laisser vide. Et je les mets dans l'ordre suivant : d'abord le petit nom du format de commentaire, puis le nom, puis l'adresse e-mail, et enfin le site.

Dans mon exemple, ça donne :

comment-markdown Natacha ""//instinctive.eu/

Compression Smaz

Une fois toutes les données rassemblées dans une seule chaîne de caractère, on se retrouve avec quelque chose qui prend pas mal de place, et qui peut contenir n'importe quoi, ce qui n'est pas forcément génial.

Pour assainir la communication et en même temps compresser les données, j'utilise une variante personnelle de l'algorithme Smaz, qui a le mérite d'être simple et efficace sur ce type de données. Pour ceux qui connaissent, je l'ai juste appliqué à des symboles en base-64 au lieu d'octets.

Pour ceux qui ne connaissent pas, c'est plus facile de regarder dans le sens de la décompression, et de se dire qu'en faisant l'inverse on peut compresser.

La compression se fait au moyen d'un dictionnaire fixe : la plupart des symboles représentent une ou plusieurs lettres, et pour décompresser il suffit de les remplacer par les lettres que chacun représente. Par exemple, dans mon cookie, après le A qui indique le format, il y a un B, qui signifie à lui tout seul comment-markdown, qui est bien le début ce que je voulais compresser à la fin de la section précédente.

Voici le dictionnaire :

Symbole Valeur Signification
A 0 "legacy-comment "
B 1 "comment-markdown "
C 2 "e"
D 3 "o"
E 4 "a"
F 5 "t"
G 6 "m"
H 7 "c"
I 8 "n"
J 9 " "
K 10 "r"
L 11 "l"
M 12 "g"
N 13 "h"
O 14 "s"
P 15 "i"
Q 16 "."
R 17 "om"
S 18 "p"
T 19 "-"
U 20 "u"
V 21 "/"
W 22 "com"
X 23 "y"
Y 24 "en"
Z 25 "le"
a 26 "ac"
b 27 "f"
c 28 "\""
d 29 "@"
e 30 "d"
f 31 "ma"
g 32 "b"
h 33 "fr"
i 34 "ro"
j 35 "ou"
k 36 "://"
l 37 "http"
m 38 "blog"
n 39 "gmail"
o 40 "www"
p 41 ".fr"
q 42 "k"
r 43 "in"
s 44 "ri"
t 45 "or"
u 46 " \""
v 47 "z"
w 48 "on"
x 49 "an"
y 50 "w"
z 51 "net"
0 52 "x"
1 53 "j"
2 54 "re"
3 55 "v"
4 56 "ee"
5 57 "ch"
6 58 "er"
7 59 "is"
8 60 "_"
9 61 spécial
+ 62 spécial
/ 63 spécial

Comme tout n'est pas dans le dictionnaire, il y a en plus des symboles spéciaux pour représenter ce qui n'y est pas. Dans mon cookie, après le format de commentaire se trouve mon nom, qui commence par une majuscule, alors qu'il n'y a aucune majuscule dans le dictionnaire.

La façon habituelle de sortir un tas d'octets arbitraire en une suite de symboles base-64 est de faire des groupes de trois octets, ce qui fait 24 bits, et les redécouper en quatre symboles base-64, au moyen des valeurs numériques que j'ai données dans le tableau.

Il se trouve que par mégarde, j'ai fait un redécoupage petit-boutiste, c'est-à-dire que le premier symbole base-64 correspond au six bits de moindre poids dans le premier octet, alors que traditionnellement on le fait dans l'autre sens, en y mettant les six bits de poids fort. Comme je m'en suis rendue compte après avoir écrit à la main tous les cas de test, je n'ai pas eu le courage de le corriger.

Donc lorsqu'il y a un nombre multiple de trois d'octets qu'on ne trouve pas dans le dictionnaire, je le marque avec le caractère / suivi du nombre de blocs moins un (parce que ça ne sert à rien d'avoir zéro bloc), suivi des blocs en question.

Par exemple, les trois lettres ABC correspondent aux nombres 65, 66, et 67, c'est-à-dire en binaire petit-boutiste 1000 0010, 0100 0010, et 1100 0010, ce qui est redécoupé en 100000, 100100, 001011, 000010, c'est-à-dire 1, 9, 52, et 16. Et ça correspond aux symboles BJ0Q. Avec l'indicateur qu'il s'agit d'un seul bloc de trois octets, on obtient /ABJ0Q. Vous comprenez maintenant pourquoi je ne voulais pas refaire tout ça juste pour écrire le binaire dans l'autre sens ?

Ensuite il y a la question des séquences d'octets qui ne sont pas multiples de trois, c'est-à-dire lorsqu'on n'arrive pas à remplir un bloc. La méthode traditionnelle est d'ajouter du padding, c'est-à-dire des octets qui ne servent à rien pour compléter le bloc. Étant donné la place que ça gaspille, j'ai préféré faire autrement.

Lorsqu'on n'a qu'un seul octet en trop, il faut de toute façon deux symboles base-64 pour couvrir tous les huit bits. Mais deux symboles base-64, ça fait douze bits, on pourrait trouver une utilité aux quatre bits restants. Genre indiquer le nombre de blocs entiers qui suivent. Et le tout est précédé du symbole + pour indiquer que c'est 3n+1 bits.

Par exemple, le N tout seul dans mon cookie, il a la valeur 78, soit 0111 0010, toujours en binaire petit-boutiste, donc 011100 et 10???? en base-64. Tout seul, il n'y a pas de bloc supplémentaire, les points d'interrogation sont des zéros, et on finit avec +OB. Et pour encoder NABC, c'est la même chose mais avec un bloc de plus, le B devient F, et on retrouve le bloc précédent, pour un total +OFBJ0Q.

Ça ne compresse pas vraiment, on est d'accord, mais ça reste mieux que le « vrai » base-64 pour faire rentrer tout ça dans des caractères civilisés.

Lorsqu'il y des blocs entiers et deux octets qui restent, c'est le même principe, avec le symbole 9 pour le marquer, trois symboles base-64 qui encodent les deux octets et deux bits pour le nombre de blocs entiers qui suivent. Par exemple AB devient ainsi 9BJE.

On se rend bien compte que tout ça ne compresse pas vraiment, parce que ça prend nettement plus de place à l'arrivée. Le principe du système est d'espérer que les éléments du dictionnaire sont suffisamment fréquents pour compenser.

Voici le résultat du décodage de mon cookie (pour rappel AB+OBEFaNEucVVrOFrHFP3CQCUV), qui illustre finalement assez peu de fonctionnalités de ce système :

Cookie Décodage
A Système d'encodage décrit ici
B comment-markdown
+ bloc partiel d'un octet
OB N et aucun bloc complet ensuite
E a
F t
a ac
N h
E a
u espace "
c "
V /
V /
r in
O s
F t
r in
H c
F t
P i
3 v
C e
Q .
C e
U u
V /

À partir de là, il me semble qu'on peut assez facilement imaginer comment construire le cookie, et peut-être même entrevoir les difficultés pratiques peu intéressantes pour le faire effectivement.

Commentaires

Pas de commentaire pour le moment.

Poster un commentaire

Mise en forme historique : pour mettre en valeur un mot ou un groupe de mot, tapez une étoile de part et d'autre, sans mettre d'espace entre l'étoile et le mot, comme ceci : *mise en valeur*. Pour insérer un lien, mettez le entre crochets, comme ceci : [http://instinctive.eu/].

Mise en forme markdown : voir le guide détaillé, en résumé c'est le Markdown traditionnel, sans HTML ni titres, mais avec les tables PHP-Markdown-Extra.

Attention : les balises HTML entrées dans les commentaires seront affichées telles quelles, et non pas interprétées.

Autour de cette page

 

Autour de cet article

  • Publié le 4 juillet 2017 à 11h49
  • Pas de commentaire

Derniers commentaires

Site-level navigation and features

 

Instinctive.eu

Contact

Sections

Validation

Copyright © 2008-2017 Natacha Kerensikova

Butterfly images are copyright © 2008 Shoofly