SimpleHTTPServer模块分析

该模块是python中自带的提供HTTP服务的最上层模块,主要提供文件服务,如请求路径是文件夹,则返回该文件夹目录结构。该模块被webpy继承后用于提供静态文件服务。

SimpleHTTPServer模块自带了运行例子,理解起来也比较容易,这里直接贴上注释源码:

## 
# @file $python27$\Lib\SimpleHTTPServer.py
# @brief Python中非常简单的HTTP请求处理类,能处理对静态文件响应
# @date 2015-02-04
# @remark 为减少字符量,文件中的注释和对理解无关的内容都被我删除了,想详细了解请见原文件

__version__ = "0.6"
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    server_version = "SimpleHTTP/" + __version__

    # 处理HTTP中GET的请求
    def do_GET(self): 
        f = self.send_head()
        if f:
            self.copyfile(f, self.wfile)
            f.close()

    # 处理HTTP中HEAD的请求
    def do_HEAD(self): 
        f = self.send_head()
        if f:
            f.close()

    # 发送响应信息中的头部分,如果是请求文件,将返回该文件对象
    def send_head(self):
        path = self.translate_path(self.path)   # 将相对路径的url转化成本地路径
        f = None
        if os.path.isdir(path):                 # 本地路径是目录
            if not self.path.endswith('/'):     # 对"127.0.0.1/images"的url,将通知客户端重定向到"127.0.0.1/images/"
                # redirect browser - doing basically what apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            for index in "index.html", "index.htm": # 检查目录下是否有index文件存在,如果有,稍后会把index发送给客户端
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                return self.list_directory(path)    # 未找到index,则列出该目录下的文件和文件夹
        ctype = self.guess_type(path)               # 获取文件的MIME类型
        try:
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)                     # 响应状态码:200
        self.send_header("Content-type", ctype)     # 以下为响应报文头
        fs = os.fstat(f.fileno())
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.end_headers()  # 结果响应报文头
        return f            # 返回该文件对象

    # 列出path目录下的文件和文件夹,发送响应报文头,以内存文件形式返回显示文件列表的html
    def list_directory(self, path):
        try:
            list = os.listdir(path)
        except os.error:
            self.send_error(404, "No permission to list directory")
            return None
        list.sort(key=lambda a: a.lower())      # 文件名小写后排序
        f = StringIO()                          # 创建内存文件对象
        displaypath = cgi.escape(urllib.unquote(self.path))
        f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
        f.write("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
        f.write("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
        f.write("<hr>\n<ul>\n")
        for name in list:
            fullname = os.path.join(path, name)
            displayname = linkname = name
            # Append / for directories or @ for symbolic links
            if os.path.isdir(fullname):
                displayname = name + "/"
                linkname = name + "/"
            if os.path.islink(fullname):    # 判断是否为文件链接(以为是*.lnk文件,测试也不是,不知道这是什么)
                displayname = name + "@"
            f.write('<li><a href="%s">%s</a>\n'
                    % (urllib.quote(linkname), cgi.escape(displayname)))
        f.write("</ul>\n<hr>\n</body>\n</html>\n")
        length = f.tell()
        f.seek(0)
        self.send_response(200)
        encoding = sys.getfilesystemencoding()  # 获取文件编码,防止客户端显示乱码
        self.send_header("Content-type", "text/html; charset=%s" % encoding)
        self.send_header("Content-Length", str(length))
        self.end_headers()
        return f

    # 将相对路径的url转化成本地路径
    def translate_path(self, path):
        # 丢弃url请求中的参数
        path = path.split('?',1)[0]
        path = path.split('#',1)[0]
        path = posixpath.normpath(urllib.unquote(path))
        words = path.split('/')         # 对路径按'/'分割,将''的子字符串去掉
        words = filter(None, words)
        path = os.getcwd()
        for word in words:
            drive, word = os.path.splitdrive(word)
            head, word = os.path.split(word)
            if word in (os.curdir, os.pardir): continue
            path = os.path.join(path, word)
        return path

    # 拷贝类文件对象,webpy中没用这么粗暴的方式,而是一块一块发送
    def copyfile(self, source, outputfile):
        shutil.copyfileobj(source, outputfile)

    # 获得文件的MIME类型
    def guess_type(self, path):
        base, ext = posixpath.splitext(path)
        if ext in self.extensions_map:
            return self.extensions_map[ext]
        ext = ext.lower()
        if ext in self.extensions_map:
            return self.extensions_map[ext]
        else:
            return self.extensions_map['']

    # mimetypes是Python自带的标准库,可以根据文件后缀直接得到文件的MIME类型
    # 参见http://www.pythonclub.org/modules/mimetypes-txt
    if not mimetypes.inited:
        mimetypes.init() # try to read system mime.types
    extensions_map = mimetypes.types_map.copy()
    extensions_map.update({
        '': 'application/octet-stream', # Default
        '.py': 'text/plain',
        '.c': 'text/plain',
        '.h': 'text/plain',
        })
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值