[Python-checkins] cpython (merge 2.7 -> 2.7): merge heads

benjamin.peterson python-checkins at python.org
Wed Apr 11 22:12:27 CEST 2012


http://hg.python.org/cpython/rev/5d5573d94988
changeset:   76254:5d5573d94988
branch:      2.7
parent:      76253:5324c821da95
parent:      76247:c67efb8ffca4
user:        Benjamin Peterson <benjamin at python.org>
date:        Wed Apr 11 16:12:21 2012 -0400
summary:
  merge heads

files:
  .hgtags                      |   1 +
  Doc/howto/logging.rst        |  15 ++++
  Doc/library/logging.rst      |  16 ++++-
  Doc/library/re.rst           |  24 +++---
  Lib/CGIHTTPServer.py         |  61 +++++++++----------
  Lib/test/test_httpservers.py |  76 ++++++++++++-----------
  6 files changed, 110 insertions(+), 83 deletions(-)


diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -139,6 +139,7 @@
 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6
 caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1
 1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2
+c9910fd022fc842e5578e1bf5a30ba55a37239fc v2.6.8
 b4107eb00b4271fb73a9e1b736d4f23460950778 v2.7a1
 adc85ebc7271cc22e24e816782bb2b8d7fa3a6b3 v2.7a2
 4180557b7a9bb9dd5341a18af199f843f199e46e v2.7a3
diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst
--- a/Doc/howto/logging.rst
+++ b/Doc/howto/logging.rst
@@ -642,6 +642,21 @@
 code approach, mainly separation of configuration and code and the ability of
 noncoders to easily modify the logging properties.
 
+.. warning:: The :func:`fileConfig` function takes a default parameter,
+   ``disable_existing_loggers``, which defaults to ``True`` for reasons of
+   backward compatibility. This may or may not be what you want, since it
+   will cause any loggers existing before the :func:`fileConfig` call to
+   be disabled unless they (or an ancestor) are explicitly named in the
+   configuration.  Please refer to the reference documentation for more
+   information, and specify ``False`` for this parameter if you wish.
+
+   The dictionary passed to :func:`dictConfig` can also specify a Boolean
+   value with key ``disable_existing_loggers``, which if not specified
+   explicitly in the dictionary also defaults to being interpreted as
+   ``True``.  This leads to the logger-disabling behaviour described above,
+   which may not be what you want - in which case, provide the key
+   explicitly with a value of ``False``.
+
 .. currentmodule:: logging
 
 Note that the class names referenced in config files need to be either relative
diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst
--- a/Doc/library/logging.rst
+++ b/Doc/library/logging.rst
@@ -51,9 +51,21 @@
 Logger Objects
 --------------
 
-Loggers have the following attributes and methods. Note that Loggers are never
+Loggers have the following attributes and methods.  Note that Loggers are never
 instantiated directly, but always through the module-level function
-``logging.getLogger(name)``.
+``logging.getLogger(name)``.  Multiple calls to :func:`getLogger` with the same
+name will always return a reference to the same Logger object.
+
+The ``name`` is potentially a period-separated hierarchical value, like
+``foo.bar.baz`` (though it could also be just plain ``foo``, for example).
+Loggers that are further down in the hierarchical list are children of loggers
+higher up in the list.  For example, given a logger with a name of ``foo``,
+loggers with names of ``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all
+descendants of ``foo``.  The logger name hierarchy is analogous to the Python
+package hierarchy, and identical to it if you organise your loggers on a
+per-module basis using the recommended construction
+``logging.getLogger(__name__)``.  That's because in a module, ``__name__``
+is the module's name in the Python package namespace.
 
 .. class:: Logger
 
diff --git a/Doc/library/re.rst b/Doc/library/re.rst
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -353,20 +353,20 @@
    character  properties database.
 
 ``\s``
-   When the :const:`LOCALE` and :const:`UNICODE` flags are not specified, matches
-   any whitespace character; this is equivalent to the set ``[ \t\n\r\f\v]``. With
-   :const:`LOCALE`, it will match this set plus whatever characters are defined as
-   space for the current locale. If :const:`UNICODE` is set, this will match the
-   characters ``[ \t\n\r\f\v]`` plus whatever is classified as space in the Unicode
-   character properties database.
+   When the :const:`UNICODE` flag is not specified, it matches any whitespace
+   character, this is equivalent to the set ``[ \t\n\r\f\v]``. The
+   :const:`LOCALE` flag has no extra effect on matching of the space.
+   If :const:`UNICODE` is set, this will match the characters ``[ \t\n\r\f\v]``
+   plus whatever is classified as space in the Unicode character properties
+   database.
 
 ``\S``
