SCOP d'ingénieurs experts du logiciel libre depuis 2004
+33 1 70 61 60 16

Débugger vos requêtes HTTP en une ligne plutôt que mille

Nous vous proposons une approche minimaliste permettant de debugger simplement non pas une réponse HTTP mais la requête elle-même.
Bad http request ! Bad !

Notre prochain webinar

Nous gérons pour nos clients des centaines de plateformes, il nous arrive donc souvent de devoir assister au débogage ce qui peut impliquer de valider si les réponses d'un site/API sont bien cohérentes avec les requêtes qu'il reçoit.

Si le gros du travail de débogage se fait du côté de la réponse, il est parfois utile de vérifier en premier lieu que la requête est correctement formée.

Dans notre cas on cherchait à débugger une réponse passant par une série de proxies (Apache et Nginx), et on voulait vérifier que différents éléments étaient bien transmis de proxy en proxy (headers d'authentification, URI, paramètres, etc.) dont certains ne se retrouvent pas dans les logs du serveur HTTP.

Tout ce travail de débogage peut aussi être utile au développeur qui travaille sur son API (pour les mêmes raisons que nous) ou avec une API tiers pour vérifier que les appels partants de son code sont bien formés selon les spécifications de cette API.

Voyons ensemble comment debugger nos appels via un serveur qui répondra à chaque requête son contenu (on l'appellera "echo").

TL;DR

L'idée de départ de ce post est de simplifier cet outil qui s'est trouvé très utile lors d'une séance de debug: Docker http/https echo.

En une ligne plutôt que mille :

print_r($_SERVER); 

Le kit de débogage

Pour une mise en place rapide de ce kit de débogage, partons de nos images docker. Voici l'arborescence nécessaire :

|____docker-compose.yml
                |____echo
                | |____Dockerfile
                | |____echo.php
                |____nginx-echo.conf

On y trouve le 'docker-compose.yml' contenant simplement un conteneur nginx (qui servira sur 'localhost:8000') et un conteneur PHP :

services:
                  nginx:
                    image: bearstech/nginx
                    container_name: echo-nginx
                    restart: unless-stopped
                    volumes:
                      - ./nginx-echo.conf:/etc/nginx/conf.d/default.conf
                    ports:
                      - 127.0.0.1:8000:80
                  php:
                    build: ./echo
                    container_name: echo-php
                    restart: unless-stopped

La configuration nginx utilisée est minimale et fait simplement appel au conteneur PHP en utilisant toujours le même script :

server {
                   listen         80;
                   root /var/www/default/;
                   location / {
                      include fastcgi_params;
                      fastcgi_pass echo-php:9000;
                      fastcgi_param SCRIPT_FILENAME /var/www/default/echo.php;
                   }
                }

L'image PHP est buildée depuis le dossier 'echo' qui contient le Dockerfile nécessaire :

FROM bearstech/php:8.2
                ARG uid=1001
                RUN useradd echo --uid $uid --shell /bin/bash --home /var/www
                COPY echo.php /var/www/default/echo.php
                WORKDIR /var/www
                RUN chown -R $uid.$uid /var/www
                USER echo

ainsi que le fichier echo.php :

<?php print('toto'); ?>

Avec cela en place, on lance simplement :

$ docker-compose up --build

Nous avons un serveur d'echo qui affiche tous les headers (HTTP_*), le site requêté (HTTP_HOST), l'URI (REQUEST_URI) et ses paramètres (QUERY_STRING), etc.


                        $ curl -H 'My-Super-Header: my-header-value' "127.0.0.1:8000/my-uri?my-param=my-param-value"
                                Array
                                (
                                    [HOSTNAME] =&gt; e2880d12e72e
                                    [PHP_VERSION] =&gt; 8.2
                                    [PWD] =&gt; /var/www
                                    [HOME] =&gt; /var/www
                                    [LANG] =&gt; en_US.UTF-8
                                    [SHLVL] =&gt; 0
                                    [PATH] =&gt; /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
                                    [DEBIAN_FRONTEND] =&gt; noninteractive
                                    [USER] =&gt; echo
                                    [HTTP_MY_SUPER_HEADER] =&gt; my-header-value
                                    [HTTP_ACCEPT] =&gt; */*
                                    [HTTP_USER_AGENT] =&gt; curl/8.4.0
                                    [HTTP_HOST] =&gt; 127.0.0.1:8000
                                    [SCRIPT_FILENAME] =&gt; /var/www/default/echo.php
                                    [REDIRECT_STATUS] =&gt; 200
                                    [SERVER_NAME] =&gt; 
                                    [SERVER_PORT] =&gt; 80
                                    [SERVER_ADDR] =&gt; 172.21.0.3
                                    [REMOTE_USER] =&gt; 
                                    [REMOTE_PORT] =&gt; 39722
                                    [REMOTE_ADDR] =&gt; 172.21.0.1
                                    [SERVER_SOFTWARE] =&gt; nginx/1.18.0
                                    [GATEWAY_INTERFACE] =&gt; CGI/1.1
                                    [REQUEST_SCHEME] =&gt; http
                                    [SERVER_PROTOCOL] =&gt; HTTP/1.1
                                    [DOCUMENT_ROOT] =&gt; /var/www/default
                                    [DOCUMENT_URI] =&gt; /my-uri
                                    [REQUEST_URI] =&gt; /my-uri?my-param=my-param-value
                                    [SCRIPT_NAME] =&gt; /my-uri
                                    [CONTENT_LENGTH] =&gt; 
                                    [CONTENT_TYPE] =&gt; 
                                    [REQUEST_METHOD] =&gt; GET
                                    [QUERY_STRING] =&gt; my-param=my-param-value
                                    [FCGI_ROLE] =&gt; RESPONDER
                                    [PHP_SELF] =&gt; /my-uri
                                    [REQUEST_TIME_FLOAT] =&gt; 1700665959.4737
                                    [REQUEST_TIME] =&gt; 1700665959
                                )

Voilà, vous avez désormais un serveur répondant sur 'localhost:8000' et qui répète toutes les requêtes entrantes sur votre serveur.

Happy debug!


Maurice Audin

Inscrivez-vous à notre newsletter

Mieux comprendre le monde du DevOps et de l'administration système.

Abonnez-vous à notre newsletter

Hébergement & Infogérance

  • ✓ Service Astreinte 24h/7j/365
  • ✓ Supervision, monitoring & Alertes
  • ✓ Mises à jour en continu
  • ✓ Certificat SSL letsencrypt
  • ✓ Hébergement dédié sécurisé en France
  • ✓ Backup vers datacenter distant
Découvrir notre offre

Expertise Technologique

Notre équipe possède une vaste expertise technologique.