~ubuntu-branches/ubuntu/hardy/libapache2-mod-python/hardy

« back to all changes in this revision

Viewing changes to lib/python/mod_python/apache.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2006-07-07 13:18:35 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060707131835-zfp1vupanjj2e77y
Tags: 3.2.8-1ubuntu1
* Merge to Debian unstable.
* Remaining Ubuntu change: debian/{control,rules}: Drop python 2.3 package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 #
2
 
 # Copyright 2004 Apache Software Foundation 
3
 
 # 
 
2
 # Copyright 2004 Apache Software Foundation
 
3
 #
4
4
 # Licensed under the Apache License, Version 2.0 (the "License"); you
5
5
 # may not use this file except in compliance with the License.  You
6
6
 # may obtain a copy of the License at
15
15
 #
16
16
 # Originally developed by Gregory Trubetskoy.
17
17
 #
18
 
 # $Id: apache.py 102649 2004-02-16 19:47:28Z grisha $
 
18
 # $Id: apache.py 374268 2006-02-02 05:31:45Z nlehuen $
19
19
 
20
20
import sys
21
21
import traceback
41
41
        The actual stack string lives in the request object so
42
42
        it can be manipulated by both apache.py and mod_python.c
43
43
        """
44
 
        
 
44
 
45
45
        def __init__(self, req):
46
46
            self.req = req
47
47
 
128
128
            finally:
129
129
                exc_traceback = None
130
130
 
131
 
        return result
 
131
        return result
132
132
 
133
133
    def FilterDispatch(self, filter):
134
134
 
154
154
 
155
155
            # add the directory to pythonpath if
156
156
            # not there yet, or pythonpath specified
157
 
            
 
157
 
158
158
            if config.has_key("PythonPath"):
159
159
                # we want to do as little evaling as possible,
160
160
                # so we remember the path in un-evaled form and
201
201
                        req.status = status
202
202
                else:
203
203
                    result = value.args[0]
204
 
                    
 
204
 
205
205
                if type(result) != type(7):
206
206
                    s = "Value raised with SERVER_RETURN is invalid. It is a "
207
207
                    s = s + "%s, but it must be a tuple or an int." % type(result)
234
234
            finally:
235
235
                exc_traceback = None
236
236
 
237
 
        return OK
 
237
        return OK
238
238
 
239
239
    def HandlerDispatch(self, req):
240
240
        """
251
251
        try:
252
252
            hlist = req.hlist
253
253
 
254
 
            while hlist.handler:
 
254
            while hlist.handler is not None:
255
255
 
256
256
                # split module::handler
257
257
                l = hlist.handler.split('::', 1)
304
304
                    # stop cycling through handlers
305
305
                    if result != OK:
306
306
                        break
307
 
                    
 
307
 
308
308
                elif hlist.silent:
309
 
                    result = DECLINED
 
309
                    # A faulty handler marked as silent will only 
 
310
                    # propagate DECLINED if it is the first and only handler.
 
311
                    if result != OK:
 
312
                        result = DECLINED
310
313
 
311
314
                hlist.next()
312
315
 
320
323
                        req.status = status
321
324
                else:
322
325
                    result = value.args[0]
323
 
                    
 
326
 
324
327
                if type(result) != type(7):
325
328
                    s = "Value raised with SERVER_RETURN is invalid. It is a "
326
329
                    s = s + "%s, but it must be a tuple or an int." % type(result)
349
352
            finally:
350
353
                exc_traceback = None
351
354
 
352
 
        return result
 
355
        return result
353
356
 
354
357
 
355
358
    def ReportError(self, etype, evalue, etb, req=None, filter=None, srv=None,
356
359
                    phase="N/A", hname="N/A", debug=0):
357
 
        """ 
358
 
        This function is only used when debugging is on.
359
 
        It sends the output similar to what you'd see
360
 
        when using Python interactively to the browser
361
 
        """