-   When the :const:`LOCALE` and :const:`UNICODE` flags are not specified,
-   matches any non-whitespace character; this is equivalent to the set ``[^
-   \t\n\r\f\v]`` With :const:`LOCALE`, it will match the above set plus any
-   non-space character in the current locale. If :const:`UNICODE` is set, the
-   above set ``[^ \t\n\r\f\v]`` plus the characters not marked as space in the
-   Unicode character properties database.
+   When the :const:`UNICODE` flags is not specified, matches any non-whitespace
+   character; this is equivalent to the set ``[^ \t\n\r\f\v]`` The
+   :const:`LOCALE` flag has no extra effect on non-whitespace match.  If
+   :const:`UNICODE` is set, then any character not marked as space in the
+   Unicode character properties database is matched.
+
 
 ``\w``
    When the :const:`LOCALE` and :const:`UNICODE` flags are not specified, matches
diff --git a/Lib/CGIHTTPServer.py b/Lib/CGIHTTPServer.py
--- a/Lib/CGIHTTPServer.py
+++ b/Lib/CGIHTTPServer.py
@@ -84,9 +84,11 @@
         path begins with one of the strings in self.cgi_directories
         (and the next character is a '/' or the end of the string).
         """
-        splitpath = _url_collapse_path_split(self.path)
-        if splitpath[0] in self.cgi_directories:
-            self.cgi_info = splitpath
+        collapsed_path = _url_collapse_path(self.path)
+        dir_sep = collapsed_path.find('/', 1)
+        head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
+        if head in self.cgi_directories:
+            self.cgi_info = head, tail
             return True
         return False
 
@@ -298,51 +300,46 @@
                 self.log_message("CGI script exited OK")
 
 
-# TODO(gregory.p.smith): Move this into an appropriate library.
-def _url_collapse_path_split(path):
+def _url_collapse_path(path):
     """
     Given a URL path, remove extra '/'s and '.' path elements and collapse
-    any '..' references.
+    any '..' references and returns a colllapsed path.
 
     Implements something akin to RFC-2396 5.2 step 6 to parse relative paths.
+    The utility of this function is limited to is_cgi method and helps
+    preventing some security attacks.
 
     Returns: A tuple of (head, tail) where tail is everything after the final /
     and head is everything before it.  Head will always start with a '/' and,
     if it contains anything else, never have a trailing '/'.
 
     Raises: IndexError if too many '..' occur within the path.
+
     """
     # Similar to os.path.split(os.path.normpath(path)) but specific to URL
     # path semantics rather than local operating system semantics.
-    path_parts = []
-    for part in path.split('/'):
-        if part == '.':
-            path_parts.append('')
-        else:
-            path_parts.append(part)
-    # Filter out blank non trailing parts before consuming the '..'.
-    path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:]
+    path_parts = path.split('/')
+    head_parts = []
+    for part in path_parts[:-1]:
+        if part == '..':
+            head_parts.pop() # IndexError if more '..' than prior parts
+        elif part and part != '.':
+            head_parts.append( part )
     if path_parts:
-        # Special case for CGI's for PATH_INFO
-        if path.startswith('/cgi-bin') or path.startswith('/htbin'):
-            tail_part = []
-            while path_parts[-1] not in ('cgi-bin','htbin'):
-                tail_part.insert(0,path_parts.pop())
-            tail_part = "/".join(tail_part)
-        else:
-            tail_part = path_parts.pop()
+        tail_part = path_parts.pop()
+        if tail_part:
+            if tail_part == '..':
+                head_parts.pop()
+                tail_part = ''
+            elif tail_part == '.':
+                tail_part = ''
     else:
         tail_part = ''
-    head_parts = []
-    for part in path_parts:
-        if part == '..':
-            head_parts.pop()
-        else:
-            head_parts.append(part)
-    if tail_part and tail_part == '..':
-        head_parts.pop()
-        tail_part = ''
-    return ('/' + '/'.join(head_parts), tail_part)
+
+    splitpath = ('/' + '/'.join(head_parts), tail_part)
+    collapsed_path = "/".join(splitpath)
+
+    return collapsed_path
 
 
 nobody = None
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -4,11 +4,6 @@
 Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
 """
 
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from SimpleHTTPServer import SimpleHTTPRequestHandler
-from CGIHTTPServer import CGIHTTPRequestHandler
-import CGIHTTPServer
-
 import os
 import sys
 import re
