schrodinger.application.glide.http_server module

Glide HTTP Server

This module implements the functions necessary to turn Glide into a persistent HTTP server that accepts ligands via POST requests and sends the poses back.

To use, just add the following lines to a Glide input file:

CLIENT_MODULE schrodinger.application.glide.http_server CLIENT_OPTIONS “host=localhost; port=8000”

The server may then be tested using a web browser by opening http://localhost:8000/. For programmatic access, see

The server responds to the following paths:

/ a form that can be used for testing from a browser /shutdown break out of the ligand loop and terminate /dock_ligand POST a ligand and get the poses back

NOTE: the server is single-threaded, single-process, hence it’s not designed to accept concurrent connections. While Glide is busy docking a ligand, the server won’t be accepting connections. This server is meant for uses where there is a single client that only needs to do one ligand at a time!

class schrodinger.application.glide.http_server.GlideHTTPHandler(request, client_address, server)

Bases: http.server.BaseHTTPRequestHandler

This class, derived from BaseHTTPRequestHandler, implements the do_GET and do_POST methods. Unlike the parent class, this handler does not “finish” immediately after calling do_GET/do_POST, but waits until glide_finish() is called.


  • glide_data (dict[str, list]) – a dictionary containing the posted form data.

  • glide_stop (bool) – a boolean, set to True if the client asked us to stop.

glide_data = Ellipsis
glide_stop = Ellipsis
glide_send_response(ctype, body)

Convenience method to send the response line, content-type header, and body in just one call.


Finish the handler by calling the finish() method from the parent class. Among other things, this closes the connection.


alias of http.client.HTTPMessage

__init__(request, client_address, server)

Return the client address.


Return the current date and time formatted for a message header.

default_request_version = 'HTTP/0.9'
disable_nagle_algorithm = False

Send the blank line ending the MIME headers.

error_content_type = 'text/html;charset=utf-8'
error_message_format = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n        "">\n<html>\n    <head>\n        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">\n        <title>Error response</title>\n    </head>\n    <body>\n        <h1>Error response</h1>\n        <p>Error code: %(code)d</p>\n        <p>Message: %(message)s.</p>\n        <p>Error code explanation: %(code)s - %(explain)s.</p>\n    </body>\n</html>\n'

Handle multiple requests if necessary.


Decide what to do with an “Expect: 100-continue” header.

If the client is expecting a 100 Continue response, we must respond with either a 100 Continue or a final response before waiting for the request body. The default is to always respond with a 100 Continue. You can behave differently (for example, reject unauthorized requests) by overriding this method.

This method should either return True (possibly after sending a 100 Continue response) or send an error response and return False.


Handle a single HTTP request.

You normally don’t need to override this method; see the class __doc__ string for information on how to handle specific HTTP commands such as GET and POST.


Return the current time formatted for logging.

log_error(format, *args)

Log an error.

This is called when a request cannot be fulfilled. By default it passes the message on to log_message().

Arguments are the same as for log_message().

XXX This should go to the separate error log.

log_message(format, *args)

Log an arbitrary message.

This is used by all other logging functions. Override it if you have specific logging wishes.

The first argument, FORMAT, is a format string for the message to be logged. If the format string contains any % escapes requiring parameters, they should be specified as subsequent arguments (it’s just like printf!).

The client ip and current date/time are prefixed to every message.

log_request(code='-', size='-')

Log an accepted request.

This is called by send_response().

monthname = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

Parse a request (internal).

The request should be stored in self.raw_requestline; the results are in self.command, self.path, self.request_version and self.headers.

Return True for success, False for failure; on failure, any relevant error response has already been sent back.

