Загрузка файлов с символами Юникода из BaseHTTPServer в Python

Я использую Python 2.7.8, чтобы создать сервер, с которого я могу скачивать файлы. Проблема в том, что многие файлы содержат символы utf-8, такие как čćžšđ и другие. Я попытался расшифровать путь, но всякий раз, когда я нажимаю на имя файла с символом Unicode, он возвращает "ошибка 404: файл не найден". Как правильно декодировать пути, чтобы можно было загружать файлы с символами utf-8 и, если возможно, отображать их как символы utf-8 в индексе моего сервера. Вот код моего сервера, который включает в себя то, что я пробовал, и полный код сервера:

# -*- coding: utf-8 -*-

__version__ = "0.6"

__all__ = ["SimpleHTTPRequestHandler"]

import os
import posixpath
import BaseHTTPServer
import urllib
import cgi
import shutil
import mimetypes
from StringIO import StringIO
import SocketServer
import time
import sys
import unicodedata



class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    server_version = "SimpleHTTP/" + __version__

    def do_GET(self):
        """Serve a GET request."""
        f = self.send_head()
        if f:
        self.copyfile(f, self.wfile)
        f.close()

    def do_HEAD(self):
        """Serve a HEAD request."""
        f = self.send_head()
        if f:
            f.close()

    def send_head(self):
        path_now = self.translate_path(self.path)
        path_change = (os.path.dirname(os.path.abspath(__file__)) + "/files/")
        if path_now.startswith("/home/files/"):
           pass
        else:
           os.chdir(path_change)
        path = self.translate_path(self.path)
        """Those are few examples of what have I tried:
        path = path1.decode('ascii', 'ignore').makePath()
        path = unicodedata.normalize('NFKD', path1).encode('ascii','ignore')
        path2 = path1.decode("utf-8")
        path = path2.encode("utf-8")
        path = path2.encode("utf-8")"""
        f = None
        if os.path.isdir(path):
            for index in "index.html", "index.htm":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        if ctype.startswith('text/'):
            mode = 'r'
        else:
            mode = 'rb'
        try:
            f = open(path.decode(sys.getfilesystemencoding()), mode) #this doesn't work, nothing changes
            size = os.path.getsize(path)
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype + "; charset=utf-8") # + " charset=utf-8"
        self.send_header("Content-Length", size)
        self.end_headers()
        return f

    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(lambda a, b: cmp(a.lower(), b.lower()))
        f = StringIO()
        f.write("<title>Directory listing for %s</title>\n" % self.path)
        f.write("<h2>Directory listing for %s</h2>\n" % self.path)
        f.write("<hr>\n<ul>\n")
        for name in list:
            fullname = os.path.join(path, name)
            displayname = linkname = name = cgi.escape(name)
            if os.path.isdir(fullname):
                displayname = name + "/"
                linkname = name + "/"
            if os.path.islink(fullname):
                displayname = name + "@"
            f.write('<li><a href="%s">%s</a>\n' % (linkname, displayname))
        f.write("</ul>\n<hr>\n")
        f.seek(0)
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        return f

    def translate_path(self, path):
        try:
            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
        except Exception, e:
           self.send_error(403, e)
           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.encode("utf-8")

    def copyfile(self, source, outputfile):
        shutil.copyfileobj(source, outputfile)

    def guess_type(self, path):
        base, ext = posixpath.splitext(path)
        if self.extensions_map.has_key(ext):
            return self.extensions_map[ext]
        ext = ext.lower()
        if self.extensions_map.has_key(ext):
            return self.extensions_map[ext]
        else:
            return self.extensions_map['']

    extensions_map = mimetypes.types_map.copy()
    extensions_map.update({
        '': 'application/octet-stream', # Default
        '.py': 'text/plain',
        '.c': 'text/plain',
        '.h': 'text/plain',
        })

class ForkingHTTPServer(SocketServer.ForkingMixIn, BaseHTTPServer.HTTPServer):
    def finish_request(self, request, client_address):
        request.settimeout(30)
        BaseHTTPServer.HTTPServer.finish_request(self, request, client_address)


def test(HandlerClass = SimpleHTTPRequestHandler, ServerClass = BaseHTTPServer.HTTPServer, server_address=("192.168.1.2", 8000)):
    try:
        print "Server started"
        srvr = ForkingHTTPServer(server_address, HandlerClass)
        srvr.serve_forever()  # serve_forever
    except KeyboardInterrupt:
        print "Closing sockets..."
        time.sleep(2)
        print "Server is shutting down in 3"
        time.sleep(1)
        print "Server is shutting down in 2"
        time.sleep(1)
        print "Server is shutting down in 1"
        time.sleep(1)
        srvr.socket.close()


if __name__ == '__main__':
        test()

Я надеюсь, что это вся информация, которая вам нужна. Если вам нужно что-то еще, просто прокомментируйте, и я буду рад отредактировать мой вопрос;)

1 ответ

Решение

Я только что увидел, что я устанавливал charset в utf-8 внутри функции send_head, но не в функции list_directory. Также я отредактировал

"; charset=utf-8" 

в

'; charset="utf-8"' 

и теперь это работает как шарм.

Похоже, я все время кодировал / декодировал правильные вещи, но неправильно настраивал свои заголовки.

Другие вопросы по тегам