zoukankan      html  css  js  c++  java
  • simple HTTP server with upload

      1 #!/usr/bin/env python
      2 
      3 """Simple HTTP Server With Upload.
      4 
      5 https://github.com/tualatrix/tools/blob/master/SimpleHTTPServerWithUpload.py
      6 
      7 This module builds on BaseHTTPServer by implementing the standard GET
      8 and HEAD requests in a fairly straightforward manner.
      9 
     10 """
     11 
     12 
     13 import os
     14 import posixpath
     15 import BaseHTTPServer
     16 import urllib
     17 import cgi
     18 import shutil
     19 import mimetypes
     20 import re
     21 
     22 __version__ = "0.1"
     23 __all__ = ["SimpleHTTPRequestHandler"]
     24 __author__ = "bones7456"
     25 __home_page__ = "http://li2z.cn/"
     26 
     27 try:
     28     from cStringIO import StringIO
     29 except ImportError:
     30     from StringIO import StringIO
     31 
     32 
     33 class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     34 
     35     """Simple HTTP request handler with GET/HEAD/POST commands.
     36 
     37     This serves files from the current directory and any of its
     38     subdirectories.  The MIME type for files is determined by
     39     calling the .guess_type() method. And can reveive file uploaded
     40     by client.
     41 
     42     The GET/HEAD/POST requests are identical except that the HEAD
     43     request omits the actual contents of the file.
     44 
     45     """
     46 
     47     server_version = "SimpleHTTPWithUpload/" + __version__
     48 
     49     def do_GET(self):
     50         """Serve a GET request."""
     51         f = self.send_head()
     52         if f:
     53             self.copyfile(f, self.wfile)
     54             f.close()
     55 
     56     def do_HEAD(self):
     57         """Serve a HEAD request."""
     58         f = self.send_head()
     59         if f:
     60             f.close()
     61 
     62     def do_POST(self):
     63         """Serve a POST request."""
     64         r, info = self.deal_post_data()
     65         print r, info, "by: ", self.client_address
     66         f = StringIO()
     67         f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
     68         f.write("<html>
    <meta charset='UTF-8'>
    <title>Upload Result Page</title>
    ")
     69         f.write("<html>
    <title>Upload Result Page</title>
    ")
     70         f.write("<body>
    <h2>Upload Result Page</h2>
    ")
     71         f.write("<hr>
    ")
     72         if r:
     73             f.write("<strong>Success:</strong>")
     74         else:
     75             f.write("<strong>Failed:</strong>")
     76         f.write(info)
     77         f.write("<br><a href="%s">back</a>" % self.headers['referer'])
     78         f.write("<hr><small>Powered By: bones7456, check new version at ")
     79         f.write("<a href="http://li2z.cn/?s=SimpleHTTPServerWithUpload">")
     80         f.write("here</a>.</small></body>
    </html>
    ")
     81         length = f.tell()
     82         f.seek(0)
     83         self.send_response(200)
     84         self.send_header("Content-type", "text/html")
     85         self.send_header("Content-Length", str(length))
     86         self.end_headers()
     87         if f:
     88             self.copyfile(f, self.wfile)
     89             f.close()
     90 
     91     def deal_post_data(self):
     92         boundary = self.headers.plisttext.split("=")[1]
     93         remainbytes = int(self.headers['content-length'])
     94         line = self.rfile.readline()
     95         remainbytes -= len(line)
     96         if boundary not in line:
     97             return (False, "Content NOT begin with boundary")
     98         line = self.rfile.readline()
     99         remainbytes -= len(line)
    100         fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line)
    101         if not fn:
    102             return (False, "Can't find out file name...")
    103         path = self.translate_path(self.path)
    104         fn = os.path.join(path, fn[0])
    105         while os.path.exists(fn):
    106             fn += "_"
    107         line = self.rfile.readline()
    108         remainbytes -= len(line)
    109         line = self.rfile.readline()
    110         remainbytes -= len(line)
    111         try:
    112             out = open(fn, 'wb')
    113         except IOError:
    114             return (False, "Can't create file to write, do you have permission to write?")
    115 
    116         preline = self.rfile.readline()
    117         remainbytes -= len(preline)
    118         while remainbytes > 0:
    119             line = self.rfile.readline()
    120             remainbytes -= len(line)
    121             if boundary in line:
    122                 preline = preline[0:-1]
    123                 if preline.endswith('
    '):
    124                     preline = preline[0:-1]
    125                 out.write(preline)
    126                 out.close()
    127                 return (True, "File '%s' upload success!" % fn)
    128             else:
    129                 out.write(preline)
    130                 preline = line
    131         return (False, "Unexpect Ends of data.")
    132 
    133     def send_head(self):
    134         """Common code for GET and HEAD commands.
    135 
    136         This sends the response code and MIME headers.
    137 
    138         Return value is either a file object (which has to be copied
    139         to the outputfile by the caller unless the command was HEAD,
    140         and must be closed by the caller under all circumstances), or
    141         None, in which case the caller has nothing further to do.
    142 
    143         """
    144         path = self.translate_path(self.path)
    145         f = None
    146         if os.path.isdir(path):
    147             if not self.path.endswith('/'):
    148                 # redirect browser - doing basically what apache does
    149                 self.send_response(301)
    150                 self.send_header("Location", self.path + "/")
    151                 self.end_headers()
    152                 return None
    153             for index in "index.html", "index.htm":
    154                 index = os.path.join(path, index)
    155                 if os.path.exists(index):
    156                     path = index
    157                     break
    158             else:
    159                 return self.list_directory(path)
    160         ctype = self.guess_type(path)
    161         try:
    162             # Always read in binary mode. Opening files in text mode may cause
    163             # newline translations, making the actual size of the content
    164             # transmitted *less* than the content-length!
    165             f = open(path, 'rb')
    166         except IOError:
    167             self.send_error(404, "File not found")
    168             return None
    169         self.send_response(200)
    170         self.send_header("Content-type", ctype)
    171         fs = os.fstat(f.fileno())
    172         self.send_header("Content-Length", str(fs[6]))
    173         self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
    174         self.end_headers()
    175         return f
    176 
    177     def list_directory(self, path):
    178         """Helper to produce a directory listing (absent index.html).
    179 
    180         Return value is either a file object, or None (indicating an
    181         error).  In either case, the headers are sent, making the
    182         interface the same as for send_head().
    183 
    184         """
    185         try:
    186             list = os.listdir(path)
    187         except os.error:
    188             self.send_error(404, "No permission to list directory")
    189             return None
    190         list.sort(key=lambda a: a.lower())
    191         f = StringIO()
    192         displaypath = cgi.escape(urllib.unquote(self.path))
    193         f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
    194         f.write("<html><meta charset='UTF-8'>
    <title>Directory listing for %s</title>
    " % displaypath)
    195         f.write("<body>
    <h2>Directory listing for %s</h2>
    " % displaypath)
    196         f.write("<hr>
    ")
    197         f.write("<form ENCTYPE="multipart/form-data" method="post">")
    198         f.write("<input name="file" type="file"/>")
    199         f.write("<input type="submit" value="upload"/></form>
    ")
    200         f.write("<hr>
    <ul>
    ")
    201         for name in list:
    202             if '.py' not in name and '.html' not in name:
    203                 fullname = os.path.join(path, name)
    204                 displayname = linkname = name
    205             # Append / for directories or @ for symbolic links
    206                 if os.path.isdir(fullname):
    207                     displayname = name + "/"
    208                     linkname = name + "/"
    209                 if os.path.islink(fullname):
    210                     displayname = name + "@"
    211                 # Note: a link to a directory displays with @ and links with /
    212                 f.write('<li><a href="%s">%s</a>
    '
    213                         % (urllib.quote(linkname), cgi.escape(displayname)))
    214         f.write("</ul>
    <hr>
    </body>
    </html>
    ")
    215         length = f.tell()
    216         f.seek(0)
    217         self.send_response(200)
    218         self.send_header("Content-type", "text/html")
    219         self.send_header("Content-Length", str(length))
    220         self.end_headers()
    221         return f
    222 
    223     def translate_path(self, path):
    224         """Translate a /-separated PATH to the local filename syntax.
    225 
    226         Components that mean special things to the local file system
    227         (e.g. drive or directory names) are ignored.  (XXX They should
    228         probably be diagnosed.)
    229 
    230         """
    231         # abandon query parameters
    232         path = path.split('?', 1)[0]
    233         path = path.split('#', 1)[0]
    234         path = posixpath.normpath(urllib.unquote(path))
    235         words = path.split('/')
    236         words = filter(None, words)
    237         path = os.getcwd()
    238         for word in words:
    239             drive, word = os.path.splitdrive(word)
    240             head, word = os.path.split(word)
    241             if word in (os.curdir, os.pardir):
    242                 continue
    243             path = os.path.join(path, word)
    244         return path
    245 
    246     def copyfile(self, source, outputfile):
    247         """Copy all data between two file objects.
    248 
    249         The SOURCE argument is a file object open for reading
    250         (or anything with a read() method) and the DESTINATION
    251         argument is a file object open for writing (or
    252         anything with a write() method).
    253 
    254         The only reason for overriding this would be to change
    255         the block size or perhaps to replace newlines by CRLF
    256         -- note however that this the default server uses this
    257         to copy binary data as well.
    258 
    259         """
    260         shutil.copyfileobj(source, outputfile)
    261 
    262     def guess_type(self, path):
    263         """Guess the type of a file.
    264 
    265         Argument is a PATH (a filename).
    266 
    267         Return value is a string of the form type/subtype,
    268         usable for a MIME Content-type header.
    269 
    270         The default implementation looks the file's extension
    271         up in the table self.extensions_map, using application/octet-stream
    272         as a default; however it would be permissible (if
    273         slow) to look inside the data to make a better guess.
    274 
    275         """
    276 
    277         base, ext = posixpath.splitext(path)
    278         if ext in self.extensions_map:
    279             return self.extensions_map[ext]
    280         ext = ext.lower()
    281         if ext in self.extensions_map:
    282             return self.extensions_map[ext]
    283         else:
    284             return self.extensions_map['']
    285 
    286     if not mimetypes.inited:
    287         mimetypes.init()  # try to read system mime.types
    288     extensions_map = mimetypes.types_map.copy()
    289     extensions_map.update({
    290         '': 'application/octet-stream',  # Default
    291         '.py': 'text/plain',
    292         '.c': 'text/plain',
    293         '.h': 'text/plain',
    294         })
    295 
    296 
    297 def test(HandlerClass=SimpleHTTPRequestHandler,
    298          ServerClass=BaseHTTPServer.HTTPServer):
    299     BaseHTTPServer.test(HandlerClass, ServerClass)
    300 
    301 if __name__ == '__main__':
    302     test()
  • 相关阅读:
    代理的原理
    nodemon:让node自动重启
    http与https的区别
    Content-Type:几种常用数据编码格式
    vue ssr服务端渲染
    vue 实现文件上传和文件下载
    vue element-ui表格里时间戳转换成时间显示
    vue npm start 自动打开网页
    yearProgress.vue
    vuejs中class与style的绑定
  • 原文地址:https://www.cnblogs.com/fatt/p/6722419.html
Copyright © 2011-2022 走看看