1. WSGI
1.1 wsgiref.simple_server
server.py:
1 from wsgiref.simple_server import make_server 2 from WSGI_response import application 3 4 httpd = make_server('', 8000, application) 5 print 'Listening' 6 httpd.serve_forever()
application.py
1 def application(environ, start_response): 2 start_response('200 0k', [('Content-Type', 'text/html')]) 3 # path_info = environ['PATH_INFO'][1:] 4 return '''<head> 5 <REQUEST_METHOD>%s 6 <SCRIPT_NAME>%s 7 <PATH_INFO>%s 8 <QUERY_STRING>%s 9 <CONTENT_TYPE>%s 10 <CONTENT_LENGTH>%s 11 <SERVER_NAME>%s 12 <SERVER_PORT>%s 13 <SERVER_PROTOCOL>%s 14 <X_Storage_User>%s 15 <X_Storage_Pass>%s 16 </head> 17 <path_info>%s''' %(environ['REQUEST_METHOD'], environ['SCRIPT_NAME'], environ['PATH_INFO'], environ['QUERY_STRING'], environ['CONTENT_TYPE'] ,environ['CONTENT_LENGTH'], environ['SERVER_NAME'], environ['SERVER_PORT'], environ['SERVER_PROTOCOL'], environ.get('X_Storage_User'),environ.get('X_Storage_Pass'),environ['PATH_INFO'][1:])
没有获取到自定义的http头,那如何获取自定义http头???待续
1 2017-03-24 15:17:30 ⌚ meow in ~ 2 ○ → curl -v -H 'X_Storage_User: test:tester' -H 'X_Storage_Pass: testing' http://127.0.0.1:8000/auth 3 * Hostname was NOT found in DNS cache 4 * Trying 127.0.0.1... 5 * Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0) 6 > GET /auth HTTP/1.1 7 > User-Agent: curl/7.35.0 8 > Host: 127.0.0.1:8000 9 > Accept: */* 10 > X_Storage_User: test:tester 11 > X_Storage_Pass: testing 12 > 13 * HTTP 1.0, assume close after body 14 < HTTP/1.0 200 0k 15 < Date: Fri, 24 Mar 2017 07:19:33 GMT 16 < Server: WSGIServer/0.1 Python/2.7.6 17 < Content-Type: text/html 18 < 19 <head> 20 <REQUEST_METHOD>GET 21 <SCRIPT_NAME> 22 <PATH_INFO>/auth 23 <QUERY_STRING> 24 <CONTENT_TYPE>text/plain 25 <CONTENT_LENGTH> 26 <SERVER_NAME>meow 27 <SERVER_PORT>8000 28 <SERVER_PROTOCOL>HTTP/1.1 29 <X_Storage_User> 30 <X_Storage_Pass>None 31 </head> 32 * Closing connection 0 33 <path_info>auth
2. Flask
flask主要使用装饰器将URL和application联系起来,如@app.route('/', methods=['GET', 'POST'])
Flask也是基于WSGI的,进一步进行封装.
from flask import Flask from flask import request app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def home(): return 'at home' @app.route('/signin', methods=['GET']) def sigin_form(): return 'input x-auth-user and x-auth-pass' @app.route('/signin', methods=['POST']) def signin_auth(): username = request.headers.get('x-auth-user') passwd = request.headers.get('x-auth-pass') if username == 'coral' and passwd == '123': return 'success\nx-auth-user: %s and x-auth-pass: %s' %(username, passwd) else: return 'failed\nx-auth-user: %s and x-auth-pass: %s' %(username, passwd) if __name__ == '__main__': app.run()
then:
2017-03-27 15:42:05 ⌚ meow in ~ ○ → curl http://127.0.0.1:5000/ at home 2017-03-27 15:42:31 ⌚ meow in ~ ○ → curl http://127.0.0.1:5000/signininput x-auth-user and x-auth-pass 2017-03-27 15:42:36 ⌚ meow in ~ ○ → curl -X POST -H 'x-auth-user:coral' -H 'x-auth-pass:123' http://127.0.0.1:5000/signin success x-auth-user: coral and x-auth-pass: 123 2017-03-27 15:42:42 ⌚ meow in ~ ○ → curl -X POST -H 'x-auth-user:coral' http://127.0.0.1:5000/signinfailed x-auth-user: coral and x-auth-pass: None
3. BaseHTTPServer
BaseHTTPServer,就是麻烦了点,要自己解析http请求
1 #encoding=utf-8 2 3 from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 4 import io,shutil 5 import urllib,time 6 import getopt,string 7 8 class MyRequestHandler(BaseHTTPRequestHandler): 9 10 def handle_request(self): 11 content = "" 12 13 # 获取http head 14 request = dict() 15 request['X-AUTH-NAME'] = self.headers.get('X-AUTH-NAME', 'null') 16 request['X-AUTH-PASS'] = self.headers.get('X-AUTH-PASS', 'null') 17 18 # 获取http data 19 data = self.rfile.read(int(self.headers['content-length'])) 20 data = urllib.unquote(data).decode("utf-8", 'ignore') #指定编码方式 21 request['data'] = data 22 return request 23 24 def response(self, data, code): 25 enc="UTF-8" 26 data = data.encode(enc) 27 f = io.BytesIO() 28 f.write(data) 29 f.seek(0) 30 self.send_response(code) 31 self.send_header("Content-type", "text/html; charset=%s" % enc) 32 self.send_header("Content-Length", str(len(data))) 33 self.end_headers() 34 shutil.copyfileobj(f,self.wfile) 35 36 def do_GET(self): 37 print 'input X-AUTH-NAME AND X-AUTH-PASS' 38 39 def do_POST(self): 40 request = self.handle_request() 41 if request['X-AUTH-NAME'] == 'CCC' and request['X-AUTH-PASS'] == '123': 42 self.response('success', 200) 43 else: 44 self.response('failed', 401) 45 46 def do_PUT(self): 47 print 'put' 48 49 50 if __name__=='__main__': 51 try: 52 server = HTTPServer(('', 8000), MyRequestHandler) 53 print 'started httpserver...' 54 server.serve_forever() 55 except KeyboardInterrupt: 56 server.socket.close() 57 pass
then:
2017-03-27 20:41:55 ⌚ meow in ~ ○ → curl -v -d "data=postdata" -H 'X-AUTH-NAME:CCC' http://localhost:8000?test=post * Rebuilt URL to: http://localhost:8000/?test=post * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 8000 (#0) > POST /?test=post HTTP/1.1 > User-Agent: curl/7.35.0 > Host: localhost:8000 > Accept: */* > X-AUTH-NAME:CCC > Content-Length: 13 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 13 out of 13 bytes * Empty reply from server * Connection #0 to host localhost left intact curl: (52) Empty reply from server 2017-03-27 20:42:43 ⌚ meow in ~ ○ → curl -v -d "data=postdata" -H 'X-AUTH-NAME:CCC' http://localhost:8000?test=post * Rebuilt URL to: http://localhost:8000/?test=post * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 8000 (#0) > POST /?test=post HTTP/1.1 > User-Agent: curl/7.35.0 > Host: localhost:8000 > Accept: */* > X-AUTH-NAME:CCC > Content-Length: 13 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 13 out of 13 bytes * HTTP 1.0, assume close after body < HTTP/1.0 401 Unauthorized < Server: BaseHTTP/0.3 Python/2.7.6 < Date: Mon, 27 Mar 2017 12:43:35 GMT < Content-type: text/html; charset=UTF-8 < Content-Length: 6 < * Closing connection 0 failed
4. SimpleHTTPServer
simpleHTTPServer的父类也是BaseHTTPServer.
参考http://www.cnblogs.com/itech/archive/2011/12/31/2308697.html
1 #!/usr/bin/env python 2 #coding=utf-8 3 4 import os, sys, platform 5 import posixpath 6 import BaseHTTPServer 7 from SocketServer import ThreadingMixIn 8 import threading 9 import urllib 10 import cgi 11 import shutil 12 import mimetypes 13 import re 14 import time 15 16 try: 17 from cStringIO import StringIO 18 except ImportError: 19 from StringIO import StringIO 20 21 22 23 # 请求处理 24 class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 25 26 def do_GET(self): 27 # 获取文件内容 28 f = None 29 path = self.translate_path(self.path) 30 if os.path.isdir(path): 31 if not self.path.endswith('/'): 32 # redirect browser - doing basically what apache does 33 self.send_response(301) 34 self.send_header("Location", self.path + "/") 35 self.end_headers() 36 return None 37 try: 38 f = open(path, 'rb') 39 except IOError: 40 self.send_error(404, "File not found") 41 return None 42 self.send_response(200) 43 self.send_header("Content-type", "text/html") 44 fs = os.fstat(f.fileno()) 45 self.send_header("Content-Length", str(fs[6])) 46 self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) 47 self.end_headers() 48 shutil.copyfileobj(f,self.wfile) 49 f.close() 50 51 def do_HEAD(self): 52 """列出目录下的所有文件""" 53 path = self.translate_path(self.path) 54 # 获取路径下的文件列表 55 try: 56 list = os.listdir(path) 57 except os.error: 58 self.send_error(404, "No permission to list directory") 59 return None 60 list.sort(key=lambda a: a.lower()) 61 # print list 62 f = StringIO() 63 displaypath = cgi.escape(urllib.unquote(self.path)) 64 for name in list: 65 fullname = os.path.join(path, name) 66 f.write(fullname) 67 f.write('\n') 68 length = f.tell() 69 f.seek(0) 70 # 发送response head 71 self.send_response(200) 72 self.send_header("Content-type", "text/html") 73 self.send_header("Content-Length", str(length)) 74 self.end_headers() 75 # 发送response data 76 shutil.copyfileobj(f,self.wfile) 77 78 def do_PUT(self): 79 """Serve a POST request.""" 80 r, info = self.put_file() 81 print r, info, "by: ", self.client_address 82 f = StringIO() 83 if r: 84 f.write("Success:") 85 else: 86 f.write("Failed:") 87 f.write(info) 88 length = f.tell() 89 f.seek(0) 90 self.send_response(200) 91 self.send_header("Content-type", "text/html") 92 self.send_header("Content-Length", str(length)) 93 self.end_headers() 94 if f: 95 shutil.copyfileobj(f, self.wfile) 96 f.close() 97 98 99 def put_file(self): 100 # 获取上传的内容 101 content = "" 102 remainbytes = int(self.headers['content-length']) 103 104 line = self.rfile.readline() 105 remainbytes -= len(line) 106 content += line 107 while(remainbytes > 0): 108 line = self.rfile.readline() 109 remainbytes -= len(line) 110 content += line 111 # 创建本地文件 112 savefilepath = self.translate_path(self.path) 113 while os.path.exists(savefilepath): 114 savefilepath += "_" 115 try: 116 out = open(savefilepath, 'wb') 117 except IOError: 118 return (False, "Can't create file to write, do you have permission to write?") 119 120 remainbytes = len(content) 121 out.write(content) 122 return (True, "File %s upload success!" %savefilepath) 123 124 def translate_path(self, path): 125 path = path.split('?',1)[0] 126 path = path.split('#',1)[0] 127 path = posixpath.normpath(urllib.unquote(path)) 128 words = path.split('/') 129 words = filter(None, words) 130 path = os.getcwd() 131 for word in words: 132 drive, word = os.path.splitdrive(word) 133 head, word = os.path.split(word) 134 if word in (os.curdir, os.pardir): 135 continue 136 path = os.path.join(path, word) 137 return path 138 139 class ThreadingServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): 140 pass 141 142 if __name__ == '__main__': 143 # 获取和解析port 144 try: 145 port = int(sys.argv[1]) 146 except Exception, e: 147 port = 8080 148 if not 1024 < port < 65535: 149 port = 8080 150 serveraddr = ('', port) 151 print 'listening on port: %d' %(port) 152 #单线程 153 # srvr = BaseHTTPServer.HTTPServer(serveraddr, SimpleHTTPRequestHandler) 154 #多线程 155 srvr = ThreadingServer(serveraddr, SimpleHTTPRequestHandler) 156 srvr.serve_forever()
then:
2017-03-28 20:59:30 ⌚ meow in ~/Desktop ○ → curl -X HEAD http://127.0.0.1:8088/ /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_S.py /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_S.py~ /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_Server.py /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_Server.py~ 2017-03-28 20:59:35 ⌚ meow in ~/Desktop ○ → curl -v -X PUT -T "1" http://127.0.0.1:8088/ * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to 127.0.0.1 (127.0.0.1) port 8088 (#0) > PUT /1 HTTP/1.1 > User-Agent: curl/7.35.0 > Host: 127.0.0.1:8088 > Accept: */* > Content-Length: 303 > Expect: 100-continue > * Done waiting for 100-continue * We are completely uploaded and fine * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: BaseHTTP/0.3 Python/2.7.6 < Date: Tue, 28 Mar 2017 12:59:41 GMT < Content-type: text/html < Content-Length: 78 < * Closing connection 0 Success:File /home/meow/Desktop/python_http/SimpleHTTPServer/1 upload success! 2017-03-28 20:59:41 ⌚ meow in ~/Desktop ○ → curl -X HEAD http://127.0.0.1:8088/ /home/meow/Desktop/python_http/SimpleHTTPServer/1 /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_S.py /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_S.py~ /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_Server.py /home/meow/Desktop/python_http/SimpleHTTPServer/S_HTTP_Server.py~ 2017-03-28 20:59:47 ⌚ meow in ~/Desktop ○ → curl -v -X GET http://127.0.0.1:8088/1 * Hostname was NOT found in DNS cache * Trying 127.0.0.1... * Connected to 127.0.0.1 (127.0.0.1) port 8088 (#0) > GET /1 HTTP/1.1 > User-Agent: curl/7.35.0 > Host: 127.0.0.1:8088 > Accept: */* > * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: BaseHTTP/0.3 Python/2.7.6 < Date: Tue, 28 Mar 2017 12:59:51 GMT < Content-type: text/html < Content-Length: 303 < Last-Modified: Tue, 28 Mar 2017 12:59:41 GMT < 除了Flask,常见的Python Web框架还有: Django:全能型Web框架; web.py:一个小巧的Web框架; Bottle:和Flask类似的Web框架; Tornado:Facebook的开源异步Web框架。 华为raid2.0白皮书https://wenku.baidu.com/view/92222333336c1eb91a375dc6.html * Closing connection 0
5. SOCKET
参考http://www.cnblogs.com/litaozijin/p/6624029.html
WebServer.py:
1 #!/usr/bin/env python 2 #coding=utf-8 3 4 import socket 5 import sys 6 import getFileContent 7 8 #声明一个将要绑定的IP和端口,这里是用本地地址 9 server_address = ('localhost', 8088) 10 class WebServer(): 11 def run(self): 12 print >> sys.stderr, 'starting up on %s port %s' % server_address 13 #实例化一个Socket,AF_INET是IPV4套接字,SOCK_STREAM是tcp 14 sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 15 #绑定IP和端口 16 sock.bind(server_address) 17 #设置监听 18 sock.listen(1) 19 #这里首先给个死循环,其实这里是需要多线程的,再后续版本将会实现 20 while True: 21 #接受客户端的请求并得到请求信息和请求的端口信息 22 connection, client_address = sock.accept() 23 print >>sys.stderr, 'waiting for a connection' 24 try: 25 # 获取请求http 头信息 26 httphead = connection.recv(1024) 27 # 获取上传数据长度 28 length = 0 29 beginsearch = httphead.find("Content-Length: ") 30 if (beginsearch != -1): 31 beginsearch += 16 32 while (httphead[beginsearch:beginsearch+1].isdigit()): 33 length *= 10 34 length += int(httphead[beginsearch]) 35 beginsearch += 1 36 print length 37 # 获取上传数据内容 38 inputfile = '' 39 if length: 40 inputfile = connection.recv(length) 41 42 if httphead: 43 # 处理http请求 44 connection.sendall(getFileContent.server(httphead, inputfile)) 45 finally: 46 connection.close() 47 48 if __name__ == '__main__': 49 server=WebServer() 50 server.run()
getFileContent.py:
1 #!/usr/bin/env python 2 #coding=utf-8 3 4 import sys 5 import os 6 7 # 处理http请求入口 8 def server(httphead, inputfile): 9 # 获取请求类型 10 msgSendtoClient="" 11 requestType=httphead[0:httphead.find("/")].rstrip() 12 if requestType=="GET": 13 msgSendtoClient=responseGetRequest(httphead,msgSendtoClient) 14 if requestType=="POST": 15 msgSendtoClient=responsePostRequest(httphead, inputfile, msgSendtoClient) 16 return msgSendtoClient 17 18 #打开文件,这里不直接写,二是去取要发送的文件再写 19 def getFile(msgSendtoClient,file): 20 for line in file: 21 msgSendtoClient+=line 22 return msgSendtoClient 23 24 #筛选出请求的一个方法 25 def getMidStr(data,startStr,endStr): 26 startIndex = data.index(startStr) 27 if startIndex>=0: 28 startIndex += len(startStr) 29 endIndex = data.index(endStr) 30 return data[startIndex:endIndex] 31 32 #获取要发送数据的大小,根据HTTP协议规范,要提前指定发送的实体内容的大小 33 def getFileSize(fileobject): 34 fileobject.seek(0,2) 35 size = fileobject.tell() 36 return size 37 38 #设置返回的编码格式和文件类型 39 def setParaAndContext(msgSendtoClient,type,file,openFileType): 40 msgSendtoClient+="Content-Type: "+type+";charset=utf-8" 41 42 if file == 'null': 43 # 如果没有说明要获取的文件,则列出文件列表 44 content = '' 45 path = os.getcwd() 46 try: 47 filelist = os.listdir(path) 48 except os.error: 49 return None 50 for alist in filelist: 51 content += alist 52 content += '\n' 53 msgSendtoClient+="Content-Length: "+str(content)+"\n"+"\n" 54 msgSendtoClient += content 55 else: 56 # 如果说明了要获取的文件,则返回文件内容 57 msgSendtoClient+="Content-Length: "+str(getFileSize(open(file,"r")))+"\n"+"\n" 58 htmlFile=open(file,openFileType) 59 msgSendtoClient=getFile(msgSendtoClient,htmlFile) 60 return msgSendtoClient 61 62 #GET请求的返回数据 63 def responseGetRequest(data,msgSendtoClient): 64 return responseGRTRequest(getMidStr(data,'GET /',' HTTP/1.1'),msgSendtoClient) 65 66 #POST请求的返回数据 67 def responsePostRequest(data, inputfile, msgSendtoClient): 68 return responsePOSTRequest(data, inputfile, msgSendtoClient) 69 70 def responsePOSTRequest(httphead, inputfile, msgSendtoClient): 71 print 'responsePOSTRequest' 72 print 'httphead:' + httphead 73 print 'inputfile:' + inputfile 74 # 获取保存文件名 75 filename = httphead[httphead.find("/") + 1:] 76 filename = filename[0: filename.find(' ')] 77 print 'filename: %s \n' %(filename) 78 79 # 创建本地文件 80 savefilepath = os.getcwd() + '/' + filename 81 while os.path.exists(savefilepath): 82 savefilepath += "_" 83 try: 84 out = open(savefilepath, 'wb') 85 except IOError: 86 return (False, "Can't create file to write, do you have permission to write?") 87 out.write(inputfile) 88 return ("File %s upload success!" %savefilepath) 89 90 91 #请求返回数据 92 def responseGRTRequest(getRequestPath,msgSendtoClient): 93 '''head.txt HTTP返回头部 94 HTTP/1.1 200 OK 95 Accept-Ranges: bytes 96 ETag: W/"269-1482321927478" 97 Content-Language: zh-CN 98 ''' 99 headFile=open("head.txt","r") 100 print 'getRequestPath: ' + getRequestPath 101 msgSendtoClient=getFile(msgSendtoClient,headFile) 102 if getRequestPath=="": 103 msgSendtoClient=setParaAndContext(msgSendtoClient,"text/html","null","r") 104 else: 105 rootPath= os.getcwd() + '/' + getRequestPath 106 print rootPath 107 if os.path.exists(rootPath) and os.path.isfile(rootPath): 108 if ".txt" in rootPath: 109 msgSendtoClient=setParaAndContext(msgSendtoClient,"text/txt",rootPath,"r") 110 if ".html" in rootPath: 111 msgSendtoClient=setParaAndContext(msgSendtoClient,"text/html",rootPath,"r") 112 if ".gif" in rootPath: 113 msgSendtoClient=setParaAndContext(msgSendtoClient,"image/gif",rootPath,"rb") 114 if ".doc" in rootPath: 115 msgSendtoClient=setParaAndContext(msgSendtoClient,"application/msword",rootPath,"rb") 116 if ".mp4" in rootPath: 117 msgSendtoClient=setParaAndContext(msgSendtoClient,"video/mpeg4",rootPath,"rb") 118 else: 119 msgSendtoClient=setParaAndContext(msgSendtoClient,"application/others",rootPath,"r") 120 else: 121 print 'no such file' 122 msgSendtoClient += '\n\n \nno such file' 123 return msgSendtoClient
then:
1 2017-03-29 17:29:11 ⌚ meow in ~/Desktop 2 ○ → curl -X GET http://127.0.0.1:8088 3 4 1 5 Untitled Document~ 6 head.txt 7 getFileContent.py 8 getFileContent.py~ 9 getFileContent.pyc 10 1__ 11 head.txt~ 12 1_ 13 webServer.py~ 14 webServer.py 15 16 2017-03-29 18:19:20 ⌚ meow in ~/Desktop 17 ○ → curl -X GET http://127.0.0.1:8088/1 18 除了Flask,常见的Python Web框架还有: 19 20 Django:全能型Web框架; 21 22 web.py:一个小巧的Web框架; 23 24 Bottle:和Flask类似的Web框架; 25 26 Tornado:Facebook的开源异步Web框架。 27 华为raid2.0白皮书https://wenku.baidu.com/view/92222333336c1eb91a375dc6.html 28 29 2017-03-29 18:19:28 ⌚ meow in ~/Desktop 30 ○ → curl -X POST -T '1' http://127.0.0.1:8088 31 File /home/meow/Desktop/python_http/socket/1___ upload success! 32 2017-03-29 18:19:38 ⌚ meow in ~/Desktop 33 ○ → curl -X POST -T '1' http://127.0.0.1:8088/ttt 34 File /home/meow/Desktop/python_http/socket/ttt upload success! 35 2017-03-29 18:19:52 ⌚ meow in ~/Desktop 36 ○ → curl -X GET http://127.0.0.1:8088/ttt 37 除了Flask,常见的Python Web框架还有: 38 39 Django:全能型Web框架; 40 41 web.py:一个小巧的Web框架; 42 43 Bottle:和Flask类似的Web框架; 44 45 Tornado:Facebook的开源异步Web框架。 46 华为raid2.0白皮书https://wenku.baidu.com/view/92222333336c1eb91a375dc6.html 47 48 2017-03-29 18:20:24 ⌚ meow in ~/Desktop 49 ○ → curl -X GET http://127.0.0.1:8088/tttSSS 50 51 52 no such file
此博客主要是个人记录