Skip to content

HTTP et Telnet : pour tester rapidement un serveur HTTP

Voir rapidement les headers d’une reponse HTTP d’un serveur web peut s’avérer très pratique, pour cela, une réponse rapide : telnet.

Le protocole HTTP répond à la RFC 2616 du W3C.

Telnet

Pour se connecter à un serveur, faire la ligne de commande suivante :

> telnet serveur num_port

par exemple :

%> telnet www.voila.fr 80

Une fois connecté, on va demander un document. On va utiliser la méthode GET. Par exemple sur la racine du site (ie / ) :

GET / HTTP/1.0 <CRLF><CRLF>

Il est important de préciser le protocole que l’on va utiliser après le document demandé (ici on demande du HTTP/1.0, ca aurait pu être du HTTP/1.1).

Il est primordial de placer 2 <CRLF> (ie des retours à la ligne) après la commande GET, pour signaler au serveur que la commande est complète.

On peut construire des requêtes plus compliquées, en enchainant les Headers, par exemple :

GET / index.html HTTP/1.0 <CRLF>Accept : text/html, image/gif <CRLF>

User-Agent : Mozilla/4.0 (compatible ; MSIE 4.0 ; Linux X11 2.2.17) <CRLF><CRLF>

Autorisation

Les méthodes d’autorisation pour accéder à certaines zone d’un serveur HTTP répondent à la RFC 2617 du W3C.

Lorsqu’une zone du serveur est protégée par cette méthode, la demande d’un document de cette zone renvoie une réponse comme suit :

HTTP/1.0 401 Authorization RequiredDate: Wed, 23 Jan 2002 15:12:30 GMT

Server: Apache/1.3.20 (Unix)  (Red-Hat/Linux) ApacheJServ/1.1.1 mod_ssl/2.8.4 OpenSSL/0.9.6

WWW-Authenticate: BASIC realm="RealmName"

Content-Type: text/html

X-MTracker-Version: v4.0 build 49.5

Expires: Thu, 01 Jan 1970 00:00:00 GMT

Last-Modified: Wed, 23 Jan 2002 15:12:30 GMT

Cache-Control: no-cache must-revalidate

Pragma: no-cache

Le Header important est WWW-Authenticate. Si l’utilisateur n’est pas déjà authentifié pour le RealmRealmName“, une fenêtre pop-up apparaitra et demandera le login/password de l’utilisateur.

Autorisation et Telnet

Pour s’authentifier en utilisant Telnet sur un serveur HTTP avec l’autorisation ’Basic’, il faut ajouter un Header “Authorization”, suivi d’une chaine encodée BASE64 composée du login et du password. La structure de cette chaine est :

login:password

Si l’on veut s’identifier comme l’utilisateur marc qui a le password antoine, on obtient l’encodage BASE64 suivant : bWFyYzphbnRvaW5l [1].

La requête à construire pourra donc être :

GET /servlet/protected/content/ HTTP/1.0 <CRLF>

Authorization: Basic bWFyYzphbnRvaW5l <CRLF><CRLF>

Note : Attention à écrire Basic et non BASIC !

[1] obtenu grâce à la commande perl suivante : %> perl -MMIME::Base64 -e ‘print encode_base64(”marc:antoine”)’

OpenOffice - Numérotation des titres

J’ai souvent des problèmes avec la numérotation des titres sous OpenOffice Writer. J’utilise logiquement les styles pour définir mes titres de paragraphes mais je ne trouvais pas pratique d’affecter la numérotation correspondante. Je passais par le menu “Format > Bullets and numbering…“.

En fait, il ne faut pas utiliser ce menu, mais “Tools > Outline numbering…“. Choisir le niveau (Level) de 1 à 10 (1-10) et affecter la numérotation désirée.

Simple, mais pas dans le bon menu je trouve. Il suffit de le savoir.

Greasemonkey et chaque site devient mien

