Petit serveur web vite fait avec bash
Par Yves le lundi 13 octobre 2014, 19:08 - Lien permanent
Vous est-il déjà arrivé de vouloir partager quelques fichiers avec quelqu’un ou avec un autre appareil (un smartphone par exemple…) et d’être ennuyé parce que les solutions simples (clé USB, partage réseau…) ne sont à ce moment-là pas disponibles ? N’aurait-il pas été bienvenu d’avoir accès à un serveur web instantané permettant de partager le répertoire courant ?
Si ces fichiers sont sur une machine de type Unix ou Linux, disposant d’un shell bash et de la commande socat, alors un simple script de quelques lignes peut faire l’affaire !
Dans sa forme la plus simple, si vous êtes prêts à taper l’URL à télécharger à la main, le script minimal suivant peut suffire:
#!/bin/bash dec() { eval printf %s \$\'$(sed 's#'\''#%27#g;s#\\#\\\\#g;s#%#\\x#g')\'; } if [ "$1" != '-' ]; then self="$(cd "$(dirname "$0")" &>/dev/null && pwd)/$(basename "$0")" cd "${1:-.}" && exec socat TCP-LISTEN:${2:-8080},reuseaddr,fork exec:"$self -" fi request=".$(sed -n '/^GET /{s/^GET \(.*\) HTTP.*/\1/p;q}' | dec)" printf 'HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\nContent-Length: %d\r\n\r\n' "$(stat -c %s "$request")" cat "$request"
Ce script se lance en donnant optionnellement en paramètre le chemin à partager (chemin courant par défaut) et le port (8080 par défaut).
Par exemple, vous pourriez lancer ce script sans aucun paramètre depuis votre répertoire personnel, puis taper l’adresse suivante dans le navigateur : http://votre_pc:8080/.bash_profile, pour récupérer le fichier ~/.bash_profile depuis une autre machine.
Personnellement, puisque je ne vais que rarement saisir ce script de mémoire, mais plutôt l’avoir avec moi pour quand j’en ai besoin, je préfère la version plus complète, qui me permet de naviguer dans l’arborescence plutôt que de saisir les adresses à la main :
#!/bin/bash dec() { eval printf %s \$\'$(sed 's#'\''#%27#g;s#\\#\\\\#g;s#%#\\x#g')\'; } enc() { sed 's#&#\&#g;s#<#\<#g;s#>#\>#g;s#\"#\"#g' <<<"$1"; } if [ "$1" != '-' ]; then self="$(cd "$(dirname "$0")" &>/dev/null && pwd)/$(basename "$0")" cd "${1:-.}" && exec socat TCP-LISTEN:${2:-8080},reuseaddr,fork exec:"$self -" || exit 1 fi request=".$(sed -n '/^GET /{s/^GET \(.*\) HTTP.*/\1/p;q}' | dec)" order=$(grep -o '\?[0-9][nd]$' <<<"$request") order=${order:1} request="${request%\?[0-9]?}" if [ ! -e "$request" ]; then status='404 Not Found' elif [ ! -r "$request" ]; then status='403 Forbidden' elif [ -f "$request" ]; then status='200 OK' type=application/octet-stream size=$(stat -c %s "$request") elif [ -d "$request" ]; then status='200 OK' type=text/html output=$(cat <<-END <!doctype html> <html><head> <meta charset="utf-8"> <title>$(enc "${request:1}")</title> </head><body><table><thead> <th scope=col><a href="?1d">Type</a></th><th scope=col><a href="?2d">Mode</a></th> <th scope=col><a href="?3d">User</a></th><th scope=col><a href="?4d">Group</a></th> <th scope=col><a href="?5n">Bytes</a></th><th scope=col><a href="?6d">Last modification</a></th> <th scope=col><a href="?7d">Name</a></th> </thead><tbody> $( find "$PWD/${request:2}" -maxdepth 1 -printf '%Y\t%M\t%u\t%g\t%s\t%T+\t%P\n' \ | sort -t$'\t' -k${order:-7d} | while IFS=$'\t' read t m u g s d n; do [ -n "$n" ] && l="${request%/}/$n" || { l="${request%/?*}/"; m=; u=; g=; s=; d=; } printf ' <tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td><a href="%s">%s</a></td></tr>\n' \ "$t" "$m" "$(enc "$u")" "$(enc "$g")" "$s" "$d" "$(enc "${l:1}${order:+?$order}")" "$(enc "${n:-..}")" done ) </tbody></table></body></html> END ) else status='403 Forbidden' fi type=${type:-text/plain} [ -z "$size" ] && output=${output:-$status ${request:1}} size=${size:-${#output}} printf 'HTTP/1.0 %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s' "$status" "$type" "$size" "$output" [ -z "$output" ] && cat "$request"
Ce script s’exécute de la même manière que le précédent. Il permet en revanche de voir le contenu d’un répertoire et de se déplacer dans l’arborescence, et surtout de télécharger des fichiers simplement en cliquant dessus. Ce script permet en outre de trier l’affichage selon le critère de son choix (nom, taille…). Enfin, il gère les cas d’erreur (accès interdit, fichier non trouvé).
Le style d’écriture est un peu moche (effets de bord, pas d’explications…). J’ai voulu faire (très) court. Si vous avez des questions sur le fonctionnement, écrivez-les dans les commentaires !