Guest User

webserver.py

a guest
Oct 22nd, 2017
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.64 KB | None | 0 0
  1. #!/usr/bin/env python2.7
  2. # -*- coding: utf-8 -*-
  3.  
  4. import argparse
  5. import HTTPRequestHandler
  6. import BaseHTTPServer
  7. import logging
  8. import os
  9. import sys
  10.  
  11. def make_request_handler_class(opts):
  12.     MyHTTPRequestHandler = HTTPRequestHandler
  13.     MyHTTPRequestHandler.m_opts = opts
  14.    
  15.     return MyHTTPRequestHandler
  16.    
  17.  
  18. def make_http_handler_class(opts, localHTTPRequestHandler):
  19.     '''
  20.    Factory to make the request handler and add arguments to it.
  21.  
  22.    It exists to allow the handler to access the opts.path variable
  23.    locally.
  24.    '''
  25.     class MyHTTPHandlerClass(BaseHTTPServer.BaseHTTPRequestHandler):
  26.  
  27.         m_opts = opts
  28.  
  29.         m_HTTPRequestHandler = localHTTPRequestHandler
  30.  
  31.         def do_HEAD(self):
  32.             '''
  33.            Handle a HEAD request.
  34.            '''
  35.             logging.debug('HEADER %s' % (self.path))
  36.             self.send_response(200)
  37.             self.send_header('Content-type', 'text/html')
  38.             self.end_headers()
  39.  
  40.         def do_GET(self):
  41.             MyHTTPHandlerClass.m_HTTPRequestHandler.do_GET(self)
  42.  
  43.     return MyHTTPHandlerClass
  44.  
  45.  
  46. def err(msg):
  47.     '''
  48.    Report an error message and exit.
  49.    '''
  50.     print('ERROR: %s' % (msg))
  51.     sys.exit(1)
  52.  
  53.  
  54. def getopts():
  55.     '''
  56.    Get the command line options.
  57.    '''
  58.  
  59.     # Get the help from the module documentation.
  60.     this = os.path.basename(sys.argv[0])
  61.     description = ('description:%s' % '\n  '.join(__doc__.split('\n')))
  62.     epilog = ' '
  63.     rawd = argparse.RawDescriptionHelpFormatter
  64.     parser = argparse.ArgumentParser(formatter_class=rawd,
  65.                                      description=description,
  66.                                      epilog=epilog)
  67.  
  68.     parser.add_argument('-d', '--daemonize',
  69.                         action='store',
  70.                         type=str,
  71.                         default='.',
  72.                         metavar='DIR',
  73.                         help='daemonize this process, store the 3 run files (.log, .err, .pid) in DIR (default "%(default)s")')
  74.  
  75.     parser.add_argument('-H', '--host',
  76.                         action='store',
  77.                         type=str,
  78.                         default='localhost',
  79.                         help='hostname, default=%(default)s')
  80.  
  81.     parser.add_argument('-l', '--level',
  82.                         action='store',
  83.                         type=str,
  84.                         default='info',
  85.                         choices=['notset', 'debug', 'info', 'warning', 'error', 'critical',],
  86.                         help='define the logging level, the default is %(default)s')
  87.  
  88.     parser.add_argument('--no-dirlist',
  89.                         action='store_true',
  90.                         help='disable directory listings')
  91.  
  92.     parser.add_argument('-p', '--port',
  93.                         action='store',
  94.                         type=int,
  95.                         default=8080,
  96.                         help='port, default=%(default)s')
  97.  
  98.     parser.add_argument('-r', '--rootdir',
  99.                         action='store',
  100.                         type=str,
  101.                         default=os.path.abspath('.'),
  102.                         help='web directory root that contains the HTML/CSS/JS files %(default)s')
  103.  
  104.     parser.add_argument('-v', '--verbose',
  105.                         action='count',
  106.                         help='level of verbosity')
  107.  
  108.     parser.add_argument('-V', '--version',
  109.                         action='version',
  110.                         version='%(prog)s - v' + VERSION)
  111.  
  112.     opts = parser.parse_args()
  113.     opts.rootdir = os.path.abspath(opts.rootdir)
  114.     if not os.path.isdir(opts.rootdir):
  115.         err('Root directory does not exist: ' + opts.rootdir)
  116.     if opts.port < 1 or opts.port > 65535:
  117.         err('Port is out of range [1..65535]: %d' % (opts.port))
  118.     return opts
  119.  
  120.  
  121. def httpd(opts):
  122.     '''
  123.    HTTP server
  124.    '''
  125.     RequestHandlerClass = make_request_handler_class(opts)
  126.    
  127.     HTTPHandlerClass = make_http_handler_class(opts, RequestHandlerClass)
  128.     server = BaseHTTPServer.HTTPServer((opts.host, opts.port), HTTPHandlerClass)
  129.     logging.info('Server starting %s:%s (level=%s)' % (opts.host, opts.port, opts.level))
  130.     try:
  131.         server.serve_forever()
  132.     except KeyboardInterrupt:
  133.         pass
  134.     server.server_close()
  135.     logging.info('Server stopping %s:%s' % (opts.host, opts.port))
  136.  
  137.  
  138. def get_logging_level(opts):
  139.     '''
  140.    Get the logging levels specified on the command line.
  141.    The level can only be set once.
  142.    '''
  143.     if opts.level == 'notset':
  144.         return logging.NOTSET
  145.     elif opts.level == 'debug':
  146.         return logging.DEBUG
  147.     elif opts.level == 'info':
  148.         return logging.INFO
  149.     elif opts.level == 'warning':
  150.         return logging.WARNING
  151.     elif opts.level == 'error':
  152.         return logging.ERROR
  153.     elif opts.level == 'critical':
  154.         return logging.CRITICAL
  155.  
  156.  
  157. def daemonize(opts):
  158.     '''
  159.    Daemonize this process.
  160.  
  161.    CITATION: http://stackoverflow.com/questions/115974/what-would-be-the-simplest-way-to-daemonize-a-python-script-in-linux
  162.    '''
  163.     if os.path.exists(opts.daemonize) is False:
  164.         err('directory does not exist: ' + opts.daemonize)
  165.  
  166.     if os.path.isdir(opts.daemonize) is False:
  167.         err('not a directory: ' + opts.daemonize)
  168.  
  169.     bname = 'webserver-%s-%d' % (opts.host, opts.port)
  170.     outfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.log'))
  171.     errfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.err'))
  172.     pidfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.pid'))
  173.  
  174.     if os.path.exists(pidfile):
  175.         err('pid file exists, cannot continue: ' + pidfile)
  176.     if os.path.exists(outfile):
  177.         os.unlink(outfile)
  178.     if os.path.exists(errfile):
  179.         os.unlink(errfile)
  180.  
  181.     if os.fork():
  182.         sys.exit(0)  # exit the parent
  183.  
  184.     os.umask(0)
  185.     os.setsid()
  186.     if os.fork():
  187.         sys.exit(0)  # exit the parent
  188.  
  189.     print('daemon pid %d' % (os.getpid()))
  190.  
  191.     sys.stdout.flush()
  192.     sys.stderr.flush()
  193.  
  194.     stdin = file('/dev/null', 'r')
  195.     stdout = file(outfile, 'a+')
  196.     stderr = file(errfile, 'a+', 0)
  197.  
  198.     os.dup2(stdin.fileno(), sys.stdin.fileno())
  199.     os.dup2(stdout.fileno(), sys.stdout.fileno())
  200.     os.dup2(stderr.fileno(), sys.stderr.fileno())
  201.  
  202.     with open(pidfile, 'w') as ofp:
  203.         ofp.write('%i' % (os.getpid()))
  204.  
  205.  
  206. def main():
  207.     ''' main entry '''
  208.     opts = getopts()
  209.     if opts.daemonize:
  210.         daemonize(opts)
  211.     logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', level=get_logging_level(opts))
  212.     httpd(opts)
  213.  
  214.  
  215. if __name__ == '__main__':
  216.     main()  # this allows library functionality
Add Comment
Please, Sign In to add comment