Python服务器记录器

时间:2017-05-15 21:38:34

标签: python

我需要一些帮助来弄清楚为什么这不应该按照它应该的方式工作。目标是站起来一个本地python服务器(类似于SimpleHTTPServer),但让它记录对文件的请求/响应,以便更好地理解浏览器DOM的行为方式。我希望能够浏览到localhost并让它像网络服务器那样做出反应。

使用它时,它似乎挂在localhost上,而不是重定向'sample.html'文件。有关为什么会发生这种情况的任何想法?

代码:

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();

非常感谢任何反馈。

谢谢!

0 个答案:

没有答案