Greasemonkey est une extension à Mozilla Firefox qui permet de définir des Javascript personnels qui ne sont appliqués qu’à certains sites. Cela permet de les personnaliser à nos besoins.
J’ai donc eu l’idée d’utiliser et tester ce plugin pour faciliter l’utilisation d’un site que je consulte régulièrement, à savoir LinuxFR. En effet, les commentaires des articles sont présentés sous forme d’une arborescence. Si la première branche d’un commentaire est assez facile à suivre, il est plus ardu de rattacher les commentaires suivants à celui auquel ils répondent.

Nom de code : PAPA

Je vais donc essayer de construire un script pour Greasemonkey qui va me permettre à partir de n’importe quel commentaire de retrouver facilement celui auquel il se rattache. Son père. Ce projet s’appellera donc provisoirement PAPA en attendant d’avoir plus d’inspiration.

Références

Pour commencer, voici quelques url qui peuvent être utiles pour faire des user scripts avec Greasemonkey :
-  « Writing User Scripts », explication rapide sur la création de scripts Greasemonkey,
-  « Gecko DOM Reference »
Une liste de User scripts alimentée par un wiki,
-  Le site UserScripts qui veut proposer un outil plus poussé pour catégoriser les différents scripts.
Une présentation en français sur le site du Journal du net dans la section développeurs.
À noter : Les utilisateurs d’Internet Explorer peuvent aussi utiliser les user scripts à l’aide de l’extension turnabout. La version 8 du navigateur Opera semble aussi pourvoir supporter les scripts utilisateurs.
À noter encore : Utiliser GreaseMonkey peut causer quelques soucis avec les pages utilisant déjà du javascript, voir ce témoignage [1].

Principes

Une fois la page d’un article de LinuxFR chargée, le script va s’éxécuter. Il va ainsi parcourir l’arbre DOM de cette page et modifier le bloc contenant le titre de chaque commentaire en ajoutant un lien “Masquer“. Ceci ne sera fait que pour les commentaires qui ne sont pas le premier fils d’un commentaire de niveau supérieur [2]. Quand on cliquera sur ce lien, tous les commentaires précédents de même niveau seront masqués. On pourra donc facilement accéder au commentaire père pour suivre le fil de discussion.
Donc en images, voici ce que cela donne. On lit le fil d’un commentaire et on arrive au bout d’une branche. Le commentaire suivant est donc une réponse à un texte qui apparait bien plus haut dans l’arborescence. Il n’est pas toujours facile à retrouver, surtout dans un arbre à trolls.

Avant masquage

En cliquant sur le lien Masquer que l’on apercoit en bas de la page je vais me retrouver positionné sur le commentaire père - pour ainsi savoir sur quoi porte la réponse suivante - et les éléments intermédiaires seront masqués, comme ceci :

Aprés masquage

En cliquant sur Afficher on revient à la normal.

Installation du user script PAPA

Si vous voulez l’utiliser, il suffit d’installer l’extension Greasemonkey, de redémarrer Mozilla Firefox [3] et de “cliquer droit” sur ce lien. Dans le menu contextuelle qui apparait, il faut choisir « Install User Script ».

Menu contextuel sur un lien {.user.js}

Le code du script

Ci-dessous le code du script que j’ai réalisé.

// ==UserScript==
// @name          LinuxFR papa
// @namespace     http://arliguy.net/papa
// @description          [en] : This user script adds action links to each comment in comments tree
//                of Linuxfr.org website in order to improve navigability. With this
//                script you are able to find easily the parent of a comment and
//                hide (or display) a part of this tree.
//
//                [fr] : Ce “user script” ajoute des liens actifs à chaque commentaire dans
//                l’arbre des commentaires du site Linuxfr.org dans le but d’améliorer l’expérience
//                de navigation. Avec ce script vous êtes capable de trouver facilement le père d’un
//                commentaire et de cacher (ou d’afficher) une partie de cet arbre.
// @include       http://linuxfr.org/*
// @exclude       http://linuxfr.org/my/
// ==/UserScript==
// Notes:
//   version 0.4 - 02/12/2005 - correction suite a modification dans le code html de LinuxFR : Le script ne
//                              s’exécutait plus. Apparement il y a eu des changements dans les pages, et le
//                              onload ne s’exécutait pas, donc le script ne pouvait pas se dérouler. J’ai donc
//                              supprimer l’attachement du script à onload.
//   version 0.3 - 17/08/2005 - ajout licence GPL
//                            - modification de la description
//                            - ajout d’une traduction en anglais
//
//   version 0.2 - 05/06/2005 - quand on clique sur “Masquer” on est positionné sur le commentaire parent
//                            - un seul lien “Masquer” ou “Afficher” est visible. En fonction de ce qui est
//                              possible pour un commentaire, soit l’un soit l’autre est visible.
//
//   version 0.1 - 04/06/2005 - premiere version.
//
//   auteur  : Bruno ARLIGUY
//
//   licence : GPL license - http://www.gnu.org/copyleft/gpl.html

