我需要一些帮助来弄清楚为什么这不应该按照它应该的方式工作。目标是站起来一个本地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();
非常感谢任何反馈。
谢谢!