362
 
 
 
360
        """
 
361
        This function is only used when debugging is on.
 
362
        It sends the output similar to what you'd see
 
363
        when using Python interactively to the browser
 
364
        """
363
365
        try:       # try/finally
364
366
            try:        # try/except
365
367
 
388
390
                    for e in traceback.format_exception(etype, evalue, etb):
389
391
                        s = s + e + '\n'
390
392
                    s = s + "</pre>\n"
391
 
                        
 
393
 
392
394
                    if filter:
393
395
                        filter.write(s)
394
396
                        filter.flush()
412
414
    if it has changed since the last import.
413
415
    """
414
416
 
415
 
    # (Re)import
416
 
    if sys.modules.has_key(module_name):
417
 
 
418
 
        # The module has been imported already
419
 
        module = sys.modules[module_name]
420
 
 
421
 
        # but is it in the path?
422
 
        file = module.__dict__.get("__file__")
423
 
 
424
 
        # the "and not" part of this condition is to prevent execution
425
 
        # of arbitrary already imported modules, such as os. The
426
 
        # reason we use startswith as opposed to exact match is that
427
 
        # modules inside packages are actually in subdirectories.
428
 
 
429
 
        if not file or (path and not filter(file.startswith, path)):
430
 
            # there is a script by this name already imported, but it's in
431
 
            # a different directory, therefore it's a different script
 
417
    # nlehuen: this is a big lock, we'll have to refine it later to get better performance.
 
418
    # For now, we'll concentrate on thread-safety.
 
419
    imp.acquire_lock()
 
420
    try:
 
421
        # (Re)import
 
422
        if sys.modules.has_key(module_name):
 
423
 
 
424
            # The module has been imported already
 
425
            module = sys.modules[module_name]
 
426
 
 
427
            # but is it in the path?
 
428
            file = module.__dict__.get("__file__")
 
429
 
 
430
            # the "and not" part of this condition is to prevent execution
 
431
            # of arbitrary already imported modules, such as os. The
 
432
            # reason we use startswith as opposed to exact match is that
 
433
            # modules inside packages are actually in subdirectories.
 
434
 
 
435
            if not file or (path and not filter(file.startswith, path)):
 
436
                # there is a script by this name already imported, but it's in
 
437
                # a different directory, therefore it's a different script
 
438
                mtime, oldmtime = 0, -1
 
439
            elif autoreload:
 
440
                oldmtime = module.__dict__.get("__mtime__", 0)
 
441
                mtime = module_mtime(module)
 
442
            else:
 
443
                mtime, oldmtime = 0, 0
 
444
 
 
445
        else:
432
446
            mtime, oldmtime = 0, -1
433
 
        elif autoreload: 
434
 
            oldmtime = module.__dict__.get("__mtime__", 0)
435
 
            mtime = module_mtime(module)
436
 
        else:
437
 
            mtime, oldmtime = 0, 0
438
 
 
439
 
    else:
440
 
        mtime, oldmtime = 0, -1
441
 
 
442
 
    if mtime > oldmtime:
443
 
 
444
 
        # Import the module
445
 
        if log:
446
 
            if path:
447
 
                s = "mod_python: (Re)importing module '%s' with path set to '%s'" % (module_name, path)
448
 
            else:
449
 
                s = "mod_python: (Re)importing module '%s'" % module_name
450
 
            _apache.log_error(s, APLOG_NOERRNO|APLOG_NOTICE)
451
 
 
452
 
        parts = module_name.split('.')
453
 
        for i in range(len(parts)):
454
 
            f, p, d = imp.find_module(parts[i], path)
455
 
            try:
456
 
                mname = ".".join(parts[:i+1])
457
 
                module = imp.load_module(mname, f, p, d)
458
 
            finally:
459
 
                if f: f.close()
460
 
            if hasattr(module, "__path__"):
461
 
                path = module.__path__
462
 
 
463
 
        if mtime == 0:
464
 
            mtime = module_mtime(module)
465
 
 
466
 
        module.__mtime__ = mtime
467
 
 
468
 
    return module
 
447
 
 
448
        if mtime != oldmtime:
 
449
 
 
450
            # Import the module
 
451
            if log:
 
452
                if path:
 
453
                    s = "mod_python: (Re)importing module '%s' with path set to '%s'" % (module_name, path)
 
454
                else:
 
455
                    s = "mod_python: (Re)importing module '%s'" % module_name
 
456
                _apache.log_error(s, APLOG_NOERRNO|APLOG_NOTICE)
 
457
 
 
458
            parent = None
 
459
            parts = module_name.split('.')
 
460
            for i in range(len(parts)):
 
461
                f, p, d = imp.find_module(parts[i], path)
 
462
                try:
 
463
                    mname = ".".join(parts[:i+1])
 
464
                    module = imp.load_module(mname, f, p, d)
 
465
                    if parent:
 
466
                        setattr(parent,parts[i],module)
 
467
                    parent = module
 
468
                finally:
 
469
                    if f: f.close()
 
470
                if hasattr(module, "__path__"):
 
471
                    path = module.__path__
 
472
 
 
473
            if mtime == 0:
 
474
                mtime = module_mtime(module)
 
475
 
 
476
            module.__mtime__ = mtime
 
477
 
 
478
        return module
 
479
    finally:
 
480
        imp.release_lock()
469
481
 
470
482
def module_mtime(module):
471
483
    """Get modification time of module"""
472
484
    mtime = 0
473
485
    if module.__dict__.has_key("__file__"):
474
 
        
 
486
 
475
487
       filepath = module.__file__
476
 
       
 
488
 
477
489
       try:
478
490
           # this try/except block is a workaround for a Python bug in
479
491
           # 2.0, 2.1 and 2.1.1. See
537
549
 
538
550
    req.add_common_vars()
539
551
    env = req.subprocess_env.copy()
540
 
        
541
 
    if len(req.path_info) > 0:
 
552
 
 
553
    if req.path_info and len(req.path_info) > 0:
542
554
        env["SCRIPT_NAME"] = req.uri[:-len(req.path_info)]
543
555
    else:
544
556
        env["SCRIPT_NAME"] = req.uri
620
632
            self.buf = self.buf + self.req.read(self.BLOCK)
621
633
            if len(self.buf) == x: # nothing read, eof
622
634
                i = x - 1
623
 
                break 
 
635
                break
624
636
            i = self.buf.find('\n', x)
625
 
        
 
637
 
626
638
        # carve out the piece, then shorten the buffer
627
639
        result = self.buf[:i+1]
628
640
        self.buf = self.buf[i+1:]
629
641
        self.pos = self.pos + len(result)
630
642
        return result
631
 
        
 
643
 
632
644
 
633
645
class CGIStdout(NullIO):
634
646
 
635
647
    """