@@ -17,12 +12,17 @@
 import urllib
 import httplib
 import tempfile
+import unittest
+import CGIHTTPServer
 
-import unittest
 
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from CGIHTTPServer import CGIHTTPRequestHandler
 from StringIO import StringIO
+from test import test_support
 
-from test import test_support
+
 threading = test_support.import_module('threading')
 
 
@@ -43,7 +43,7 @@
         self.end_headers()
         self.wfile.write(b'<html><body>Data</body></html>\r\n')
 
-    def log_message(self, format, *args):
+    def log_message(self, fmt, *args):
         pass
 
 
@@ -97,9 +97,9 @@
         self.handler = SocketlessRequestHandler()
 
     def send_typical_request(self, message):
-        input = StringIO(message)
+        input_msg = StringIO(message)
         output = StringIO()
-        self.handler.rfile = input
+        self.handler.rfile = input_msg
         self.handler.wfile = output
         self.handler.handle_one_request()
         output.seek(0)
@@ -296,7 +296,7 @@
             os.chdir(self.cwd)
             try:
                 shutil.rmtree(self.tempdir)
-            except:
+            except OSError:
                 pass
         finally:
             BaseTestCase.tearDown(self)
@@ -418,42 +418,44 @@
         finally:
             BaseTestCase.tearDown(self)
 
-    def test_url_collapse_path_split(self):
+    def test_url_collapse_path(self):
+        # verify tail is the last portion and head is the rest on proper urls
         test_vectors = {
-            '': ('/', ''),
+            '': '//',
             '..': IndexError,
             '/.//..': IndexError,
-            '/': ('/', ''),
-            '//': ('/', ''),
-            '/\\': ('/', '\\'),
-            '/.//': ('/', ''),
-            'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
-            '/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
-            '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'),
-            'a': ('/', 'a'),
-            '/a': ('/', 'a'),
-            '//a': ('/', 'a'),
-            './a': ('/', 'a'),
-            './C:/': ('/C:', ''),
-            '/a/b': ('/a', 'b'),
-            '/a/b/': ('/a/b', ''),
-            '/a/b/c/..': ('/a/b', ''),
-            '/a/b/c/../d': ('/a/b', 'd'),
-            '/a/b/c/../d/e/../f': ('/a/b/d', 'f'),
-            '/a/b/c/../d/e/../../f': ('/a/b', 'f'),
-            '/a/b/c/../d/e/.././././..//f': ('/a/b', 'f'),
+            '/': '//',
+            '//': '//',
+            '/\\': '//\\',
+            '/.//': '//',
+            'cgi-bin/file1.py': '/cgi-bin/file1.py',
+            '/cgi-bin/file1.py': '/cgi-bin/file1.py',
+            'a': '//a',
+            '/a': '//a',
+            '//a': '//a',
+            './a': '//a',
+            './C:/': '/C:/',
+            '/a/b': '/a/b',
+            '/a/b/': '/a/b/',
+            '/a/b/.': '/a/b/',
+            '/a/b/c/..': '/a/b/',
+            '/a/b/c/../d': '/a/b/d',
+            '/a/b/c/../d/e/../f': '/a/b/d/f',
+            '/a/b/c/../d/e/../../f': '/a/b/f',
+            '/a/b/c/../d/e/.././././..//f': '/a/b/f',
             '../a/b/c/../d/e/.././././..//f': IndexError,
-            '/a/b/c/../d/e/../../../f': ('/a', 'f'),
-            '/a/b/c/../d/e/../../../../f': ('/', 'f'),
+            '/a/b/c/../d/e/../../../f': '/a/f',
+            '/a/b/c/../d/e/../../../../f': '//f',
             '/a/b/c/../d/e/../../../../../f': IndexError,
-            '/a/b/c/../d/e/../../../../f/..': ('/', ''),
+            '/a/b/c/../d/e/../../../../f/..': '//',
+            '/a/b/c/../d/e/../../../../f/../.': '//',
         }
         for path, expected in test_vectors.iteritems():
             if isinstance(expected, type) and issubclass(expected, Exception):
                 self.assertRaises(expected,
-                                  CGIHTTPServer._url_collapse_path_split, path)
+                                  CGIHTTPServer._url_collapse_path, path)
             else:
-                actual = CGIHTTPServer._url_collapse_path_split(path)
+                actual = CGIHTTPServer._url_collapse_path(path)
                 self.assertEqual(expected, actual,
                                  msg='path = %r\nGot:    %r\nWanted: %r' %
                                  (path, actual, expected))

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list