protocol_version = 'HTTP/1.0'
rbufsize = -1
responses = {HTTPStatus.CONTINUE: ('Continue', 'Request received, please continue'), HTTPStatus.SWITCHING_PROTOCOLS: ('Switching Protocols', 'Switching to new protocol; obey Upgrade header'), HTTPStatus.PROCESSING: ('Processing', ''), HTTPStatus.OK: ('OK', 'Request fulfilled, document follows'), HTTPStatus.CREATED: ('Created', 'Document created, URL follows'), HTTPStatus.ACCEPTED: ('Accepted', 'Request accepted, processing continues off-line'), HTTPStatus.NON_AUTHORITATIVE_INFORMATION: ('Non-Authoritative Information', 'Request fulfilled from cache'), HTTPStatus.NO_CONTENT: ('No Content', 'Request fulfilled, nothing follows'), HTTPStatus.RESET_CONTENT: ('Reset Content', 'Clear input form for further input'), HTTPStatus.PARTIAL_CONTENT: ('Partial Content', 'Partial content follows'), HTTPStatus.MULTI_STATUS: ('Multi-Status', ''), HTTPStatus.ALREADY_REPORTED: ('Already Reported', ''), HTTPStatus.IM_USED: ('IM Used', ''), HTTPStatus.MULTIPLE_CHOICES: ('Multiple Choices', 'Object has several resources -- see URI list'), HTTPStatus.MOVED_PERMANENTLY: ('Moved Permanently', 'Object moved permanently -- see URI list'), HTTPStatus.FOUND: ('Found', 'Object moved temporarily -- see URI list'), HTTPStatus.SEE_OTHER: ('See Other', 'Object moved -- see Method and URL list'), HTTPStatus.NOT_MODIFIED: ('Not Modified', 'Document has not changed since given time'), HTTPStatus.USE_PROXY: ('Use Proxy', 'You must use proxy specified in Location to access this resource'), HTTPStatus.TEMPORARY_REDIRECT: ('Temporary Redirect', 'Object moved temporarily -- see URI list'), HTTPStatus.PERMANENT_REDIRECT: ('Permanent Redirect', 'Object moved permanently -- see URI list'), HTTPStatus.BAD_REQUEST: ('Bad Request', 'Bad request syntax or unsupported method'), HTTPStatus.UNAUTHORIZED: ('Unauthorized', 'No permission -- see authorization schemes'), HTTPStatus.PAYMENT_REQUIRED: ('Payment Required', 'No payment -- see charging schemes'), HTTPStatus.FORBIDDEN: ('Forbidden', 'Request forbidden -- authorization will not help'), HTTPStatus.NOT_FOUND: ('Not Found', 'Nothing matches the given URI'), HTTPStatus.METHOD_NOT_ALLOWED: ('Method Not Allowed', 'Specified method is invalid for this resource'), HTTPStatus.NOT_ACCEPTABLE: ('Not Acceptable', 'URI not available in preferred format'), HTTPStatus.PROXY_AUTHENTICATION_REQUIRED: ('Proxy Authentication Required', 'You must authenticate with this proxy before proceeding'), HTTPStatus.REQUEST_TIMEOUT: ('Request Timeout', 'Request timed out; try again later'), HTTPStatus.CONFLICT: ('Conflict', 'Request conflict'), HTTPStatus.GONE: ('Gone', 'URI no longer exists and has been permanently removed'), HTTPStatus.LENGTH_REQUIRED: ('Length Required', 'Client must specify Content-Length'), HTTPStatus.PRECONDITION_FAILED: ('Precondition Failed', 'Precondition in headers is false'), HTTPStatus.REQUEST_ENTITY_TOO_LARGE: ('Request Entity Too Large', 'Entity is too large'), HTTPStatus.REQUEST_URI_TOO_LONG: ('Request-URI Too Long', 'URI is too long'), HTTPStatus.UNSUPPORTED_MEDIA_TYPE: ('Unsupported Media Type', 'Entity body in unsupported format'), HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE: ('Requested Range Not Satisfiable', 'Cannot satisfy request range'), HTTPStatus.EXPECTATION_FAILED: ('Expectation Failed', 'Expect condition could not be satisfied'), HTTPStatus.MISDIRECTED_REQUEST: ('Misdirected Request', 'Server is not able to produce a response'), HTTPStatus.UNPROCESSABLE_ENTITY: ('Unprocessable Entity', ''), HTTPStatus.LOCKED: ('Locked', ''), HTTPStatus.FAILED_DEPENDENCY: ('Failed Dependency', ''), HTTPStatus.UPGRADE_REQUIRED: ('Upgrade Required', ''), HTTPStatus.PRECONDITION_REQUIRED: ('Precondition Required', 'The origin server requires the request to be conditional'), HTTPStatus.TOO_MANY_REQUESTS: ('Too Many Requests', 'The user has sent too many requests in a given amount of time ("rate limiting")'), HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE: ('Request Header Fields Too Large', 'The server is unwilling to process the request because its header fields are too large'), HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS: ('Unavailable For Legal Reasons', 'The server is denying access to the resource as a consequence of a legal demand'), HTTPStatus.INTERNAL_SERVER_ERROR: ('Internal Server Error', 'Server got itself in trouble'), HTTPStatus.NOT_IMPLEMENTED: ('Not Implemented', 'Server does not support this operation'), HTTPStatus.BAD_GATEWAY: ('Bad Gateway', 'Invalid responses from another server/proxy'), HTTPStatus.SERVICE_UNAVAILABLE: ('Service Unavailable', 'The server cannot process the request due to a high load'), HTTPStatus.GATEWAY_TIMEOUT: ('Gateway Timeout', 'The gateway server did not receive a timely response'), HTTPStatus.HTTP_VERSION_NOT_SUPPORTED: ('HTTP Version Not Supported', 'Cannot fulfill request'), HTTPStatus.VARIANT_ALSO_NEGOTIATES: ('Variant Also Negotiates', ''), HTTPStatus.INSUFFICIENT_STORAGE: ('Insufficient Storage', ''), HTTPStatus.LOOP_DETECTED: ('Loop Detected', ''), HTTPStatus.NOT_EXTENDED: ('Not Extended', ''), HTTPStatus.NETWORK_AUTHENTICATION_REQUIRED: ('Network Authentication Required', 'The client needs to authenticate to gain network access')}
send_error(code, message=None, explain=None)

