Python服务器记录器
我需要一些帮助来弄清楚为什么它不能按应有的方式工作。目标是建立一个本地python服务器(类似于SimpleHTTPServer),但让它记录对文件的请求/响应,以便更好地了解浏览器DOM的行为。我希望能够浏览到localhost,并让它像Web服务器一样进行响应 使用此选项时,它似乎挂起在localhost上,而不是将其重定向到“sample.html”文件。有没有想过为什么会发生这种情况 代码:Python服务器记录器,python,Python,我需要一些帮助来弄清楚为什么它不能按应有的方式工作。目标是建立一个本地python服务器(类似于SimpleHTTPServer),但让它记录对文件的请求/响应,以便更好地了解浏览器DOM的行为。我希望能够浏览到localhost,并让它像Web服务器一样进行响应 使用此选项时,它似乎挂起在localhost上,而不是将其重定向到“sample.html”文件。有没有想过为什么会发生这种情况 代码: 导入操作系统、re、套接字、线程、线程; #您可能要更改的设置: WEBSERVER_PORT=
导入操作系统、re、套接字、线程、线程;
#您可能要更改的设置:
WEBSERVER_PORT=28876;
LOGS_FOLDER=os.path.join(os.getcwd(),'LOGS');
TEST_HTML='sample.HTML';
详细输出=真;
#添加新文件类型时可能需要更改的设置:
默认_MIME_类型='应用程序/八位字节流';
注册的\u MIME\u类型={
'text/html':['htm','html'],
'text/javascript':['js'],
'image/svg+xml':['svg'],
'image/jpeg':['jpg'],
};
def MimeType(路径):
last_dot=path.rfind('.');
如果最后一点!=-1:
ext=路径[最后一个点+1::]下();
对于mime_类型,exts在注册的\u mime_类型中。items():
如果ext中有ext:
返回mime_类型;
返回默认的MIME类型;
def GenerateDirect(新路径):
返回(301,“永久移动”\
['地点:http://localhost:%s%s“%(Web服务器端口,新路径)]\
'text/html',''(新路径,新路径));
def Reply404(路径、查询、数据):
返回404,“未找到”,“文本/普通”,“未找到路径%s”%path;
def ReplyFile(路径、查询、数据):
path=os.path.join(os.getcwd(),path[1:].replace(os.altsep,os.sep));
如果os.path.isfile(路径):
尝试:
数据=打开(路径“rb”).read();
除:
打印“无法打开文件%s”%path;
返回500,'内部服务器错误','文本/普通'\
'无法读取路径%s'%1!';
如果输出冗长:
打印“回复=文件%s”%path;
返回200,‘OK’,MimeType(路径),数据;
打印“找不到文件%s%”路径;
返回404,“未找到”,“文本/普通”,“未找到路径%s”%path;
def ReplyLog(路径、查询、数据):
path=os.path.join(LOGS_文件夹,路径[len('/LOGS/'):].replace('/',os.sep));
尝试:
打开(路径'ab')。写入(数据+'\r\n');
除:
打印“无法写入日志文件%s”%path;
返回500,'内部服务器错误','文本/普通'\
'无法读取路径%s'%1!';
如果输出冗长:
打印“已将%s字节写入日志文件%s%”(len(数据),路径);
返回200,‘确定’、‘文本/普通’、‘记录成功’;
#答复包含以下两种形式之一的条目:
#“regexp”:(“mimetype”、“body”),
#“regexp”:函数,
#第一个表单使服务器用“200OK”和给定的正文和
#模版。第二种形式需要“函数”来接受HTTP请求路径
#作为参数,并返回包含HTTP返回代码的元组HTTP reason
#消息、mimetype和正文。
答复=[
(r'^/$',generateDirect('/'+TEST_HTML)),
(r'^/logs/*$,ReplyLog),
(r'^.*$,回复文件),
];
def Main():
如果不是os.path.isdir(LOGS\u文件夹):
尝试:
mkdir(LOGS_文件夹);
除:
打印“无法创建日志文件夹%s”%logs\u文件夹;
返回;
server_socket=socket.socket();
server_socket.setsockopt(socket.SOL_socket,socket.SO_REUSEADDR,1);
server_socket.bind(“”,WEBSERVER_端口));
服务器\u套接字。侦听(1);
正在运行的“打印”Web服务器http://localhost:%d/“%WEBSERVER\u”端口;
印刷品;
线程_计数器=1;
而1:
client_socket,client_address=server_socket.accept();
线程=线程。线程(目标=连接线程\
args=(客户机_套接字,客户机_地址));
thread.start();
线程_计数器+=1;
def CONNECTIONSTREAD(客户端\u套接字、客户端\u地址):
尝试:
打印“**来自%s的连接:%s已打开”。%client\u address;
而1:
尝试:
请求\头,请求\内容=ReadRequest(客户端\套接字);
如果请求_头为无:
打破
响应=HandlerRequest(请求标题、请求内容);
尝试:
客户端_socket.send(响应);
除socket.error外,e:
引发ConnectionError(“无法发送响应”);
除连接错误外,e:
打印“连接错误:%s”%e;
尝试:
client_socket.close();
除:
通过;
打破
打印'**来自%s的连接:%s已关闭''%1!''客户端地址;
除:
thread.interrupt_main();
类ConnectionError(异常):
定义初始值(自身,值):
自我价值=价值;
定义(自我):
回归自我价值;
def GetContentLength(请求标题):
对于请求\u标头中的请求\u标头:
如果请求_头。查找(“:”)!=-1:
name,value=request_header.split(“:”,1);
如果name.strip().lower()=“内容长度”:
尝试:
返回int(值);
除值错误外:
raise ConnectionError('错误的内容长度值:%s'%1!''值);
不返回任何值;
def ReadRequest(客户端\u套接字):
请求=“”;
请求头=无;
请求\u头\u长度=无;
如果输出冗长:
打印“>>接受的请求,读取标题…”,;
当请求_头为“无”时:
尝试:
请求+=客户机_socket.recv(256);
除socket.error外,e:
如果输出冗长:
印刷品;
raise ConnectionError('读取请求头时连接已断开');
如果len(请求)==0:
如果输出冗长:
印刷品;
#升起接头错误(“接头关闭”);
返回None,None;
request_headers_length=request.find('\r\n\r\n');
如果请求\u头\u长度!=-1:
请求标题=请求[:请求标题长度].split('\r\n')[:-1];
#换行符是标题的一部分
请求头长度+=2;
#另一个不是标题或内容的一部分:
请求内容长度=GetContentLength(请求标题);
如果请求内容长度为
import os, re, socket, thread, threading;
# Settings that you may want to change:
WEBSERVER_PORT = 28876;
LOGS_FOLDER = os.path.join(os.getcwd(), 'logs');
TEST_HTML = 'sample.html';
VERBOSE_OUTPUT = True;
# Settings that you may need to change if you add new file types:
DEFAULT_MIME_TYPE = 'application/octet-stream';
REGISTERED_MIME_TYPES = {
'text/html': ['htm', 'html'],
'text/javascript': ['js'],
'image/svg+xml': ['svg'],
'image/jpeg': ['jpg'],
};
def MimeType(path):
last_dot = path.rfind('.');
if last_dot != -1:
ext = path[last_dot + 1:].lower();
for mime_type, exts in REGISTERED_MIME_TYPES.items():
if ext in exts:
return mime_type;
return DEFAULT_MIME_TYPE;
def GenerateRedirect(new_path):
return (301, 'Moved permanently', \
['Location: http://localhost:%s%s' % (WEBSERVER_PORT, new_path)], \
'text/html', '<a href="%s">%s</a>' % (new_path, new_path));
def Reply404(path, query, data):
return 404, 'Not found', 'text/plain', 'The path %s was not found' % path;
def ReplyFile(path, query, data):
path = os.path.join(os.getcwd(), path[1:].replace(os.altsep, os.sep));
if os.path.isfile(path):
try:
data = open(path, 'rb').read();
except:
print ' Cannot open file %s' % path;
return 500, 'Internal server error', 'text/plain', \
'The path %s could not be read' % path;
if VERBOSE_OUTPUT:
print ' Reply = file %s' % path;
return 200, 'OK', MimeType(path), data;
print ' Cannot find file %s' % path;
return 404, 'Not found', 'text/plain', 'The path %s was not found' % path;
def ReplyLog(path, query, data):
path = os.path.join(LOGS_FOLDER, path[len('/logs/'):].replace('/', os.sep));
try:
open(path, 'ab').write(data + '\r\n');
except:
print ' Cannot write to log file %s' % path;
return 500, 'Internal server error', 'text/plain', \
'The path %s could not be read' % path;
if VERBOSE_OUTPUT:
print ' Wrote %s bytes to log file %s' % (len(data), path);
return 200, 'OK', 'text/plain', 'Log successful';
# Replies contains entries in one of two forms:
# "regexp": ("mimetype", "body"),
# "regexp": function,
# The first form causes the server to reply with "200 OK" and the given body and
# mimetype. The second form requires "function" to accept the HTTP request path
# as an argument and return a tuple containing the HTTP return code, HTTP reason
# message, mimetype and body.
replies = [
(r'^/$', GenerateRedirect('/' + TEST_HTML)),
(r'^/logs/.*$', ReplyLog),
(r'^.*$', ReplyFile),
];
def Main():
if not os.path.isdir(LOGS_FOLDER):
try:
os.mkdir(LOGS_FOLDER);
except:
print 'Cannot create logs folder %s' % LOGS_FOLDER;
return;
server_socket = socket.socket();
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1);
server_socket.bind(('', WEBSERVER_PORT));
server_socket.listen(1);
print 'Webserver running at http://localhost:%d/' % WEBSERVER_PORT;
print;
thread_counter = 1;
while 1:
client_socket, client_address = server_socket.accept();
thread = threading.Thread(target = ConnectionThread, \
args = (client_socket, client_address));
thread.start();
thread_counter += 1;
def ConnectionThread(client_socket, client_address):
try:
print '** Connection from %s:%s opened.' % client_address;
while 1:
try:
request_headers, request_content = ReadRequest(client_socket);
if request_headers is None:
break;
response = HandleRequest(request_headers, request_content);
try:
client_socket.send(response);
except socket.error, e:
raise ConnectionError('Cannot send response');
except ConnectionError, e:
print ' ConnectionError: %s' % e;
try:
client_socket.close();
except:
pass;
break;
print '** Connection from %s:%s closed' % client_address;
except:
thread.interrupt_main();
class ConnectionError(Exception):
def __init__(self, value):
self.value = value;
def __str__(self):
return self.value;
def GetContentLength(request_headers):
for request_header in request_headers:
if request_header.find(':') != -1:
name, value = request_header.split(':', 1);
if name.strip().lower() == 'content-length':
try:
return int(value);
except ValueError:
raise ConnectionError('Bad content-length value: %s' % value);
return None;
def ReadRequest(client_socket):
request = '';
request_headers = None;
request_headers_length = None;
if VERBOSE_OUTPUT:
print '>> Accepted request, reading headers...',;
while request_headers is None:
try:
request += client_socket.recv(256);
except socket.error, e:
if VERBOSE_OUTPUT:
print;
raise ConnectionError('Connection dropped while reading request headers.');
if len(request) == 0:
if VERBOSE_OUTPUT:
print;
# raise ConnectionError('Connection closed.');
return None, None;
request_headers_length = request.find('\r\n\r\n');
if request_headers_length != -1:
request_headers = request[:request_headers_length].split('\r\n')[:-1];
# One line breaks is part of the headers
request_headers_length += 2;
# The other is not part of the headers or the content:
request_content_length = GetContentLength(request_headers);
if request_content_length is None:
if VERBOSE_OUTPUT:
print '\r>> Accepted request, read %d bytes of headers and ' \
'no content.' % (request_headers_length);
return request_headers, None;
request_content = request[request_headers_length + 2:];
else:
if VERBOSE_OUTPUT:
print '\r>> Accepted request, read %d bytes of headers...' % \
len(request),;
while len(request_content) < request_content_length:
if VERBOSE_OUTPUT:
print '\r>> Accepted request, read %d bytes of headers and ' \
'%d/%d bytes of content...' % (request_headers_length, \
len(request_content), request_content_length),;
read_size = request_content_length - len(request_content);
try:
request_content += client_socket.recv(read_size);
except socket.error, e:
if VERBOSE_OUTPUT:
print;
raise ConnectionError('Connection dropped while reading request content.');
if VERBOSE_OUTPUT:
print '\r>> Accepted request, read %d bytes of headers and ' \
'%d bytes of content. %s' % (request_headers_length, \
len(request_content), ' ' * len(str(request_content_length)));
return request_headers, request_content;
def HandleRequest(request_headers, request_content):
end_method = request_headers[0].find(' ');
if end_method == -1:
raise ConnectionError('Bad request header; no method recognized');
method = request_headers[0][:end_method];
end_path = request_headers[0].find(' ', end_method + 1);
if end_path == -1:
raise ConnectionError('Bad request header; no path recognized');
path = request_headers[0][end_method + 1:end_path];
query = None;
start_query = path.find('?');
if start_query != -1:
query = path[start_query:];
path = path[:start_query];
if VERBOSE_OUTPUT:
print ' method=%s, path=%s, query=%s, %s headers' % \
(method, path, query, len(request_headers));
code, reason, mime_type, body = 404, 'Not found', 'text/plain', 'Not found';
response = None;
for path_regexp, response in replies:
if re.match(path_regexp, path):
if type(response) != tuple:
response = response(path, query, request_content);
break;
assert type(response) == tuple and len(response) in [2, 4, 5], \
'Invalid response tuple %s' % repr(response);
code, reason, headers, mime_type, body = 200, 'OK', [], 'text/plain', '';
if len(response) == 2:
mime_type, body = response;
elif len(response) == 4:
code, reason, mime_type, body = response;
else:
code, reason, headers, mime_type, body = response;
response_lines = [
'HTTP/1.1 %03d %s' % (code, reason),
'Content-Type: %s' % mime_type,
'Date: Sat Aug 28 1976 09:15:00 GMT',
'Expires: Sat Aug 28 1976 09:15:00 GMT',
'Cache-Control: no-cache, must-revalidate',
'Pragma: no-cache',
'Accept-Ranges: bytes',
'Content-Length: %d' % len(body),
] + headers + [
'',
body
];
response = '\r\n'.join(response_lines);
if VERBOSE_OUTPUT:
print '<< %s (%d bytes %s)' % \
(response.split('\r\n')[0], len(response), mime_type);
return response;
if __name__ == "__main__":
Main();