636
648
    Class that allows writing to the socket directly for CGI.
637
649
    """
638
 
    
 
650
 
639
651
    def __init__(self, req):
640
652
        self.pos = 0
641
653
        self.req = req
642
654
        self.headers_sent = 0
643
655
        self.headers = ""
644
 
        
 
656
 
645
657
    def write(self, s):
646
658
 
647
659
        if not s: return
661
673
                    headers_over = 1
662
674
            else:
663
675
                headers_over = 1
664
 
                    
 
676
 
665
677
            if headers_over:
666
678
                # headers done, process them
667
679
                ss[0] = ss[0].replace('\r\n', '\n')
684
696
                self.req.write(ss[1])
685
697
        else:
686
698
            self.req.write(str(s))
687
 
        
 
699
 
688
700
        self.pos = self.pos + len(s)
689
701
 
690
702
    def tell(self): return self.pos
699
711
 
700
712
    # save env
701
713
    save_env = os.environ.copy()
702
 
    
 
714
 
703
715
    si = sys.stdin
704
716
    so = sys.stdout
705
717
 
706
718
    os.environ.update(build_cgi_env(req))
707
 
 
 
719
 
708
720
    sys.stdout = CGIStdout(req)
709
721
    sys.stdin = CGIStdin(req)
710
722
 
711
723
    sys.argv = [] # keeps cgi.py happy
712
724
 
713
725
    return save_env, si, so
714
 
        
 
726
 
715
727
def restore_nocgi(sav_env, si, so):
716
728
    """ see setup_cgi() """
717
729
 
726
738
    sys.stdout = si
727
739
    sys.stdin = so
728
740
 
729
 
def init():
730
 
    """ 
 
