Python服务器记录器

Python服务器记录器,python,Python,我需要一些帮助来弄清楚为什么它不能按应有的方式工作。目标是建立一个本地python服务器(类似于SimpleHTTPServer),但让它记录对文件的请求/响应,以便更好地了解浏览器DOM的行为。我希望能够浏览到localhost,并让它像Web服务器一样进行响应 使用此选项时,它似乎挂起在localhost上,而不是将其重定向到“sample.html”文件。有没有想过为什么会发生这种情况 代码: 导入操作系统、re、套接字、线程、线程; #您可能要更改的设置: WEBSERVER_PORT=

我需要一些帮助来弄清楚为什么它不能按应有的方式工作。目标是建立一个本地python服务器(类似于SimpleHTTPServer),但让它记录对文件的请求/响应,以便更好地了解浏览器DOM的行为。我希望能够浏览到localhost,并让它像Web服务器一样进行响应

使用此选项时,它似乎挂起在localhost上,而不是将其重定向到“sample.html”文件。有没有想过为什么会发生这种情况

代码:

导入操作系统、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();