Send and log an error reply.

Arguments are * code: an HTTP error code

3 digits

  • message: a simple optional 1 line reason phrase.

    *( HTAB / SP / VCHAR / %x80-FF ) defaults to short entry matching the response code

  • explain: a detailed message defaults to the long entry

    matching the response code.

This sends an error response (so it must be called before any output has been generated), logs the error, and finally sends a piece of HTML explaining the error to the user.

send_header(keyword, value)

Send a MIME header to the headers buffer.

send_response(code, message=None)

Add the response header to the headers buffer and log the response code.

Also send two standard headers with the server software version and the current date.

send_response_only(code, message=None)

Send the response header only.

server_version = 'BaseHTTP/0.6'
sys_version = 'Python/3.8.10'
timeout = None

Return the server software version string.

wbufsize = 0
weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
class schrodinger.application.glide.http_server.GlideHTTPServer(server_address, RequestHandlerClass, bind_and_activate=True)

Bases: http.server.HTTPServer

This is a variant on HTTPServer that doesn’t shut down requests immediately, but keeps them around until glide_shutdown_request is called. This allows us to split the processing of the request into two steps: one to get the request, and the other to respond to it.

In the meantime, the handler object is kept around in the glide_http_handler property.

  • glide_http_handler (GlideHTTPHandler) – The request handler.

  • glide_request (socket) – The request object.

  • glide_timeout (bool) – Whether the request has timed out.

glide_http_handler = Ellipsis
glide_request = Ellipsis
glide_timeout = Ellipsis
finish_request(request, client_address)

Finish one request by instantiating RequestHandlerClass.


Called to shutdown and close an individual request.


Shut down the current request by calling the shutdown_request method from the parent class.


Handle one request, possibly blocking.

Respects self.timeout.


Called if no new request arrives within self.timeout.

Overridden by ForkingMixIn.

__init__(server_address, RequestHandlerClass, bind_and_activate=True)

Constructor. May be extended, do not override.

address_family = 2
allow_reuse_address = 1

Called to clean up an individual request.


Return socket file number.

Interface required by selector.


Get the request and client address from the socket.

May be overridden.

handle_error(request, client_address)

Handle an error gracefully. May be overridden.

The default is to print a traceback and continue.

process_request(request, client_address)

Call finish_request.

Overridden by ForkingMixIn and ThreadingMixIn.

request_queue_size = 5

Handle one request at a time until shutdown.

Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread.


Called by constructor to activate the server.

May be overridden.


Override server_bind to store the server name.


Called to clean-up the server.

May be overridden.


Called by the serve_forever() loop.

May be overridden by a subclass / Mixin to implement any code that needs to be run during the loop.


Stops the serve_forever loop.

Blocks until the loop has finished. This must be called while serve_forever() is running in another thread, or it will deadlock.

socket_type = 1
timeout = None
verify_request(request, client_address)

Verify the request. May be overridden.

Return True if we should proceed with this request.


Start the HTTP server. Takes a string as an argument that may specify the host and port as, for example, “host=localhost; port=8000; timeout=0”. These are in fact the default values. To accept connections from remote hosts, set host to an empty string (i.e., “host=”). If the timeout value is greater than zero, pull_ligand will return -1, indicating no more ligands, after waiting for that time in seconds.

schrodinger.application.glide.http_server.get_config_as_json(ip_addr, port, backend=None)

Return the body of the config file as a JSON string.

  • ip_addr (str) – server IP address

  • port (int) – server port

  • backend (schrodinger.job.jobcontrol._Backend or NoneType) – optional jobcontrol backend object


Write a JSON file with host and port information so the client knows that the server is ready and where to connect. This is particularly needed when using automated port selection.

When running under job control as a Glide job, the file is copied back to the launch directory immediately.


Wait until someone POSTs a ligand and return its mmct handle. If we were asked to shut down by the client, return -1.

schrodinger.application.glide.http_server.push_ligand(pose_handles, msg)

Send the HTTP response as an m2io file of docked poses. Takes an array of mmct handles and an error message (the latter is currently unused.)

  • pose_handles – mmct handles for docked poses

  • msg (str) – status message from Glide


iterable of int


Delete the HTTP server object and stop listening.


Return the mmct handle to the new reference ligand (MMCT_INVALID_CT if there’s no new reference ligand). The handle is then owned by the caller and the function call has the side effect of making this module forget the current handle.


mmct handle

Return type