# http_server.py : Simple HTTP server.
#
# Java applets running in a browser can only make network connections
# back to the host from which they came.  (Full-blown Java
# applications have no such limitation.)  This means that microscope
# servers need to run an HTTP server that will return the JAR file
# containing the applet.  I don't want to run a full-blown Web server
# such as Apache, or even WN, on the microscope servers, hence this
# little HTTP server.  
#
# Unfortunately, I found by experimenting that 
# you can't just put codebase="http://microscopeserver/" in the APPLET
# tag, but actually have to retrieve the HTML page from the same
# server.  Therefore, this little server allows retrieving the HTML
# page and images, too.  All other URLs trigger 404 errors.
#
# XXX doesn't read its FIFO, but it should!

__revision__ = "$Id: http_server.py,v 1.30 2002/03/29 17:03:22 akuchlin Exp $"

from SimpleHTTPServer import SimpleHTTPRequestHandler
import SocketServer, os, socket, cStringIO
import re, string, sys, time

from mems.instrument.server import util
from mems.instrument.server.configuration import get_configuration

# Base directory where the server code resides; the HTTP server uses
# this to find the files in the data/ subdirectory.  

BASEDIR="/www/scope/docroot"

class JarSocketServer(SocketServer.TCPServer):
    def server_bind(self):
        """Called by constructor to bind the socket.

        May be overridden.

        """
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
        self.socket.bind(self.server_address)

    def handle_request(self):
        """Handle one request, possibly blocking."""
        try:
            request, client_address = self.get_request()
            if self.verify_request(request, client_address):
                try:
                    self.process_request(request, client_address)
                except:
                    self.handle_error(request, client_address)
        except IOError:
            pass # Swallow 'broken pipe' error messages
        except socket.error:
            pass # Swallow other socket errors

    def handle_error(self, request, client_address):
        msg = 'Exception happened during processing of request from '
        msg = msg + str(client_address) 
        import traceback
        file = cStringIO.StringIO()
        traceback.print_exc( file = file)
        msg = msg + file.getvalue()
        util.log("%s: %s" % (__name__, msg) )


class JarHTTPRequestHandler(SimpleHTTPRequestHandler):

    def send_head(self):
        """Common code for GET and HEAD commands.

        This sends the response code and MIME headers.

        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.

        """
        # Get the query string from the URL
        index = string.rfind(self.path, '?')
        if index == -1: path, query_string = self.path, ""
        else: path, query_string = self.path[:index], self.path[index+1:]

        # If it's not one of the files we're supporting, return a
        # 404 File Not Found error.
        if (path not in ['/microscope.jar', '/index.html',
                         '/images/coord_panel.png',
                         '/images/chat_panel.png', '/images/small_screen.png',
                         '/images/menu_panel.png', '/images/focus_panel.png',
                         '/images/control_panel.png',
                         '/images/disp_panel.png']):
            self.send_error(404, "File not found")
            return None

        # Return the requested file.
        fs_path = os.path.join(BASEDIR, path[1:])
        try:
            f = open(fs_path, 'rb')
        except IOError:
            self.send_error(404, "File not found -- no such file")
            return None
            
        self.send_response(200)

        # For index.html, we have to substitute the hostname, port,
        # and authentication token into the PARAM tags for the Java applet.
        if path == '/index.html':
            mime_type = 'text/html'
            L = string.split(query_string, ',',  4)
            if len(L) != 5:
                # XXX error handling
                data = """<p>There seems to be a problem with
the authentication token that has been generated for you.  This is a
debugging message.
<!-- Info provided:
%s
-->
""" % repr(L)                
            else:
                user_id, email, hostname, port, authtoken = L
                data = f.read()
                data = re.sub('%([^(])', r'%%\1', data)
		http_port = get_configuration().server.http_port

            self.send_header("Content-type", mime_type)
            self.end_headers()
            try:
                self.wfile.write(data % vars() )
            except IOError:
                pass # Ignore write errors; maybe the connection was broken
            f.close()
            return None

        # Handle static images
        elif path[-4:] == '.png':
            # Return a PNG file
            mime_type = 'image/png'
            self.send_header("Content-type", mime_type)
            self.end_headers()
            return f
        else:
            # Return the JAR file as a binary.
            mime_type = 'application/java-archive'
            self.send_header("Content-type", mime_type)
            self.end_headers()
            return f

    
def main ():
    server_address = ('', get_configuration().server.http_port)
    httpd = JarSocketServer(server_address, JarHTTPRequestHandler)
    httpd.serve_forever()