741
_interpreter = None
 
742
_server = None
 
743
_callback = None
 
744
 
 
745
def register_cleanup(handler,data=None):
 
746
    _apache.register_cleanup(_interpreter,_server,handler,data)
 
747
 
 
748
def init(name,server):
 
749
    """
731
750
        This function is called by the server at startup time
732
751
    """
733
752
 
734
 
    return CallBack()
 
753
    global _interpreter
 
754
    global _server
 
755
    _interpreter = name
 
756
    _server = server
 
757
 
 
758
    sys.argv = ["mod_python"]
 
759
 
 
760
    global _callback
 
761
    _callback = CallBack()
 
762
    return _callback
735
763
 
736
764
## Some functions made public
737
765
make_table = _apache.table
740
768
config_tree = _apache.config_tree
741
769
server_root = _apache.server_root
742
770
mpm_query = _apache.mpm_query
 
771
exists_config_define = _apache.exists_config_define
743
772
 
744
773
## Some constants
745
774
 
800
829
    APLOG_EMERG = syslog.LOG_EMERG     # system is unusable
801
830
    APLOG_ALERT = syslog.LOG_ALERT     # action must be taken immediately
802
831
    APLOG_CRIT = syslog.LOG_CRIT       # critical conditions
803
 
    APLOG_ERR = syslog.LOG_ERR         # error conditions 
 
832
    APLOG_ERR = syslog.LOG_ERR         # error conditions
804
833
    APLOG_WARNING = syslog.LOG_WARNING # warning conditions
805
834
    APLOG_NOTICE = syslog.LOG_NOTICE   # normal but significant condition
806
835
    APLOG_INFO = syslog.LOG_INFO       # informational
814
843
    APLOG_NOTICE = 5
815
844
    APLOG_INFO = 6
816
845
    APLOG_DEBUG = 7
817
 
    
 
846
 
818
847
APLOG_NOERRNO = 8
819
848
 
820
849
OK = REQ_PROCEED = 0
829
858
 
830
859
# legacy/mod_python things
831
860
REQ_ABORTED = HTTP_INTERNAL_SERVER_ERROR
832
 
REQ_EXIT = "REQ_EXIT"         
 
861
REQ_EXIT = "REQ_EXIT"
833
862
SERVER_RETURN = _apache.SERVER_RETURN
834
863
PROG_TRACEBACK = "PROG_TRACEBACK"
835
864
 
861
890
 
862
891
# for req.proxyreq
863
892
PROXYREQ_NONE = 0       # No proxy
864
 
PROXYREQ_PROXY = 1      # Standard proxy
865
 
PROXYREQ_REVERSE = 2    # Reverse proxy
 
893
PROXYREQ_PROXY = 1    # Standard proxy
 
894
PROXYREQ_REVERSE = 2    # Reverse proxy
866
895
 
867
896
# methods for req.allow_method()
868
897
M_GET = 0               # RFC 2616: HTTP
872
901
M_CONNECT = 4
873
902
M_OPTIONS = 5
874
903
M_TRACE = 6             # RFC 2616: HTTP
875
 
M_PATCH = 7 
 
