Files
PlantAI-dev/tools/pymol-open-source/modules/web/examples/justhttpd.py
T

225 lines
7.5 KiB
Python
Raw Normal View History

2026-08-03 18:42:47 +08:00
# Copyright (C) Schrodinger, LLC.
# All Rights Reserved
#
# For more information, see LICENSE in PyMOL's home directory.
#
# justhttpd.py
#
# vanilla web server designed for testing multi-origin applications
# by serving up content on 127.0.0.1:xxxx instead of localhost:yyyy
from __future__ import print_function
import BaseHTTPServer, cgi, urlparse, socket
import types, os, sys, traceback, threading
class _HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
self.process_request()
def do_POST(self):
self.process_request()
def process_request(self):
"""
parse any URL or FORM arguments and process the request
"""
# verify that the request is coming from localhost
try:
host, port = self.client_address
if host != '127.0.0.1':
self.send_error(403,
"Only localhost requests are allowed (not: %s)"
% host)
else:
self.callback = None
self.parse_args()
self.send_doc()
except socket.error:
pass
def parse_args(self):
if (self.command == "POST"):
self.fs = cgi.FieldStorage(fp=self.rfile, headers=self.headers,
environ = {'REQUEST_METHOD':'POST'},
keep_blank_values = 1)
self.urlpath = self.path
elif (self.command == "GET"):
scheme,netloc,path,params,qs,fragment = urlparse.urlparse(self.path)
self.fs = cgi.FieldStorage(environ = {'REQUEST_METHOD':'GET',
'QUERY_STRING':qs},
keep_blank_values = 1)
self.urlpath = path
else:
self.fs = None
def send_doc(self):
"""
send a document (file) in the current directory or any sub-directory
"""
path_list = self.path.split('/')[1:]
if '..' in path_list: # prevent access to parent directories
self.send_error(404,"Illegal path.")
self.wfile.write(": %s" % self.path)
elif self.server.root == None:
self.send_error(404,"No content root specified.")
else:
try:
full_path = os.path.join(*[self.server.root] +
list(path_list))
print(full_path)
if os.path.isdir(full_path):
full_path = full_path + "/index.html"
fp = open(full_path,"rb")
self.send_ok(self.guess_mime(full_path))
self.wfile.write(fp.read())
fp.close()
except:
self.send_error(404,"Unable to locate document.")
self.wfile.write(": %s" % self.path)
self.wfile.write(str(sys.exc_info())) # exc_info() is thread safe
# self.wfile.write(sys.exc_value) # exc_value is not thread safe
def guess_mime(self,path):
"""
guess the mime type based on the file extension
"""
if path.endswith('.html'):
return 'text/html'
elif path.endswith('.js'):
return 'application/x-javascript'
elif path.endswith('.jpg'):
return 'image/jpeg'
elif path.endswith('.png'):
return 'image/png'
elif path.endswith('.gif'):
return 'image/gif'
elif path.endswith('.sdf'):
return 'chemical/x-mdl-sdfile'
elif path.endswith('.mol'):
return 'chemical/x-mdl-molfile'
elif path.endswith('.pwg'):
return 'application/x-pymol'
else:
return 'text/plain'
def send_error(self,errcode,errmsg):
try:
self.send_response(errcode)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write("HTTPd-Error: "+errmsg+"\n")
except:
# right now we're swallowing any/all exceptions
# (e.g. Broken Pipe)
pass
def send_ok(self, mime='text/html'):
self.send_response(200)
self.send_header('Content-type', mime)
self.send_header('Pragma','no-cache')
self.send_header('Cache-Control','no-cache, must-revalidate')
self.send_header('Expires','Sat, 10 Jan 2008 01:00:00 GMT')
self.end_headers()
def echo_args(self):
"""
for debugging requests
"""
self.wfile.write("%s\n" % self.command)
if (self.fs):
for k in self.fs.keys():
self.wfile.write("%s = " % k)
# key can have multiple values, as with checkboxes,
# but also arbitrarily
if (isinstance(self.fs[k], types.ListType)):
self.wfile.write("%s\n" % self.fs.getlist(k))
else:
# key can be uploaded file
if (self.fs[k].filename):
self.wfile.write("%s\n" % self.fs[k].filename)
fp = self.fs[k].file
#self.wfile.write("FILE %s" % cgi.escape(repr(fp)))
#self.wfile.write("%s\n" % fp.name)
# fails for StringIO instances
self.wfile.write("%s\n" % repr(fp))
# two ways to get file contents
#file_contents = self.fs.getvalue(k)
#file_contents = fp.read()
#self.wfile.write("%s" % file_contents)
else:
#plain-old key/value
self.wfile.write("%s\n" % self.fs.getvalue(k))
else:
self.wfile.write("No args\n")
class PlainHttpd:
def __init__(self, port=0, root=None):
self.port = int(port)
self.stop_event = threading.Event()
self.stop_event.set()
self.root = root
self.server = BaseHTTPServer.HTTPServer(('', self.port),
_HTTPRequestHandler)
if self.port == 0:
self.port = self.server.socket.getsockname()[1]
self.server.root = self.root
def _server_thread(self):
while not self.stop_event.isSet():
self.server.handle_request()
def start(self): # spawn thread
print(" HTTPd: serving requests on http://127.0.0.1:%d" % self.port)
t = threading.Thread(target=self._server_thread)
t.setDaemon(1)
self.stop_event.clear()
t.start()
def stop(self):
if not self.stop_event.isSet():
self.stop_event.set()
try: # create a request in order to release the handler
import urllib
urllib.urlopen("http://localhost:%d" % self.port)
except:
pass
self.server.socket.close()
def main():
import os
# initialize the server, with current local working directory as root
server = PlainHttpd(0, ".")
# get a dynamically assigned port number
port = server.port
# start handling requests
server.start()
# now launch a browser pointing at our server
import webbrowser
webbrowser.open("http://127.0.0.1:%d"%port)
if __name__ in [ '__main__', 'pymol' ]:
# intended to be launched with normal Python or
# pymol -qc justhttpd.py
main()
import time
while 1:
time.sleep(1)