(function()
{
        //Listener positionné sur chaque lien “Masquer” quand on le “clique”.
        // On va masquer le lien “Masquer”, afficher le lien “Afficher” et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les masquer
        //
        // param e : l’évènement reçu par l’objet auquel est associé ce listener
        function hideSibling(e)
        {
                //masquer le lien “masquer”
                e.target.style.display = ‘none’;
                //afficher le lien “afficher”
                e.target.nextSibling.style.display = ‘block’;
                //masquer les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == ‘UL’; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = ‘none’;
                        }
                }
        }

        //Listener positionné sur chaque lien “Afficher” quand on le “clique”.
        // On va masquer le lien “Afficher”, afficher le lien “Masquer” et ensuite
        // parcourir tous les commentaires précédents (ie previousSibling) et les afficher
        //
        // Attention : ceci va re-afficher tous les commentaires précédents de même niveau,
        // même si ils n’ont pas été cachés en activant le lien “cacher” correspondant au lien
        // “afficher” actuellement actif. Il faut donc repositionner les liens “Afficher” et “Masquer”
        // de ces commentaires, car certains pourraient être innapropriés.
        //
        // param e : l’évènement reçu par l’objet auquel est associé ce listener
        function showSibling(e)
        {
                //masquer le lien “afficher”
                e.target.style.display = ‘none’;
                //afficher le lien “masquer”
                e.target.previousSibling.style.display = ‘block’;
                //afficher les commentaires précédents
                var currentComment = e.target.parentNode.parentNode.parentNode.parentNode;
                var papaBlock      = null;
                if (currentComment)
                {
                        for (var sibling = currentComment.previousSibling; sibling.nodeName == ‘UL’; sibling = sibling.previousSibling)
                        {
                                sibling.style.display = ‘block’;
                                papaBlock = document.evaluate(”./li/h1/div”, sibling, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
                                if (papaBlock != null)
                                {
                                        papaBlock.childNodes[0].style.display = ‘block’;
                                        papaBlock.childNodes[1].style.display = ‘none’;
                                }
                        }
                }
        }

        //Construit un block (div) qui contient les liens “Masquer” et “Afficher” pour l’UL passé en paramètre.
        //
        // param ul : un objet qui doit représenter un UL correspondant à
        //            un commentaire (ie répond au xpath //ul[@class='commentsul'])
        function getPapaBlock(ul)
        {
                var namedLink  = ul.firstChild.childNodes[1];
                var parentLink = ul.parentNode.childNodes[1];
                var id         = namedLink.name;
                var div        = document.createElement(”div”);
                var aHide      = document.createElement(”a”);
                var aShow      = document.createElement(”a”);

                //
                div.setAttribute(”id”, “pn” + namedLink.name);
                div.setAttribute(”class”, “pn”);
                div.setAttribute(”style”, “float: right;”);

                //Faire pointer le lien masquant sur le commentaire parent.
                aHide.setAttribute(”href”, “#” + parentLink.name);
                aHide.setAttribute(”id”, “hide” + namedLink.name);
                aHide.setAttribute(”class”, “pn”);
                aHide.addEventListener(”click”, hideSibling, false);

                aShow.setAttribute(”href”, “#” + namedLink.name);
                aShow.setAttribute(”id”, “show” + namedLink.name);
                aShow.setAttribute(”class”, “pn”);
                aShow.setAttribute(”style”, “display: none”);
                aShow.addEventListener(”click”, showSibling, false);

                div.appendChild(aHide);
                div.appendChild(aShow);

                aHide.appendChild(document.createTextNode(”- Masquer”));
                aShow.appendChild(document.createTextNode(”+ Afficher”));

                return div;
        }

                try
                {
                        // Recupérer tous les UL de classe “commentsul”. Pour chacun, ajouter un bloc dans sa barre de titre.
                        // Ce bloc contiendra deux liens : “Masquer” et “Afficher”. Chaque lien appellera un script
                        // qui appliquera l’action correspondante (masquer ou afficher) sur tous les “previousSibling” du
                        // commentaire associé. Le lien en lui même consistera à appeler la même page en la positionnant sur :
                        //    - le lien nommé correspondant au commentaire parent si l’utilisateur a cliqué sur “Masquer”
                        //    - le lien nommé correspondant au commentaire si l’utilisateur a cliqué sur “Afficher”.
                        // les liens nommés sont ceux de la forme <a name=”580185″></a> et qui sont les “childNodes[1]” de chaque //ul[@class='commentsul'].
                        var elements = document.evaluate(”//ul[@class='commentsul']“, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
                        var uls = new Array();
                        var ul  = null;
                        //tranferer les éléments trouvés dans un tableau.
                        for (var i = 0; ul = elements.iterateNext(); i++)
                        {
                                uls[i] = ul;
                        }

                        var before = null;
                        var previous = null;
                        for (var i = 0; i < uls.length; i++)
                        {
                                previous = uls[i].previousSibling;
                                while (previous.nodeName == “#text”)
                                {
                                        previous = previous.previousSibling;
                                }

                                if (previous.nodeName == “UL”)
                                {
                                        //Selectionner le premier H1 à partir du premier enfant de cet UL. J’utilise une expression xPath car
                                        // apparement le Html de LinuxFR a tendance à évoluer. Donc un accés relatif comme avant (avec des numéros
                                        // d’index dans les enfants, par exemple uls[i].firstChild.childNodes[5]) rendait le code trop dépendant des
                                        // modifications du code.
                                        before = document.evaluate(”./h1″, uls[i].firstChild, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.firstChild;
                                        before.parentNode.insertBefore(getPapaBlock(uls[i]), before);
                                }
                        }
                }
                catch (ex)
                {
                        GM_log(ex);
                }
})();
[1] Ce n’est pas un avis négatif sur l’utilisation de GreaseMonkey, juste qu’il faut faire attention à ce que l’on fait avec
[2] désolé, je n’ai pas réussi à expliquer ceci plus simplement
[3] Oui oui, il faut arrêter FireFox - toutes les instances lancées sous le même profil - et le relancer

Cartes de références pour développeurs

Voici quelques sites qui proposent des fiches de référence pour différents outils/langages. Toujours utile à avoir sous la main :

  • Quick References Cards propose « JSP Syntax », « XSLT and XPath Quick Reference », « XSL Transformations (XSLT) 1.0 », « Apache Quick Reference Card », etc…
  • RefCards propose « Apache », « CVS », « MySQL », « HTML DOM », « CSS level 2 », « XPath », etc…
  • Peter Dickman propose sa carte de référence Java 5 et 6.

Tunneling SSH

Utiliser SSH pour faire passer différents protocoles, ce qui permet de sécuriser la communication (une sorte de VPN software)

Quand on se connecte à Internet depuis un lieu public et si ce lieu de connexion ne permet pas d’accéder à des ports particuliers d’un serveur (règles de firewall restrictives), il est possible d’utiliser un serveur intermédiaire sur lequel on a un compte utilisateur et qui fait tourner un serveur ssh. C’est ce serveur qui se connectera au serveur désiré. Cette solution va aussi permettre de chiffrer la communication entre le point d’accés et le serveur intermédiaire.

Pour réaliser cela, on va utiliser un tunnel SSH. Il faut donc que l’on ai accès au port 22 du serveur intermédiaire, mais dans 90% des cas les firewalls laissent sortir le traffic sur ce port.

Le principe

Il faut crééer une connexion ssh entre le pc client et le serveur intermédiaire. Cette connexion (le tunnel donc) connectera un port du pc client au serveur intermédiaire. Celui-ci va lire tout ce qu’il recoit depuis cette connexion et re-expédier le tout vers le serveur destinataire.

attention : sous Linux, on ne peut pas connecter le tunnel sur un port local priviligié si on n’est pas root. Il faut donc prendre un port au dessus de 2000.

Exemple

Je veux lire mes mails par un accés imap. Mon serveur imap est imap.mail.com et je l’interroge sur le port 143 [firewall ne laisse pas sortir les connexions vers le port 143 et en plus je n’ai pas confiance dans le réseau, il pourrait y avoir une surveillance et c’est un mail privé.

Je vais donc établir un tunnel SSH entre le pc que j’utilise et un serveur sur lequel j’ai un accés ssh. Ce serveur s’appelle monserveurssh.com et j’ai un compte utilisateur de login moncompte. Je vais connecter le tunnel sur le port 2000 de mon pc client, comme suit :

ssh -2NfC -L2000:imap.mail.com:143 moncompte@monserveurssh.com

Cette commande ne me connecte pas sur le serveur intermédiaire, mais me rend la main de suite grâce a l’option -f combinée avec l’option -N. L’option -2 c’est pour demander à ssh d’utiliser le protocole v2 et l’option -C c’est pour demander de compresser le tunnel.

Il ne me reste plus qu’à brancher mon client mail sur le port 2000 de localhost, et je pourrai lire mes mails, comme si j’étais connecté directement au serveur de mails.

Un détail sécurité

Quand je créé des comptes utilisateurs sur mon serveur juste pour permettre du port forwarding je ne donne pas le droit de connexion au serveur. Pour cela, dans le fichier /etc/passwd je remplace le shell du compte par /sbin/nologin. Ainsi la personne qui a ce compte peut créé des tunnels SSH mais elle ne peut pas se connecter au serveur.

Sous Windows

En utilisant Cygwin et le client ssh fourni avec, cela fonctionne très bien. Putty permet aussi d’établir des tunnels pour ceux qui sont réfractaires à la ligne de commande.

Quelques liens sur le sujet

-  Remote Desktop and SSH tunneling
-  Using ssh to Connect Between Systems, Including Running X Applications

Faire un backup avec rsync

On peut utiliser ssh pour faire un backup d’une machine distante (pratique pour conserver une copie d’un site web, en ne téléchargeant que ce qui a changé depuis le dernier backup) avec rsync

rsync -v -u -a –rsh=ssh –stats user@serveur.net:/chemin/dossier/distant/a/sauver /chemin/dossier/local

Commandes diff, patch mode d’emploi

Quelques tips pour bien utiliser la commande patch.

La commande diff

Cette commande permet de trouver les differences entre 2 fichiers. Elle vous retourne la ligne du fichier original et la ligne modifiée. Elle va nous permettre de créer le patch que nous pourrons ensuite appliquer. Il existe plusieurs types de patch. Celui qui est le plus répandu est le patch unifié car il apporte de la souplesse dans son application en permettant une certaine variation du fichier à patcher.

La commande patch

La commande patch va prendre en entré le resultat de la commande diff et va appliquer les changements sur le fichier désigné. Le fait d’avoir dans le patch la version originale et la version modifiée permet d’éviter de patcher un fichier qui n’est pas le bon, ou même de patcher un fichier déjà à jour.

Exemple :

diff -aburN --exclude=CVS* repertoire/reference/ repertoire/modifie/ > patch.diff

Cette commande crée un patch unifié. Interêt des options passées :

  • -a : traiter tout les fichiers comme du texte
  • -b : permet de ne pas tenir compte des différences sur les espaces
  • -u : faire un patch unifié
  • -r : parcourrir les sous répertoires
  • -N : permet de gérer les fichiers nouveaux
  • —exclude=CVS : permet d’exclure des fichiers ou répertoire de l’analyse.

Le patch ainsi fabriqué contient des éléments qui vont permettre à la commande patch de retrouver les fichiers à modifier à travers l’arborescense, puis de trouver les bonnes lignes, même si celles-ci ont légèrement été déplacées.

patch -p 1 < patch.diff

L’option -p N permet d’adapter l’aborescence d’origine du patch à l’arborescence que l’on est en train de traiter.

La gestion des exceptions en Java

La gestion des exceptions en Java pose parfois quelques problèmes aux développeurs. Cet article a le mérite d’expliquer certaines bonnes méthodes pour les gérer. A lire sans réserve.

Le lien : Best Practices for Exception Handling

Et un article intéressant sur la gestion des exceptions pour le traitement des erreurs de validation

Le lien : Using exception for server-side validation in JSP

Tests unitaires avec Junit et Ant

Cet article pésente comment utiliser JUnit et Ant pour automatiser les tests unitaires.

Le lien : L’article

RegExp pour valider une adresse mail

Une adresse email doit respecter la RFC822. Il y a plein de choses à vérifier, alors pourquoi ne pas déléguer ca à une RegExp - ou Expression Regulière ? Sur le lien proposé dans cette brève, vous trouverez la RegExp pour valider un email d’après la RFC822… Attention, c’est impressionnant, j’avais encore jamais vu d’expression si longue… Chapeau bas à l’auteur !

Le lien : La RegExp

Applications Java serveur nécessitant un serveur X

Comment se passer d’un serveur X pour une application java qui en veut un alors qu’elle tourne sur un serveur qui n’est pas sensé en avoir : vous me suivez ?

Des applications java peuvent avoir besoin d’un serveur X pour faire du rendu de dessin. C’est le cas par exemple en cas d’utilisation de la bibliothèque de rendu de graphiques JChart ou avec JasperReport. On aura par exemple une stacktrace du genre :

java.lang.InternalError

Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.sun.awt.X11GraphicsEnvironment::initDisplay (native)

sun.awt.X11GraphicsEnvironment::<clinit> ( X11GraphicsEnvironment.java: 134 )

java.lang.Class::forName0 (native)

java.lang.Class::forName ( Class.java: 141 )

java.awt.GraphicsEnvironment::getLocalGraphicsEnvironment ( GraphicsEnvironment.java: 62 )

net.sf.jasperreports.engine.util.JRGraphEnvInitializer::initializeGraphEnv ( JRGraphEnvInitializer.java: 58 )

...

Cependant, sous les serveurs de production, on lance rarement un serveur X. Il faut donc utiliser soit :
-  un serveur virtuel xvfb
-  l’option -Djava.awt.headless=true [1] si on utilise Java 1.4 ou supérieur

PS : Cette astuce a été trouvée dans la doc de jCharts

[1] ou dans le code avec System.setProperty(”java.awt.headless”,”true”) ;

Manipuler le dump d’une base PostgreSQL

Pour toutes les manipumations qui suivent, il faut être connecté en tant qu’utilisateur postgres :

%> su - postgres

Dumper une base

La commande pg_dump permet d’afficher la structure d’une base nom_de_la_base ainsi que ses données sur la sortie standard.

En utilisant une redirection de la sortie standard vers un fichier, on réalise donc une copie de la base.

%> pg_dump -D {nom_de_la_base} > {nom_du_fichier.dump}

Recréer une base à partir d’un dump

S’il y a besoin de restaurer une base, ou d’en construire une nouvelle à partir d’une base existante, il faut utiliser un fichier de dump.

Dans un premier temps, effacer la base existante si besoin :

%> dropdb {nom_de_la_base}

Dans un deuxième temps, recréer ou créer la base :

%> createdb {nom_de_la_base}

Dans un troisième temps, importer dans la base le fichier de dump :

%> psql -e {nom_de_la_base} < {nom_du_fichier.dump}

Pour importer le dump, on peut aussi le faire en étant connecté à la base (utile lorsque le postmaster demande une authentification par mot de passe [1]) en utilisant la commande psql :

nom_de_la_base=# \i {nom_du_fichier.dump}

Ainsi la base est créée et initialisée avec la structure et les données déclarées dans le fichier de dump. Celui-ci étant en mode texte il est trés facile de le modifier avec un éditeur.

PS : Dans tous les cas, pour que cela fonctionne, il faut que le serveur de base de donnés PostgreSQL fonctionne sur la machine. C’est une erreur courante que d’oublier de le démarrer.

[1] car dans ce cas là, on ne peut pas faire la redirection de l’entrée standart