Cette page présente un petit exemple de CGI fait en Python.

L'exemple choisi ici est un outil de tests réseau à distance réalisé à l'occasion d'un problème de routage chez le FAI qu'il ne constatait pas depuis son propre réseau.

Cet exemple montre comment faire un CGI rapidement pour un besoin ponctuel, en Python pur sans autre dépendance (pas de Django ou autre Pylons ici).

Fichier /usr/lib/cgi-bin/network-test.py :

   1 #!/usr/bin/env python
   2 # -*- coding: utf-8 -*-
   3 """
   4 Network test tools (CGI)
   5 
   6 Copyright ©2009  Agence universitaire de la Francophonie
   7 Licence: GNU General Public License, version 2
   8 Author: Progfou <jean-christophe.andre@auf.org>
   9 Creation: 2009-03-21
  10 
  11 Debian-Depends: mtr-tiny iputils-ping dnsutils
  12 Filename: /usr/lib/cgi-bin/network-test.py (chmod +x)
  13 Usage: http://localhost/cgi-bin/network-test.py
  14 """
  15 
  16 import os
  17 import cgi
  18 import commands
  19 
  20 ACTIONS = {
  21   'mtr': u"mtr -rc%(count)s %(addr)s",
  22   'ping': u"ping -nc%(count)s %(addr)s",
  23   'host': u"host %(addr)s",
  24   'dig': u"dig any %(addr)s",
  25   'dig +trace': u"dig any +trace %(addr)s",
  26   'dig +nssearch': u"dig +nssearch %(addr)s",
  27   'source': u"cat %(__file__)s",
  28 }
  29 
  30 COUNT = 3
  31 
  32 HTML = u"""<html>
  33 <head>
  34   <title>%(title)s</title>
  35   <style type="text/css">
  36 body { margin: 0; padding: 0; }
  37 h1 { margin: 0; padding: 2pt; background: red; color: yellow; text-align: center; font-family: sans; }
  38 fieldset { margin: 5pt; padding: 5pt; background: #E0E0FF; }
  39 fieldset legend { margin: 5pt; padding: 2pt; background: #E0E0FF; border: 1.5pt groove lightgrey; font-weight: bold; }
  40 fieldset pre { margin: 0pt; padding: 2pt; background: white; width: 80em; border: 2pt inset lightgrey; }
  41 span.error { font-weight: bold; color: red; }
  42 div.signature { margin: 5pt; color: grey; text-align: right; font-size: 70%%; }
  43   </style>
  44 </head>
  45 <body>
  46   <h1>%(title)s</h1>
  47   <form>
  48 %(content)s
  49   </form>
  50 %(signature)s
  51 </body>
  52 </html>
  53 """
  54 
  55 TITLE = u"""Network test tools @ %(HTTP_HOST)s[%(SERVER_ADDR)s]"""
  56 
  57 REQUEST = u"""<fieldset>
  58   <legend>Request</legend>
  59   <label>Hostname or IP address:</label>
  60   <input name="addr" type="text" size="16" maxwidth="16" value="%(addr)s" />
  61   <input name="action" type="submit" value="mtr" />
  62   <input name="action" type="submit" value="ping" />
  63   <input name="action" type="submit" value="host" />
  64   <input name="action" type="submit" value="dig" />
  65   <input name="action" type="submit" value="dig +trace" />
  66   <input name="action" type="submit" value="dig +nssearch" />
  67   <br />
  68   <br />
  69   (You'll have to wait about %(count)s seconds after clic for result to display.)
  70 </fieldset>
  71 """
  72 
  73 ERROR = u"""<fieldset>
  74   <legend>Error</legend>
  75   <span class="error">%(content)s</span>
  76 </fieldset>
  77 """
  78 
  79 RESULT = u"""<fieldset>
  80   <legend>Result%(legend_ext)s</legend>
  81   <pre>%(content)s</pre>
  82 </fieldset>
  83 """
  84 
  85 SIGNATURE = u"""<div class="signature">
  86 Copyright&nbsp;©2009&nbsp;&nbsp;Agence universitaire de la Francophonie<br />
  87 <a href="http://www.auf.org/regions/asie-pacifique/">http://www.auf.org/regions/asie-pacifique/</a><br />
  88 <span style="font-size: 70%%">(<a href="?action=source">view this script source</a>)</span>
  89 </div>
  90 """
  91 
  92 if __name__ == "__main__":
  93     query_string = cgi.parse_qs(os.environ['QUERY_STRING'])
  94     addr = query_string.get('addr', ["www.auf.org"])[0]
  95     count = query_string.get('count', [COUNT])[0]
  96     result_legend_ext = ""
  97     error = None
  98     result = None
  99 
 100     # check URL parameters
 101     if not addr.replace('.','').replace('-','').isalnum():
 102         error = u"Invalid address!"
 103         addr = "invalid"
 104     elif type(count) == str and not count.isdigit():
 105         error = u"Invalid count!"
 106         count = COUNT
 107     else:
 108         # process request
 109         action = query_string.get('action', [None])[0]
 110         if action in ACTIONS:
 111             command = (ACTIONS[action] % locals()).encode('utf-8')
 112             (status, result) = commands.getstatusoutput(command)
 113             result = result.decode('utf-8', 'ignore')
 114             result_legend_ext = u" for `%s`" % command
 115         elif action is not None:
 116             error = u"Invalid action!"
 117 
 118     # display result
 119     print u"Content-Type: text/html; charset=utf-8\n"
 120     #cgi.print_environ()
 121     title = TITLE % os.environ
 122     content = REQUEST % locals()
 123     if error is not None:
 124         content += ERROR % {'content': cgi.escape(error)}
 125     if result is not None:
 126         content += RESULT % {'content': cgi.escape(result),
 127                              'legend_ext': result_legend_ext}
 128     signature = SIGNATURE % locals()
 129     print (HTML % locals()).encode('utf-8')

Exemple d'utilisation : http://smtp.vn.auf.org/cgi-bin/network-test.py