904
M_PATCH = 7
876
905
M_PROPFIND = 8          # RFC 2518: WebDAV
877
 
M_PROPPATCH = 9         
 
906
M_PROPPATCH = 9
878
907
M_MKCOL = 10
879
908
M_COPY = 11
880
909
M_MOVE = 12
900
929
 
901
930
 
902
931
# for mpm_query
903
 
AP_MPMQ_NOT_SUPPORTED      = 0  # This value specifies whether 
904
 
                                # an MPM is capable of         
905
 
                                # threading or forking.        
906
 
AP_MPMQ_STATIC             = 1  # This value specifies whether 
 
932
AP_MPMQ_NOT_SUPPORTED      = 0  # This value specifies whether
 
933
                                # an MPM is capable of
 
934
                                # threading or forking.
 
935
AP_MPMQ_STATIC             = 1  # This value specifies whether
907
936
                                # an MPM is using a static # of
908
 
                                # threads or daemons.          
909
 
AP_MPMQ_DYNAMIC            = 2  # This value specifies whether 
 
937
                                # threads or daemons.
 
938
AP_MPMQ_DYNAMIC            = 2  # This value specifies whether
910
939
                                # an MPM is using a dynamic # of
911
 
                                # threads or daemons.          
912
 
 
913
 
AP_MPMQ_MAX_DAEMON_USED    = 1  # Max # of daemons used so far 
914
 
AP_MPMQ_IS_THREADED        = 2  # MPM can do threading         
915
 
AP_MPMQ_IS_FORKED          = 3  # MPM can do forking           
916
 
AP_MPMQ_HARD_LIMIT_DAEMONS = 4  # The compiled max # daemons   
917
 
AP_MPMQ_HARD_LIMIT_THREADS = 5  # The compiled max # threads   
918
 
AP_MPMQ_MAX_THREADS        = 6  # # of threads/child by config 
919
 
AP_MPMQ_MIN_SPARE_DAEMONS  = 7  # Min # of spare daemons       
920
 
AP_MPMQ_MIN_SPARE_THREADS  = 8  # Min # of spare threads       
921
 
AP_MPMQ_MAX_SPARE_DAEMONS  = 9  # Max # of spare daemons       
922
 
AP_MPMQ_MAX_SPARE_THREADS  = 10 # Max # of spare threads       
923
 
AP_MPMQ_MAX_REQUESTS_DAEMON= 11 # Max # of requests per daemon 
924
 
AP_MPMQ_MAX_DAEMONS        = 12 # Max # of daemons by config   
925
 
                                                                                                                                                                                                                                    
 
940
                                # threads or daemons.
 
941
 
 
942
AP_MPMQ_MAX_DAEMON_USED    = 1  # Max # of daemons used so far
 
943
AP_MPMQ_IS_THREADED        = 2  # MPM can do threading
 
944
AP_MPMQ_IS_FORKED          = 3  # MPM can do forking
 
945
AP_MPMQ_HARD_LIMIT_DAEMONS = 4  # The compiled max # daemons
 
946
AP_MPMQ_HARD_LIMIT_THREADS = 5  # The compiled max # threads
 
947
AP_MPMQ_MAX_THREADS        = 6  # # of threads/child by config
 
948
AP_MPMQ_MIN_SPARE_DAEMONS  = 7  # Min # of spare daemons
 
949
AP_MPMQ_MIN_SPARE_THREADS  = 8  # Min # of spare threads
 
950
AP_MPMQ_MAX_SPARE_DAEMONS  = 9  # Max # of spare daemons
 
951
AP_MPMQ_MAX_SPARE_THREADS  = 10 # Max # of spare threads
 
952
AP_MPMQ_MAX_REQUESTS_DAEMON= 11 # Max # of requests per daemon
 
953
AP_MPMQ_MAX_DAEMONS        = 12 # Max # of daemons by config
 
954