Python实现,源码来自网络,代码内部有作者信息。

HTTP方式共享文件,对于不需要用户名和密码验证的系统非常方便。通过浏览器就可以实现文件上传和下载。非常适合用作测试系统的脚手架。

对于系统使用curl命令行也可以轻松实现文件上传。wget实现文件下载。

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

启动一个支持文件上传的HTTP-Server的更多相关文章

  1. java nio 写一个完整的http服务器 支持文件上传 chunk传输 gzip 压缩 使用过程 和servlet差不多

    java nio 写一个完整的http服务器  支持文件上传   chunk传输    gzip 压缩      也仿照着 netty处理了NIO的空轮询BUG        本项目并不复杂 代码不多 ...

  2. RPC基于http协议通过netty支持文件上传下载

    本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...

  3. Openresty + nginx-upload-module支持文件上传

    0. 说明 这种方式其实复杂,麻烦!建议通过这个方式搭建Openresty文件上传和下载服务器:http://www.cnblogs.com/lujiango/p/9056680.html 1. 包下 ...

  4. springmvc学习笔记--支持文件上传和阿里云OSS API简介

    前言: Web开发中图片上传的功能很常见, 本篇博客来讲述下springmvc如何实现图片上传的功能. 主要讲述依赖包引入, 配置项, 本地存储和云存储方案(阿里云的OSS服务). 铺垫: 文件上传是 ...

  5. 让nginx支持文件上传的几种模式

    文件上传的几种不同语言和不同方法的总结. 第一种模式 : PHP 语言来处理 这个模式比较简单, 用的人也是最多的, 类似的还有用 .net 来实现, jsp来实现, 都是处理表单.只有语言的差别, ...

  6. 让UpdatePanel支持文件上传(2):服务器端组件 .

    我们现在来关注服务器端的组件.目前的主要问题是,我们如何让页面(事实上是ScriptManager控件)认为它接收到的是一个异步的回送?ScriptManager控件会在HTTP请求的Header中查 ...

  7. 让UpdatePanel支持文件上传(1):开始 .

    UpdatePanel从一开始就无法支持AJAX的文件上传方式.Eilon Lipton写了一篇文章解释了这个问题的原因.文章中提供了两个绕开此问题的方法: 将“上传”按钮设为一个传统的PostBac ...

  8. 配置servlet支持文件上传

    Servlet3.0为Servlet添加了multipart配置选项,并为HttpServletRequest添加了getPart和getParts方法获取上传文件.为了使Servlet支付文件上传需 ...

  9. 测试平台系列(92) 让http请求支持文件上传

    大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持. 欢迎关注我的公众号米洛的测开日记,获取最新文章教程! 回顾 上一节呢,我们编写了oss的 ...

随机推荐

  1. 跟着百度学PHP[14]-COOKIE的应用/网站登陆案例完整案例

    先在数据库当中创建以下数据: mysql> create table user( -> id int not null auto_increment, ) not null default ...

  2. 让一个 csproj 项目指定多个开发框架[转]

    原贴:https://walterlv.gitee.io/post/configure-projects-to-target-multiple-platforms.html 可移植类库.共享项目..N ...

  3. OpenERP report doesn't work

    1. When you have used OpenOffice edited  one of reports,it has stored the report's banary data is da ...

  4. 转 java调用php的webService

    1.首先先下载php的webservice包:NuSOAP,自己到官网去下载,链接就不给出来了,自己去google吧    基于NoSOAP我们写了一个php的webservice的服务端,例子如下: ...

  5. Android最流行的网络框架(原创)

    Android程序最重要的模块就是网络部分,如何从网络上下载数据,如何将处理过的数据上传至网络,往往是android程序的关键环节.        Android原生提供基于HttpClient和Ht ...

  6. java 遍历String

    Java字符串是一系列的Unicode字符序列,但是,它却常常被误认为是char序列.于是,我们经常这样来遍历字符串: package testchar; public class TestChar2 ...

  7. BlockingQueue(阻塞队列)分析

    如果读者还有一点印象,我们在实现线程池时,用了队列这种数据结构来存储接收到的任务,在多线程环境中阻塞队列是一种非常有用的队列,在介绍BlockingQueue之前,我们先解释一下Queue接口. Qu ...

  8. VC++ Debug内存值

    Memory Values If you're using the debug heap, memory is initialized and cleared with special values. ...

  9. reactjs中props和state最佳实践

    http://blog.csdn.net/dangnian/article/details/50998981

  10. 使用HTML5构建iOS原生APP(2)

    本文转载至 http://ju.outofmemory.cn/entry/18807 有时候我们在内嵌的webview中希望点击一个链接之后,触发iOS原生事件,而不是webview内页面跳转(因为w ...