Python - BaseHTTPServer:范围外的外部do_GET方法

时间:2017-10-23 07:25:15

标签: python

具有小(大)OOP问题的新Python无法解决:(

我下载了一个由BaseHTTPServer实现的网络服务器运行代码的示例到目前为止一切正常,我试图通过我的"外部"来调用do_GET方法。 class脚本停止使用错误消息:

Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 652, in __init__
self.handle()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
self.handle_one_request()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 328, in handle_one_request
method()
File "./webserver.py", line 41, in do_GET
MyHTTPHandlerClass.m_HTTPRequestHandler.do_GET(self)
AttributeError: 'module' object has no attribute 'do_GET'

解决问题的最佳方法是什么?谢谢!

webserver.py

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import argparse
import HTTPRequestHandler
import BaseHTTPServer
import logging
import os
import sys

def make_request_handler_class(opts):
    MyHTTPRequestHandler = HTTPRequestHandler
    MyHTTPRequestHandler.m_opts = opts

    return MyHTTPRequestHandler


def make_http_handler_class(opts, localHTTPRequestHandler):
    '''
    Factory to make the request handler and add arguments to it.

    It exists to allow the handler to access the opts.path variable
    locally.
    '''
    class MyHTTPHandlerClass(BaseHTTPServer.BaseHTTPRequestHandler):

        m_opts = opts

        m_HTTPRequestHandler = localHTTPRequestHandler

        def do_HEAD(self):
            '''
            Handle a HEAD request.
            '''
            logging.debug('HEADER %s' % (self.path))
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()

        def do_GET(self):
            MyHTTPHandlerClass.m_HTTPRequestHandler.do_GET(self)

    return MyHTTPHandlerClass


def err(msg):
    '''
    Report an error message and exit.
    '''
    print('ERROR: %s' % (msg))
    sys.exit(1)


def getopts():
    '''
    Get the command line options.
    '''

    # Get the help from the module documentation.
    this = os.path.basename(sys.argv[0])
    description = ('description:%s' % '\n  '.join(__doc__.split('\n')))
    epilog = ' '
    rawd = argparse.RawDescriptionHelpFormatter
    parser = argparse.ArgumentParser(formatter_class=rawd,
                                     description=description,
                                     epilog=epilog)

    parser.add_argument('-d', '--daemonize',
                        action='store',
                        type=str,
                        default='.',
                        metavar='DIR',
                        help='daemonize this process, store the 3 run files (.log, .err, .pid) in DIR (default "%(default)s")')

    parser.add_argument('-H', '--host',
                        action='store',
                        type=str,
                        default='localhost',
                        help='hostname, default=%(default)s')

    parser.add_argument('-l', '--level',
                        action='store',
                        type=str,
                        default='info',
                        choices=['notset', 'debug', 'info', 'warning', 'error', 'critical',],
                        help='define the logging level, the default is %(default)s')

    parser.add_argument('--no-dirlist',
                        action='store_true',
                        help='disable directory listings')

    parser.add_argument('-p', '--port',
                        action='store',
                        type=int,
                        default=8080,
                        help='port, default=%(default)s')

    parser.add_argument('-r', '--rootdir',
                        action='store',
                        type=str,
                        default=os.path.abspath('.'),
                        help='web directory root that contains the HTML/CSS/JS files %(default)s')

    parser.add_argument('-v', '--verbose',
                        action='count',
                        help='level of verbosity')

    parser.add_argument('-V', '--version',
                        action='version',
                        version='%(prog)s - v' + VERSION)

    opts = parser.parse_args()
    opts.rootdir = os.path.abspath(opts.rootdir)
    if not os.path.isdir(opts.rootdir):
        err('Root directory does not exist: ' + opts.rootdir)
    if opts.port < 1 or opts.port > 65535:
        err('Port is out of range [1..65535]: %d' % (opts.port))
    return opts


def httpd(opts):
    '''
    HTTP server
    '''
    RequestHandlerClass = make_request_handler_class(opts)

    HTTPHandlerClass = make_http_handler_class(opts, RequestHandlerClass)
    server = BaseHTTPServer.HTTPServer((opts.host, opts.port), HTTPHandlerClass)
    logging.info('Server starting %s:%s (level=%s)' % (opts.host, opts.port, opts.level))
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        pass
    server.server_close()
    logging.info('Server stopping %s:%s' % (opts.host, opts.port))


def get_logging_level(opts):
    '''
    Get the logging levels specified on the command line.
    The level can only be set once.
    '''
    if opts.level == 'notset':
        return logging.NOTSET
    elif opts.level == 'debug':
        return logging.DEBUG
    elif opts.level == 'info':
        return logging.INFO
    elif opts.level == 'warning':
        return logging.WARNING
    elif opts.level == 'error':
        return logging.ERROR
    elif opts.level == 'critical':
        return logging.CRITICAL


def daemonize(opts):
    '''
    Daemonize this process.

    CITATION: http://stackoverflow.com/questions/115974/what-would-be-the-simplest-way-to-daemonize-a-python-script-in-linux
    '''
    if os.path.exists(opts.daemonize) is False:
        err('directory does not exist: ' + opts.daemonize)

    if os.path.isdir(opts.daemonize) is False:
        err('not a directory: ' + opts.daemonize)

    bname = 'webserver-%s-%d' % (opts.host, opts.port)
    outfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.log'))
    errfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.err'))
    pidfile = os.path.abspath(os.path.join(opts.daemonize, bname + '.pid'))

    if os.path.exists(pidfile):
        err('pid file exists, cannot continue: ' + pidfile)
    if os.path.exists(outfile):
        os.unlink(outfile)
    if os.path.exists(errfile):
        os.unlink(errfile)

    if os.fork():
        sys.exit(0)  # exit the parent

    os.umask(0)
    os.setsid()
    if os.fork():
        sys.exit(0)  # exit the parent

    print('daemon pid %d' % (os.getpid()))

    sys.stdout.flush()
    sys.stderr.flush()

    stdin = file('/dev/null', 'r')
    stdout = file(outfile, 'a+')
    stderr = file(errfile, 'a+', 0)

    os.dup2(stdin.fileno(), sys.stdin.fileno())
    os.dup2(stdout.fileno(), sys.stdout.fileno())
    os.dup2(stderr.fileno(), sys.stderr.fileno())

    with open(pidfile, 'w') as ofp:
        ofp.write('%i' % (os.getpid()))


def main():
    ''' main entry '''
    opts = getopts()
    if opts.daemonize:
        daemonize(opts)
    logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', level=get_logging_level(opts))
    httpd(opts)


if __name__ == '__main__':
    main()  # this allows library functionality

HTTPRequestHandler.py

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import cgi
import logging
import os


'''
Factory to make the request handler and add arguments to it.

It exists to allow the handler to access the opts.path variable
locally.
'''    
class HTTPRequestHandler:

    def do_GET(BaseHTTPRequestHandler):
        m_BaseHTTPRequest = BaseHTTPRequestHandler

        # Parse out the arguments.
        # The arguments follow a '?' in the URL. Here is an example:
        #   http://example.com?arg1=val1
        args = {}
        idx = m_BaseHTTPRequest.path.find('?')
        if idx >= 0:
            rpath = m_BaseHTTPRequest.path[:idx]
            args = cgi.parse_qs(m_BaseHTTPRequest.path[idx+1:])
        else:
            rpath = m_BaseHTTPRequest.path

        # Print out logging information about the path and args.
        if 'content-type' in m_BaseHTTPRequest.headers:
            ctype, _ = cgi.parse_header(m_BaseHTTPRequest.headers['content-type'])
            logging.debug('TYPE %s' % (ctype))

        logging.debug('PATH %s' % (rpath))
        logging.debug('ARGS %d' % (len(args)))
        if len(args):
            i = 0
            for key in sorted(args):
                logging.debug('ARG[%d] %s=%s' % (i, key, args[key]))
                i += 1

        # Check to see whether the file is stored locally,
        # if it is, display it.

        # Get the file path.
        path = HTTPRequestHandler.m_opts.rootdir + rpath
        dirpath = None
        logging.debug('FILE %s' % (path))

        # If it is a directory look for index.html
        # or process it directly if there are 3
        # trailing slashed.
        if rpath[-3:] == '///':
            dirpath = path
        elif os.path.exists(path) and os.path.isdir(path):
            dirpath = path  # the directory portion
            index_files = ['/index.html', '/index.htm', ]
            for index_file in index_files:
                tmppath = path + index_file
                if os.path.exists(tmppath):
                    path = tmppath
                    break

        # Allow the user to type "///" at the end to see the
        # directory listing.
        if os.path.exists(path) and os.path.isfile(path):
            # This is valid file, send it as the response
            # after determining whether it is a type that
            # the server recognizes.
            _, ext = os.path.splitext(path)
            ext = ext.lower()
            content_type = {
                '.css': 'text/css',
                '.gif': 'image/gif',
                '.htm': 'text/html',
                '.html': 'text/html',
                '.jpeg': 'image/jpeg',
                '.jpg': 'image/jpg',
                '.js': 'text/javascript',
                '.png': 'image/png',
                '.text': 'text/plain',
                '.txt': 'text/plain',
            }

            # If it is a known extension, set the correct
            # content type in the response.
            if ext in content_type:
                m_BaseHTTPRequest.send_response(200)  # OK
                m_BaseHTTPRequest.send_header('Content-type', content_type[ext])
                m_BaseHTTPRequest.end_headers()

                with open(path) as ifp:
                    m_BaseHTTPRequest.wfile.write(ifp.read())
            else:
                # Unknown file type or a directory.
                # Treat it as plain text.
                m_BaseHTTPRequest.send_response(200)  # OK
                m_BaseHTTPRequest.send_header('Content-type', 'text/plain')
                m_BaseHTTPRequest.end_headers()

                with open(path) as ifp:
                    m_BaseHTTPRequest.wfile.write(ifp.read())
        elif 1 == 2:
            # There is special handling for http://127.0.0.1/info. That URL
            # displays some internal information.
            if m_BaseHTTPRequest.path == '/info' or m_BaseHTTPRequest.path == '/info/':
                m_BaseHTTPRequest.send_response(200)  # OK
                m_BaseHTTPRequest.send_header('Content-type', 'text/html')
                m_BaseHTTPRequest.end_headers()
                m_BaseHTTPRequest.info()
        else:
            if dirpath is None or m_BaseHTTPRequest.m_opts.no_dirlist == True:
                # Invalid file path, respond with a server access error
                m_BaseHTTPRequest.send_response(500)  # generic server error for now
                m_BaseHTTPRequest.send_header('Content-type', 'text/html')
                m_BaseHTTPRequest.end_headers()

                m_BaseHTTPRequest.wfile.write('<html>')
                m_BaseHTTPRequest.wfile.write('  <head>')
                m_BaseHTTPRequest.wfile.write('    <title>Server Access Error</title>')
                m_BaseHTTPRequest.wfile.write('  </head>')
                m_BaseHTTPRequest.wfile.write('  <body>')
                m_BaseHTTPRequest.wfile.write('    <p>Server access error.</p>')
                m_BaseHTTPRequest.wfile.write('    <p>%r</p>' % (repr(m_BaseHTTPRequest.path)))
                m_BaseHTTPRequest.wfile.write('    <p><a href="%s">Back</a></p>' % (rpath))
                m_BaseHTTPRequest.wfile.write('  </body>')
                m_BaseHTTPRequest.wfile.write('</html>')
            else:
                # List the directory contents. Allow simple navigation.
                logging.debug('DIR %s' % (dirpath))

                m_BaseHTTPRequest.send_response(200)  # OK
                m_BaseHTTPRequest.send_header('Content-type', 'text/html')
                m_BaseHTTPRequest.end_headers()

                m_BaseHTTPRequest.wfile.write('<html>')
                m_BaseHTTPRequest.wfile.write('  <head>')
                m_BaseHTTPRequest.wfile.write('    <title>%s</title>' % (dirpath))
                m_BaseHTTPRequest.wfile.write('  </head>')
                m_BaseHTTPRequest.wfile.write('  <body>')
                m_BaseHTTPRequest.wfile.write('    <a href="%s">Home</a><br>' % ('/'));

                # Make the directory path navigable.
                dirstr = ''
                href = None
                for seg in rpath.split('/'):
                    if href is None:
                        href = seg
                    else:
                        href = href + '/' + seg
                        dirstr += '/'
                    dirstr += '<a href="%s">%s</a>' % (href, seg)
                m_BaseHTTPRequest.wfile.write('    <p>Directory: %s</p>' % (dirstr))

                # Write out the simple directory list (name and size).
                m_BaseHTTPRequest.wfile.write('    <table border="0">')
                m_BaseHTTPRequest.wfile.write('      <tbody>')
                fnames = ['..']
                fnames.extend(sorted(os.listdir(dirpath), key=str.lower))
                for fname in fnames:
                    m_BaseHTTPRequest.wfile.write('        <tr>')
                    m_BaseHTTPRequest.wfile.write('          <td align="left">')
                    path = rpath + '/' + fname
                    fpath = os.path.join(dirpath, fname)
                    if os.path.isdir(path):
                        m_BaseHTTPRequest.wfile.write('            <a href="%s">%s/</a>' % (path, fname))
                    else:
                        m_BaseHTTPRequest.wfile.write('            <a href="%s">%s</a>' % (path, fname))
                    m_BaseHTTPRequest.wfile.write('          <td>&nbsp;&nbsp;</td>')
                    m_BaseHTTPRequest.wfile.write('          </td>')
                    m_BaseHTTPRequest.wfile.write('          <td align="right">%d</td>' % (os.path.getsize(fpath)))
                    m_BaseHTTPRequest.wfile.write('        </tr>')
                m_BaseHTTPRequest.wfile.write('      </tbody>')
                m_BaseHTTPRequest.wfile.write('    </table>')
                m_BaseHTTPRequest.wfile.write('  </body>')
                m_BaseHTTPRequest.wfile.write('</html>')

代码文件:

webserver.py https://pastebin.com/P1sy67gE

HTTPRequestHandler.py https://pastebin.com/4KX3XE8b

0 个答案:

没有答案