/[secure-testing]/lib/python/web_support.py
ViewVC logotype

Diff of /lib/python/web_support.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 12983 by fw, Sun Oct 11 10:23:56 2009 UTC revision 12984 by fw, Sun Oct 11 12:02:02 2009 UTC
# Line 26  import grp Line 26  import grp
26  import traceback  import traceback
27  import types  import types
28  import urllib  import urllib
29    import threading
30    import SocketServer
31    import BaseHTTPServer
32    
33  class ServinvokeError(Exception):  class ServinvokeError(Exception):
34      pass      pass
# Line 556  class Result: Line 559  class Result:
559      def flatten(self, write):      def flatten(self, write):
560          pass          pass
561    
562        def flatten_later(self):
563            """Flattens this result.
564    
565            Returns a closure which sends the result using a
566            BaseHTTPRequestHandler object passed as argument."""
567            pass
568    
569  class RedirectResult(Result):  class RedirectResult(Result):
570      """Permanently redirects the browser to a new URL."""      """Permanently redirects the browser to a new URL."""
571      def __init__(self, url, permanent=True):      def __init__(self, url, permanent=True):
# Line 568  class RedirectResult(Result): Line 578  class RedirectResult(Result):
578      def flatten(self, write):      def flatten(self, write):
579          write("Status: %d\nLocation: %s\n\n" % (self.status, self.url))          write("Status: %d\nLocation: %s\n\n" % (self.status, self.url))
580    
581        def flatten_later(self):
582            def later(req):
583                req.send_response(self.status)
584                req.send_header('Location', self.url)
585                req.end_headers()
586            return later
587    
588  class HTMLResult(Result):  class HTMLResult(Result):
589      """An object of this class combines a status code with HTML contents."""      """An object of this class combines a status code with HTML contents."""
590      def __init__(self, contents, status=200, doctype=''):      def __init__(self, contents, status=200, doctype=''):
# Line 584  class HTMLResult(Result): Line 601  class HTMLResult(Result):
601          write("Content-Type: text/html\n\n%s\n" % self.doctype)          write("Content-Type: text/html\n\n%s\n" % self.doctype)
602          self.contents.flatten(write)          self.contents.flatten(write)
603    
604        def flatten_later(self):
605            buf = cStringIO.StringIO()
606            buf.write(self.doctype)
607            buf.write('\n')
608            self.contents.flatten(buf.write)
609            buf = buf.getvalue()
610            def later(req):
611                req.send_response(self.status)
612                req.send_header('Content-Type', 'text/html; charset=UTF-8')
613                req.end_headers()
614                req.wfile.write(buf)
615            return later
616    
617  class BinaryResult(Result):  class BinaryResult(Result):
618      """An object of this class combines a status code with HTML contents."""      """An object of this class combines a status code with HTML contents."""
619      def __init__(self, contents, status=200,      def __init__(self, contents, status=200,
# Line 599  class BinaryResult(Result): Line 629  class BinaryResult(Result):
629          write("Content-Type: %s\n\n" % self.mimetype)          write("Content-Type: %s\n\n" % self.mimetype)
630          write(self.contents)          write(self.contents)
631    
632        def flatten_later(self):
633            def later(req):
634                req.send_response(self.status)
635                req.send_header('Content-Type', self.mimetype)
636                req.wfile.write(self.contents)
637            return later
638    
639  class WebServiceBase:  class WebServiceBase:
640      def __init__(self):      def __init__(self):
641          self.router = PathRouter()          self.router = PathRouter()
# Line 679  class WebService(Service, WebServiceBase Line 716  class WebService(Service, WebServiceBase
716          assert isinstance(r, Result), `r`          assert isinstance(r, Result), `r`
717          r.flatten(result.write)          r.flatten(result.write)
718    
719    class ThreadingHTTPServer(BaseHTTPServer.HTTPServer,
720                              SocketServer.ThreadingMixIn):
721        pass
722    
723    RE_BASE_URL = re.compile(r'^http://([^/]+)(.*)')
724    
725    class WebServiceHTTP(WebServiceBase):
726        def __init__(self, socket_name):
727            WebServiceBase.__init__(self)
728            (base_url, address, port) = socket_name
729            self.lock = threading.Lock()
730    
731            self.__parse_base_url(base_url)
732    
733            service_self = self
734            class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
735                def do_GET(self):
736                    (method, path, remaining, params) = self.route()
737                    if path is None:
738                        return
739    
740                    url = URLFactory(service_self.server_name,
741                                     service_self.script_name,
742                                     path, params)
743    
744                    service_self.lock.acquire()
745                    try:
746                        service_self.pre_dispatch()
747                        r = method(remaining, params, url)
748                        assert isinstance(r, Result), `r`
749                        result = r.flatten_later()
750                    finally:
751                        service_self.lock.release()
752                    result(self)
753    
754                def __parse_path(self):
755                    pos = self.path.find('?')
756                    if pos < 0:
757                        return (self.path, {})
758                    path = self.path[:pos]
759                    if path[:1] != '/':
760                        path = '/' + path
761                    params = cgi.parse_qs(self.path[pos + 1:])
762                    return (path, params)
763    
764                def route(self):
765                    (path, params) = self.__parse_path()
766                    prefix_len = len(service_self.script_name)
767                    prefix = path[0:prefix_len]
768                    result = None
769                    if prefix == service_self.script_name:
770                        suffix = path[prefix_len:]
771                        try:
772                            (method, remaining) = \
773                                service_self.router.get(suffix)
774                            return (method, suffix, remaining, params)
775                        except InvalidPath:
776                            pass
777                    self.send_error(404, "page not found")
778                    return (None, None, None, None)
779    
780            self.server = ThreadingHTTPServer((address, port), Handler)
781    
782        def run(self):
783            self.server.serve_forever()
784    
785        def __parse_base_url(self, url):
786            m = RE_BASE_URL.match(url)
787            if m is None:
788                raise ValueError("invalid base URL: " + url)
789            self.server_name = m.group(1)
790            self.script_name = m.group(2)
791    
792    
793  def __test():  def __test():
794      assert str(URL("")) == ""      assert str(URL("")) == ""
795      assert str(URL("abc")) == "abc"      assert str(URL("abc")) == "abc"

Legend:
Removed from v.12983  
changed lines
  Added in v.12984

  ViewVC Help
Powered by ViewVC 1.1.5