basebuilder_pel7x64builder0
6 years ago
81 changed files with 27533 additions and 1331 deletions
@ -1,822 +1,198 @@
@@ -1,822 +1,198 @@
|
||||
diff -up Python-3.3.0rc2/configure.ac.systemtap Python-3.3.0rc2/configure.ac |
||||
--- Python-3.3.0rc2/configure.ac.systemtap 2012-09-09 05:11:14.000000000 -0400 |
||||
+++ Python-3.3.0rc2/configure.ac 2012-09-10 09:17:21.114511781 -0400 |
||||
@@ -2678,6 +2678,23 @@ if test "$with_valgrind" != no; then |
||||
OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" |
||||
diff -up Python-2.7rc1/configure.ac.systemtap Python-2.7rc1/configure.ac |
||||
--- Python-2.7rc1/configure.ac.systemtap 2010-06-06 10:53:15.514975012 -0400 |
||||
+++ Python-2.7rc1/configure.ac 2010-06-06 10:53:15.520974361 -0400 |
||||
@@ -2616,6 +2616,38 @@ if test "$with_valgrind" != no; then |
||||
) |
||||
fi |
||||
|
||||
+# Check for systemtap support |
||||
+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap |
||||
+AC_MSG_CHECKING([for --with-systemtap]) |
||||
+AC_ARG_WITH([systemtap], |
||||
+ AC_HELP_STRING([--with(out)-systemtap], [disable/enable SystemTap support]),, |
||||
+ with_systemtap=no) |
||||
+AC_MSG_RESULT([$with_systemtap]) |
||||
+if test "$with_systemtap" != no; then |
||||
+ AC_DEFINE(WITH_SYSTEMTAP, 1, |
||||
+ [Define if you want to compile in SystemTap support]) |
||||
+ SYSTEMTAPOBJS="Python/pysystemtap.o" |
||||
+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h" |
||||
+fi |
||||
+ |
||||
+AC_SUBST(SYSTEMTAPOBJS) |
||||
+AC_SUBST(SYSTEMTAPDEPS) |
||||
+ |
||||
# -I${DLINCLDIR} is added to the compile rule for importdl.o |
||||
AC_SUBST(DLINCLDIR) |
||||
DLINCLDIR=. |
||||
diff -up Python-3.3.0rc2/configure.systemtap Python-3.3.0rc2/configure |
||||
--- Python-3.3.0rc2/configure.systemtap 2012-09-09 05:11:14.000000000 -0400 |
||||
+++ Python-3.3.0rc2/configure 2012-09-10 09:17:21.116511780 -0400 |
||||
@@ -618,6 +618,8 @@ TRUE |
||||
MACHDEP_OBJS |
||||
DYNLOADFILE |
||||
DLINCLDIR |
||||
+SYSTEMTAPDEPS |
||||
+SYSTEMTAPOBJS |
||||
THREADOBJ |
||||
LDLAST |
||||
USE_THREAD_MODULE |
||||
@@ -779,6 +781,7 @@ with_doc_strings |
||||
with_tsc |
||||
with_pymalloc |
||||
with_valgrind |
||||
+with_systemtap |
||||
with_fpectl |
||||
with_libm |
||||
with_libc |
||||
@@ -1456,6 +1459,7 @@ Optional Packages: |
||||
--with(out)-tsc enable/disable timestamp counter profile |
||||
--with(out)-pymalloc disable/enable specialized mallocs |
||||
--with-valgrind Enable Valgrind support |
||||
+ --with(out)-systemtap disable/enable SystemTap support |
||||
--with-fpectl enable SIGFPE catching |
||||
--with-libm=STRING math library |
||||
--with-libc=STRING C library |
||||
@@ -10065,6 +10069,31 @@ fi |
||||
OPT="-DDYNAMIC_ANNOTATIONS_ENABLED=1 $OPT" |
||||
fi |
||||
|
||||
+# Check for systemtap support |
||||
+# On Linux, /usr/bin/dtrace is in fact a shim to SystemTap |
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-systemtap" >&5 |
||||
+$as_echo_n "checking for --with-systemtap... " >&6; } |
||||
+ |
||||
+# Check whether --with-systemtap was given. |
||||
+if test "${with_systemtap+set}" = set; then : |
||||
+ withval=$with_systemtap; |
||||
+# Check for dtrace support |
||||
+AC_MSG_CHECKING(for --with-dtrace) |
||||
+AC_ARG_WITH(dtrace, |
||||
+ AC_HELP_STRING(--with(out)-dtrace, disable/enable dtrace support)) |
||||
+ |
||||
+if test ! -z "$with_dtrace" |
||||
+then |
||||
+ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null |
||||
+ then |
||||
+ AC_DEFINE(WITH_DTRACE, 1, |
||||
+ [Define if you want to compile in Dtrace support]) |
||||
+ with_dtrace="Sun" |
||||
+ DTRACEOBJS="Python/dtrace.o" |
||||
+ DTRADEHDRS="" |
||||
+ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d |
||||
+ then |
||||
+ AC_DEFINE(WITH_DTRACE, 1, |
||||
+ [Define if you want to compile in Dtrace support]) |
||||
+ with_dtrace="Apple" |
||||
+ DTRACEOBJS="" |
||||
+ DTRADEHDRS="pydtrace.h" |
||||
+ else |
||||
+ with_dtrace="no" |
||||
+ fi |
||||
+else |
||||
+ with_systemtap=no |
||||
+fi |
||||
+ |
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_systemtap" >&5 |
||||
+$as_echo "$with_systemtap" >&6; } |
||||
+if test "$with_systemtap" != no; then |
||||
+ |
||||
+$as_echo "#define WITH_SYSTEMTAP 1" >>confdefs.h |
||||
+ |
||||
+ SYSTEMTAPOBJS="Python/pysystemtap.o" |
||||
+ SYSTEMTAPDEPS="\$(srcdir)/Python/pysystemtap.h" |
||||
+ with_dtrace="no" |
||||
+fi |
||||
+ |
||||
+AC_MSG_RESULT($with_dtrace) |
||||
+AC_SUBST(DTRACEOBJS) |
||||
+AC_SUBST(DTRACEHDRS) |
||||
+ |
||||
# Check for --with-wctype-functions |
||||
AC_MSG_CHECKING(for --with-wctype-functions) |
||||
AC_ARG_WITH(wctype-functions, |
||||
diff -up Python-2.7rc1/Include/pydtrace.d.systemtap Python-2.7rc1/Include/pydtrace.d |
||||
--- Python-2.7rc1/Include/pydtrace.d.systemtap 2010-06-06 10:53:15.520974361 -0400 |
||||
+++ Python-2.7rc1/Include/pydtrace.d 2010-06-06 10:53:15.520974361 -0400 |
||||
@@ -0,0 +1,10 @@ |
||||
+provider python { |
||||
+ probe function__entry(const char *, const char *, int); |
||||
+ probe function__return(const char *, const char *, int); |
||||
+}; |
||||
+ |
||||
+ |
||||
+ |
||||
# -I${DLINCLDIR} is added to the compile rule for importdl.o |
||||
|
||||
DLINCLDIR=. |
||||
diff -up Python-3.3.0rc2/Doc/howto/index.rst.systemtap Python-3.3.0rc2/Doc/howto/index.rst |
||||
--- Python-3.3.0rc2/Doc/howto/index.rst.systemtap 2012-09-09 05:10:51.000000000 -0400 |
||||
+++ Python-3.3.0rc2/Doc/howto/index.rst 2012-09-10 09:17:21.117511779 -0400 |
||||
@@ -29,4 +29,5 @@ Currently, the HOWTOs are: |
||||
argparse.rst |
||||
ipaddress.rst |
||||
clinic.rst |
||||
+ instrumentation.rst |
||||
|
||||
diff -up Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap Python-3.3.0rc2/Doc/howto/instrumentation.rst |
||||
--- Python-3.3.0rc2/Doc/howto/instrumentation.rst.systemtap 2012-09-10 09:17:21.117511779 -0400 |
||||
+++ Python-3.3.0rc2/Doc/howto/instrumentation.rst 2012-09-10 09:17:21.117511779 -0400 |
||||
@@ -0,0 +1,295 @@ |
||||
+.. _instrumentation: |
||||
+ |
||||
+==================================== |
||||
+Instrumenting CPython with SystemTap |
||||
+==================================== |
||||
+ |
||||
+:author: David Malcolm <dmalcolm@redhat.com> |
||||
+ |
||||
+DTrace and SystemTap are monitoring tools, each providing a way to inspect |
||||
+what the processes on a computer system are doing. They both use |
||||
+domain-specific languages allowing a user to write scripts which: |
||||
+ |
||||
+ - filter which processes are to be observed |
||||
+ - gather data from the processes of interest |
||||
+ - generate reports on the data |
||||
+ |
||||
+As of Python 3.3, CPython can be built with embedded "markers" that can be |
||||
+observed by a SystemTap script, making it easier to monitor what the CPython |
||||
+processes on a system are doing. |
||||
+ |
||||
+.. Potentially this document could be expanded to also cover DTrace markers. |
||||
+ However, I'm not a DTrace expert. |
||||
+ |
||||
+.. I'm using ".. code-block:: c" for SystemTap scripts, as "c" is syntactically |
||||
+ the closest match that Sphinx supports |
||||
+ |
||||
+ |
||||
+Enabling the static markers |
||||
+--------------------------- |
||||
+ |
||||
+In order to build CPython with the embedded markers for SystemTap, the |
||||
+SystemTap development tools must be installed. |
||||
+ |
||||
+On a Fedora or Red Hat Enterprise Linux machine, this can be done via:: |
||||
+ |
||||
+ yum install systemtap-sdt-devel |
||||
+ |
||||
+CPython must then be configured `--with-systemtap`:: |
||||
+ |
||||
+ checking for --with-systemtap... yes |
||||
+ |
||||
+You can verify if the SystemTap static markers are present in the built |
||||
+binary by seeing if it contains a ".note.stapsdt" section. |
||||
+ |
||||
+.. code-block:: bash |
||||
+ |
||||
+ $ eu-readelf -S ./python | grep .note.stapsdt |
||||
+ [29] .note.stapsdt NOTE 0000000000000000 00308d78 000000b8 0 0 0 4 |
||||
+ |
||||
+If you've built python as a shared library (with --enable-shared), you need |
||||
+to look instead within the shared library. For example: |
||||
+ |
||||
+.. code-block:: bash |
||||
+ |
||||
+ $ eu-readelf -S libpython3.3dm.so.1.0 | grep .note.stapsdt |
||||
+ [28] .note.stapsdt NOTE 0000000000000000 00365b68 000000b8 0 0 0 4 |
||||
+ |
||||
+Earlier versions of SystemTap stored the markers in a ".probes" section. |
||||
+ |
||||
+For the curious, you can see the metadata for the static markers using this |
||||
+invocation. |
||||
+ |
||||
+.. code-block:: bash |
||||
+ |
||||
+ $ eu-readelf -x .note.stapsdt ./python |
||||
+ |
||||
+ Hex dump of section [29] '.note.stapsdt', 184 bytes at offset 0x308d78: |
||||
+ 0x00000000 08000000 45000000 03000000 73746170 ....E.......stap |
||||
+ 0x00000010 73647400 d4664b00 00000000 4fc36600 sdt..fK.....O.f. |
||||
+ 0x00000020 00000000 488d9000 00000000 70797468 ....H.......pyth |
||||
+ 0x00000030 6f6e0066 756e6374 696f6e5f 5f656e74 on.function__ent |
||||
+ 0x00000040 72790038 40257261 78203840 25726478 ry.8@%rax 8@%rdx |
||||
+ 0x00000050 202d3440 25656378 00000000 08000000 -4@%ecx........ |
||||
+ 0x00000060 46000000 03000000 73746170 73647400 F.......stapsdt. |
||||
+ 0x00000070 0d674b00 00000000 4fc36600 00000000 .gK.....O.f..... |
||||
+ 0x00000080 4a8d9000 00000000 70797468 6f6e0066 J.......python.f |
||||
+ 0x00000090 756e6374 696f6e5f 5f726574 75726e00 unction__return. |
||||
+ 0x000000a0 38402572 61782038 40257264 78202d34 8@%rax 8@%rdx -4 |
||||
+ 0x000000b0 40256563 78000000 @%ecx... |
||||
+ |
||||
+and a sufficiently modern eu-readelf can print the metadata: |
||||
+ |
||||
+.. code-block:: bash |
||||
+ |
||||
+ $ eu-readelf -n ./python |
||||
+ |
||||
+ Note section [ 1] '.note.gnu.build-id' of 36 bytes at offset 0x190: |
||||
+ Owner Data size Type |
||||
+ GNU 20 GNU_BUILD_ID |
||||
+ Build ID: a28f8db1b224530b0d38ad7b82a249cf7c3f18d6 |
||||
+ |
||||
+ Note section [27] '.note.stapsdt' of 184 bytes at offset 0x1ae884: |
||||
+ Owner Data size Type |
||||
+ stapsdt 70 Version: 3 |
||||
+ PC: 0xe0d3a, Base: 0x14b150, Semaphore: 0x3ae882 |
||||
+ Provider: python, Name: function__return, Args: '8@%rbx 8@%r13 -4@%eax' |
||||
+ stapsdt 69 Version: 3 |
||||
+ PC: 0xe0f37, Base: 0x14b150, Semaphore: 0x3ae880 |
||||
+ Provider: python, Name: function__entry, Args: '8@%rbx 8@%r13 -4@%eax' |
||||
+ |
||||
+The above metadata contains information for SystemTap describing how it can |
||||
+patch strategically-placed machine code instructions to enable the tracing |
||||
+hooks used by a SystemTap script. |
||||
+ |
||||
+ |
||||
+Static markers |
||||
+-------------- |
||||
+ |
||||
+The low-level way to use the SystemTap integration is to use the static |
||||
+markers directly. This requires you to explicitly state the binary file |
||||
+containing them. |
||||
+ |
||||
+For example, this script can be used to show the call/return hierarchy of a |
||||
+Python script: |
||||
+ |
||||
+.. code-block:: c |
||||
+ |
||||
+ probe process('python').mark("function__entry") { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ |
||||
+ printf("%s => %s in %s:%d\\n", |
||||
+ thread_indent(1), funcname, filename, lineno); |
||||
+ } |
||||
+ |
||||
+ probe process('python').mark("function__return") { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ |
||||
+ printf("%s <= %s in %s:%d\\n", |
||||
+ thread_indent(-1), funcname, filename, lineno); |
||||
+ } |
||||
+ |
||||
+It can be invoked like this: |
||||
+ |
||||
+.. code-block:: bash |
||||
+ |
||||
+ $ stap \ |
||||
+ show-call-hierarchy.stp \ |
||||
+ -c ./python test.py |
||||
+ |
||||
+The output looks like this:: |
||||
+ |
||||
+ 11408 python(8274): => __contains__ in Lib/_abcoll.py:362 |
||||
+ 11414 python(8274): => __getitem__ in Lib/os.py:425 |
||||
+ 11418 python(8274): => encode in Lib/os.py:490 |
||||
+ 11424 python(8274): <= encode in Lib/os.py:493 |
||||
+ 11428 python(8274): <= __getitem__ in Lib/os.py:426 |
||||
+ 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366 |
||||
+ |
||||
+where the columns are: |
||||
+ |
||||
+ - time in microseconds since start of script |
||||
+ |
||||
+ - name of executable |
||||
+ |
||||
+ - PID of process |
||||
+ |
||||
+and the remainder indicates the call/return hierarchy as the script executes. |
||||
+ |
||||
+For a `--enable-shared` build of CPython, the markers are contained within the |
||||
+libpython shared library, and the probe's dotted path needs to reflect this. For |
||||
+example, this line from the above example:: |
||||
+ |
||||
+ probe process('python').mark("function__entry") { |
||||
+ |
||||
+should instead read:: |
||||
+ |
||||
+ probe process('python').library("libpython3.3dm.so.1.0").mark("function__entry") { |
||||
+ |
||||
+(assuming a debug build of CPython 3.3) |
||||
+ |
||||
+.. I'm reusing the "c:function" type for markers |
||||
+ |
||||
+.. c:function:: function__entry(str filename, str funcname, int lineno) |
||||
+ |
||||
+ This marker indicates that execution of a Python function has begun. It is |
||||
+ only triggered for pure-python (bytecode) functions. |
||||
+ |
||||
+ The filename, function name, and line number are provided back to the |
||||
+ tracing script as positional arguments, which must be accessed using |
||||
+ `$arg1`, `$arg2`: |
||||
+ |
||||
+ * `$arg1` : `(const char *)` filename, accessible using `user_string($arg1)` |
||||
+ |
||||
+ * `$arg2` : `(const char *)` function name, accessible using |
||||
+ `user_string($arg2)` |
||||
+ |
||||
+ * `$arg3` : `int` line number |
||||
+ |
||||
+ * `$arg4` : `(PyFrameObject *)`, the frame being executed |
||||
+ |
||||
+.. c:function:: function__return(str filename, str funcname, int lineno) |
||||
+ |
||||
+ This marker is the converse of `function__entry`, and indicates that |
||||
+ execution of a Python function has ended (either via ``return``, or via an |
||||
+ exception). It is only triggered for pure-python (bytecode) functions. |
||||
+ |
||||
+ The arguments are the same as for `function__entry` |
||||
+ |
||||
+ |
||||
+Tapsets |
||||
+------- |
||||
+ |
||||
+The higher-level way to use the SystemTap integration is to use a "tapset": |
||||
+SystemTap's equivalent of a library, which hides some of the lower-level |
||||
+details of the static markers. |
||||
+ |
||||
+Here is a tapset file, based on a non-shared build of CPython: |
||||
+ |
||||
+.. code-block:: c |
||||
+ |
||||
+ /* |
||||
+ Provide a higher-level wrapping around the function__entry and |
||||
+ function__return markers: |
||||
+ */ |
||||
+ probe python.function.entry = process("python").mark("function__entry") |
||||
+ { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ frameptr = $arg4 |
||||
+ } |
||||
+ probe python.function.return = process("python").mark("function__return") |
||||
+ { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ frameptr = $arg4 |
||||
+ } |
||||
+ |
||||
+If this file is installed in SystemTap's tapset directory (e.g. |
||||
+`/usr/share/systemtap/tapset`), then these additional probepoints become |
||||
+available: |
||||
+ |
||||
+.. c:function:: python.function.entry(str filename, str funcname, int lineno, frameptr) |
||||
+ |
||||
+ This probe point indicates that execution of a Python function has begun. |
||||
+ It is only triggered for pure-python (bytecode) functions. |
||||
+ |
||||
+.. c:function:: python.function.return(str filename, str funcname, int lineno, frameptr) |
||||
+ |
||||
+ This probe point is the converse of `python.function.return`, and indicates |
||||
+ that execution of a Python function has ended (either via ``return``, or |
||||
+ via an exception). It is only triggered for pure-python (bytecode) functions. |
||||
+ |
||||
+ |
||||
+Examples |
||||
+-------- |
||||
+This SystemTap script uses the tapset above to more cleanly implement the |
||||
+example given above of tracing the Python function-call hierarchy, without |
||||
+needing to directly name the static markers: |
||||
+ |
||||
+.. code-block:: c |
||||
+ |
||||
+ probe python.function.entry |
||||
+ { |
||||
+ printf("%s => %s in %s:%d\n", |
||||
+ thread_indent(1), funcname, filename, lineno); |
||||
+ } |
||||
+ |
||||
+ probe python.function.return |
||||
+ { |
||||
+ printf("%s <= %s in %s:%d\n", |
||||
+ thread_indent(-1), funcname, filename, lineno); |
||||
+ } |
||||
+ |
||||
+ |
||||
+The following script uses the tapset above to provide a top-like view of all |
||||
+running CPython code, showing the top 20 most frequently-entered bytecode |
||||
+frames, each second, across the whole system: |
||||
+ |
||||
+.. code-block:: c |
||||
+ |
||||
+ global fn_calls; |
||||
+ |
||||
+ probe python.function.entry |
||||
+ { |
||||
+ fn_calls[pid(), filename, funcname, lineno] += 1; |
||||
+ } |
||||
+ |
||||
+ probe timer.ms(1000) { |
||||
+ printf("\033[2J\033[1;1H") /* clear screen */ |
||||
+ printf("%6s %80s %6s %30s %6s\n", |
||||
+ "PID", "FILENAME", "LINE", "FUNCTION", "CALLS") |
||||
+ foreach ([pid, filename, funcname, lineno] in fn_calls- limit 20) { |
||||
+ printf("%6d %80s %6d %30s %6d\n", |
||||
+ pid, filename, lineno, funcname, |
||||
+ fn_calls[pid, filename, funcname, lineno]); |
||||
+ } |
||||
+ delete fn_calls; |
||||
+ } |
||||
+ |
||||
diff -up Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap Python-3.3.0rc2/Lib/test/test_systemtap.py |
||||
--- Python-3.3.0rc2/Lib/test/test_systemtap.py.systemtap 2012-09-10 09:17:21.117511779 -0400 |
||||
+++ Python-3.3.0rc2/Lib/test/test_systemtap.py 2012-09-10 09:17:21.117511779 -0400 |
||||
@@ -0,0 +1,234 @@ |
||||
+# Verify that systemtap static probes work |
||||
+# |
||||
+import subprocess |
||||
+import sys |
||||
+import sysconfig |
||||
+import os |
||||
+import unittest |
||||
+ |
||||
+from test.support import run_unittest, TESTFN, unlink |
||||
+ |
||||
+if '--with-systemtap' not in sysconfig.get_config_var('CONFIG_ARGS'): |
||||
+ raise unittest.SkipTest("Python was not configured --with-systemtap") |
||||
+ |
||||
+try: |
||||
+ _, stap_version = subprocess.Popen(["stap", "-V"], |
||||
+ stdout=subprocess.PIPE, |
||||
+ stderr=subprocess.PIPE, |
||||
+ ).communicate() |
||||
+except OSError: |
||||
+ # This is what "no stap" looks like. There may, however, be other |
||||
+ # errors that manifest this way too. |
||||
+ raise unittest.SkipTest("Couldn't find stap on the path") |
||||
+ |
||||
+def invoke_systemtap_script(script, cmd): |
||||
+ # Start a child process, probing with the given systemtap script |
||||
+ # (passed as stdin to the "stap" tool) |
||||
+ # The script should be a bytes instance |
||||
+ # Return (stdout, stderr) pair |
||||
+ |
||||
+ p = subprocess.Popen(["stap", "-", '-vv', '-c', cmd], |
||||
+ stdin=subprocess.PIPE, |
||||
+ stdout=subprocess.PIPE, |
||||
+ stderr=subprocess.PIPE) |
||||
+ out, err = p.communicate(input=script) |
||||
+ return out, err |
||||
+ |
||||
+# Verify that stap can run a simple "hello world"-style script |
||||
+# This can fail for various reasons: |
||||
+# - missing kernel headers |
||||
+# - permissions (a non-root user needs to be in the "stapdev" group) |
||||
+TRIVIAL_STAP_SCRIPT = b'probe begin { println("hello world") exit () }' |
||||
+ |
||||
+out, err = invoke_systemtap_script(TRIVIAL_STAP_SCRIPT, 'true') |
||||
+if out != b'hello world\n': |
||||
+ raise unittest.SkipTest("Test systemtap script did not run; stderr was: %s" % err) |
||||
+ |
||||
+# We don't expect stderr to be empty, since we're invoking stap with "-vv": stap |
||||
+# will (we hope) generate debugging output on stderr. |
||||
+ |
||||
+def invoke_python_under_systemtap(script, pythoncode=None, pythonfile=None): |
||||
+ # Start a child python process, probing with the given systemtap script |
||||
+ # (passed as stdin to the "stap" tool) |
||||
+ # The script should be a bytes instance |
||||
+ # Return (stdout, stderr) pair |
||||
+ |
||||
+ if pythonfile: |
||||
+ pythoncmd = '%s %s' % (sys.executable, pythonfile) |
||||
+ else: |
||||
+ pythoncmd = '%s -c %r' % (sys.executable, pythoncode) |
||||
+ |
||||
+ # The process tree of a stap invocation of a command goes through |
||||
+ # something like this: |
||||
+ # stap ->fork/exec(staprun; exec stapio ->f/e(-c cmd); exec staprun -r) |
||||
+ # and this trip through setuid leads to LD_LIBRARY_PATH being dropped, |
||||
+ # which would lead to an --enable-shared build of python failing to be |
||||
+ # find its libpython, with an error like: |
||||
+ # error while loading shared libraries: libpython3.3dm.so.1.0: cannot |
||||
+ # open shared object file: No such file or directory |
||||
+ # Hence we need to jump through some hoops to expose LD_LIBRARY_PATH to |
||||
+ # the invoked python process: |
||||
+ LD_LIBRARY_PATH = os.environ.get('LD_LIBRARY_PATH', '') |
||||
+ if LD_LIBRARY_PATH: |
||||
+ pythoncmd = 'env LD_LIBRARY_PATH=%s ' % LD_LIBRARY_PATH + pythoncmd |
||||
+ |
||||
+ return invoke_systemtap_script(script, pythoncmd) |
||||
+ |
||||
+# When using the static markers, we need to supply the prefix of a systemtap |
||||
+# dotted probe point that containing the marker. |
||||
+# See http://sourceware.org/systemtap/langref/Probe_points.html |
||||
+# |
||||
+# We need to determine if this is a shared-library build |
||||
+# |
||||
+# Note that sysconfig can get this wrong; see: |
||||
+# http://bugs.python.org/issue14774 |
||||
+# |
||||
+if '--enable-shared' in sysconfig.get_config_var('CONFIG_ARGS'): |
||||
+ # For a shared-library build, the markers are in library(INSTSONAME): |
||||
+ INSTSONAME = sysconfig.get_config_var('INSTSONAME') |
||||
+ probe_prefix = 'process("%s").library("%s")' % (sys.executable, INSTSONAME) |
||||
+else: |
||||
+ # For a non-shared-library build, we can simply use sys.executable: |
||||
+ probe_prefix = 'process("%s")' % sys.executable |
||||
+ |
||||
+# The following script ought to generate lots of lines showing recursive |
||||
+# function entry and return, of the form: |
||||
+# 11408 python(8274): => __contains__ in Lib/_abcoll.py:362 |
||||
+# 11414 python(8274): => __getitem__ in Lib/os.py:425 |
||||
+# 11418 python(8274): => encode in Lib/os.py:490 |
||||
+# 11424 python(8274): <= encode in Lib/os.py:493 |
||||
+# 11428 python(8274): <= __getitem__ in Lib/os.py:426 |
||||
+# 11433 python(8274): <= __contains__ in Lib/_abcoll.py:366 |
||||
+# where the column are: |
||||
+# - time in microseconds since start of script |
||||
+# - name of executable |
||||
+# - PID of process |
||||
+# and the remainder indicates the call/return hierarchy |
||||
+ |
||||
+hierarchy_script = (''' |
||||
+probe %s.mark("function__entry") { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ |
||||
+ printf("%%s => %%s in %%s:%%d\\n", thread_indent(1), funcname, filename, lineno); |
||||
+} |
||||
+ |
||||
+probe %s.mark("function__return") { |
||||
+ filename = user_string($arg1); |
||||
+ funcname = user_string($arg2); |
||||
+ lineno = $arg3; |
||||
+ |
||||
+ printf("%%s <= %%s in %%s:%%d\\n", thread_indent(-1), funcname, filename, lineno); |
||||
+} |
||||
+''' % (probe_prefix, probe_prefix)).encode('utf-8') |
||||
+ |
||||
+ |
||||
+class ErrorDumper: |
||||
+ # A context manager that dumps extra information if an exception is raised, |
||||
+ # to help track down why the problem occurred |
||||
+ def __init__(self, out, err): |
||||
+ self.out = out |
||||
+ self.err = err |
||||
+ |
||||
+ def __enter__(self): |
||||
+ pass |
||||
+ |
||||
+ def __exit__(self, type_, value, traceback): |
||||
+ if type_: |
||||
+ # an exception is being raised: |
||||
+ print('stdout: %s' % out.decode()) |
||||
+ print('stderr: %s' % err.decode()) |
||||
+ |
||||
+class SystemtapTests(unittest.TestCase): |
||||
+ |
||||
+ def test_invoking_python(self): |
||||
+ # Ensure that we can invoke python under stap, with a trivial stap |
||||
+ # script: |
||||
+ out, err = invoke_python_under_systemtap( |
||||
+ b'probe begin { println("hello from stap") exit () }', |
||||
+ pythoncode="print('hello from python')") |
||||
+ with ErrorDumper(out, err): |
||||
+ self.assertIn(b'hello from stap', out) |
||||
+ self.assertIn(b'hello from python', out) |
||||
+ |
||||
+ def test_function_entry(self): |
||||
+ # Ensure that the function_entry static marker works |
||||
+ out, err = invoke_python_under_systemtap(hierarchy_script) |
||||
+ # stdout ought to contain various lines showing recursive function |
||||
+ # entry and return (see above) |
||||
+ |
||||
+ # Uncomment this for debugging purposes: |
||||
+ # print(out.decode('utf-8')) |
||||
+ |
||||
+ # Executing the cmdline-supplied "pass": |
||||
+ # 0 python(8274): => <module> in <string>:1 |
||||
+ # 5 python(8274): <= <module> in <string>:1 |
||||
+ with ErrorDumper(out, err): |
||||
+ self.assertIn(b'=> <module> in <string>:1', out, |
||||
+ msg="stdout: %s\nstderr: %s\n" % (out, err)) |
||||
+ |
||||
+ def test_function_encoding(self): |
||||
+ # Ensure that function names containing non-Latin 1 code |
||||
+ # points are handled: |
||||
+ pythonfile = TESTFN |
||||
+ try: |
||||
+ unlink(pythonfile) |
||||
+ f = open(pythonfile, "wb") |
||||
+ f.write(""" |
||||
+# Sample script with non-ASCII filename, for use by test_systemtap.py |
||||
+# Implicitly UTF-8 |
||||
+ |
||||
+def 文字化け(): |
||||
+ '''Function with non-ASCII identifier; I believe this reads "mojibake"''' |
||||
+ print("hello world!") |
||||
+ |
||||
+文字化け() |
||||
+""".encode('utf-8')) |
||||
+ f.close() |
||||
+ |
||||
+ out, err = invoke_python_under_systemtap(hierarchy_script, |
||||
+ pythonfile=pythonfile) |
||||
+ out_utf8 = out.decode('utf-8') |
||||
+ with ErrorDumper(out, err): |
||||
+ self.assertIn('=> <module> in %s:5' % pythonfile, out_utf8) |
||||
+ self.assertIn(' => 文字化け in %s:5' % pythonfile, out_utf8) |
||||
+ self.assertIn(' <= 文字化け in %s:7' % pythonfile, out_utf8) |
||||
+ self.assertIn('<= <module> in %s:9' % pythonfile, out_utf8) |
||||
+ finally: |
||||
+ unlink(pythonfile) |
||||
+ |
||||
+ @unittest.skipIf(sys.getfilesystemencoding() == 'ascii', |
||||
+ 'the test filename is not encodable with ASCII') |
||||
+ def test_filename_encoding(self): |
||||
+ # Ensure that scripts names containing non-Latin 1 code |
||||
+ # points are handled: |
||||
+ pythonfile = TESTFN + '_☠.py' |
||||
+ try: |
||||
+ unlink(pythonfile) |
||||
+ f = open(pythonfile, "wb") |
||||
+ f.write(""" |
||||
+def foo(): |
||||
+ '''Function with non-ASCII identifier; I believe this reads "mojibake"''' |
||||
+ print("hello world!") |
||||
+ |
||||
+foo() |
||||
+""".encode('utf-8')) |
||||
+ f.close() |
||||
+ |
||||
+ out, err = invoke_python_under_systemtap(hierarchy_script, |
||||
+ pythonfile=pythonfile) |
||||
+ out_utf8 = out.decode('utf-8') |
||||
+ with ErrorDumper(out, err): |
||||
+ self.assertIn('=> <module> in %s:2' % pythonfile, out_utf8) |
||||
+ self.assertIn(' => foo in %s:2' % pythonfile, out_utf8) |
||||
+ self.assertIn(' <= foo in %s:4' % pythonfile, out_utf8) |
||||
+ self.assertIn('<= <module> in %s:6' % pythonfile, out_utf8) |
||||
+ finally: |
||||
+ unlink(pythonfile) |
||||
+ |
||||
+def test_main(): |
||||
+ run_unittest(SystemtapTests) |
||||
+ |
||||
+if __name__ == "__main__": |
||||
+ test_main() |
||||
diff -up Python-3.3.0rc2/Makefile.pre.in.systemtap Python-3.3.0rc2/Makefile.pre.in |
||||
--- Python-3.3.0rc2/Makefile.pre.in.systemtap 2012-09-09 05:11:05.000000000 -0400 |
||||
+++ Python-3.3.0rc2/Makefile.pre.in 2012-09-10 09:19:51.195501518 -0400 |
||||
@@ -363,6 +363,7 @@ PYTHON_OBJS= \ |
||||
+#pragma D attributes Evolving/Evolving/Common provider python provider |
||||
+#pragma D attributes Private/Private/Common provider python module |
||||
+#pragma D attributes Private/Private/Common provider python function |
||||
+#pragma D attributes Evolving/Evolving/Common provider python name |
||||
+#pragma D attributes Evolving/Evolving/Common provider python args |
||||
diff -up Python-2.7rc1/Makefile.pre.in.systemtap Python-2.7rc1/Makefile.pre.in |
||||
--- Python-2.7rc1/Makefile.pre.in.systemtap 2010-06-06 10:53:15.488978775 -0400 |
||||
+++ Python-2.7rc1/Makefile.pre.in 2010-06-06 11:05:30.411100568 -0400 |
||||
@@ -298,6 +298,7 @@ PYTHON_OBJS= \ |
||||
Python/formatter_unicode.o \ |
||||
Python/fileutils.o \ |
||||
Python/formatter_string.o \ |
||||
Python/$(DYNLOADFILE) \ |
||||
+ @SYSTEMTAPOBJS@ \ |
||||
+ @DTRACEOBJS@ \ |
||||
$(LIBOBJS) \ |
||||
$(MACHDEP_OBJS) \ |
||||
$(THREADOBJ) |
||||
@@ -713,7 +714,8 @@ Objects/setobject.o: $(srcdir)/Objects/s |
||||
$(OPCODETARGETS_H): $(OPCODETARGETGEN_FILES) |
||||
$(OPCODETARGETGEN) $(OPCODETARGETS_H) |
||||
|
||||
-Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h |
||||
+Python/ceval.o: $(OPCODETARGETS_H) $(srcdir)/Python/ceval_gil.h \ |
||||
+ $(srcdir)/Python/ceval_systemtap.h @SYSTEMTAPDEPS@ |
||||
@@ -599,6 +600,18 @@ Python/formatter_unicode.o: $(srcdir)/Py |
||||
Python/formatter_string.o: $(srcdir)/Python/formatter_string.c \ |
||||
$(STRINGLIB_HEADERS) |
||||
|
||||
Python/frozen.o: Python/importlib.h Python/importlib_external.h |
||||
|
||||
@@ -724,6 +726,13 @@ Objects/typeobject.o: $(srcdir)/Objects/ |
||||
Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py |
||||
$(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > Objects/typeslots.inc |
||||
|
||||
+# Only needed with --with-systemtap; not a public header: |
||||
+$(srcdir)/Python/pysystemtap.h: $(srcdir)/Python/pysystemtap.d |
||||
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Python/pysystemtap.d |
||||
+# Only needed with --with-dtrace |
||||
+buildinclude: |
||||
+ mkdir -p Include |
||||
+ |
||||
+Include/pydtrace.h: buildinclude $(srcdir)/Include/pydtrace.d |
||||
+ dtrace -o $@ $(DFLAGS) -C -h -s $(srcdir)/Include/pydtrace.d |
||||
+ |
||||
+Python/ceval.o: Include/pydtrace.h |
||||
+ |
||||
+Python/pysystemtap.o: $(srcdir)/Python/pysystemtap.d Python/ceval.o |
||||
+ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Python/pysystemtap.d Python/ceval.o |
||||
+Python/dtrace.o: buildinclude $(srcdir)/Include/pydtrace.d Python/ceval.o |
||||
+ dtrace -o $@ $(DFLAGS) -C -G -s $(srcdir)/Include/pydtrace.d Python/ceval.o |
||||
+ |
||||
############################################################################ |
||||
# Header files |
||||
|
||||
@@ -1345,6 +1354,7 @@ clean: pycremoval |
||||
-rm -f Lib/lib2to3/*Grammar*.pickle |
||||
-rm -f Programs/_testembed Programs/_freeze_importlib |
||||
-rm -rf build |
||||
+ -rm -f $(srcdir)/Python/pysystemtap.h |
||||
|
||||
profile-removal: |
||||
find . -name '*.gc??' -exec rm -f {} ';' |
||||
diff -up Python-3.3.0rc2/pyconfig.h.in.systemtap Python-3.3.0rc2/pyconfig.h.in |
||||
--- Python-3.3.0rc2/pyconfig.h.in.systemtap 2012-09-09 05:11:14.000000000 -0400 |
||||
+++ Python-3.3.0rc2/pyconfig.h.in 2012-09-10 09:17:21.120511781 -0400 |
||||
@@ -1306,6 +1306,9 @@ |
||||
/* Define if you want to compile in Python-specific mallocs */ |
||||
#undef WITH_PYMALLOC |
||||
|
||||
+/* Define if you want to compile in SystemTap support */ |
||||
+#undef WITH_SYSTEMTAP |
||||
+ |
||||
/* Define if you want to compile in rudimentary thread support */ |
||||
#undef WITH_THREAD |
||||
|
||||
diff -up Python-3.3.0rc2/Python/ceval.c.systemtap Python-3.3.0rc2/Python/ceval.c |
||||
--- Python-3.3.0rc2/Python/ceval.c.systemtap 2012-09-09 05:11:12.000000000 -0400 |
||||
+++ Python-3.3.0rc2/Python/ceval.c 2012-09-10 09:17:21.122511781 -0400 |
||||
@@ -18,6 +18,8 @@ |
||||
@@ -1251,7 +1264,7 @@ Python/thread.o: @THREADHEADERS@ |
||||
.PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure |
||||
.PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools |
||||
.PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean |
||||
-.PHONY: smelly funny patchcheck touch altmaninstall |
||||
+.PHONY: smelly funny patchcheck touch altmaninstall buildinclude |
||||
.PHONY: gdbhooks |
||||
|
||||
# IF YOU PUT ANYTHING HERE IT WILL GO AWAY |
||||
diff -up Python-2.7rc1/pyconfig.h.in.systemtap Python-2.7rc1/pyconfig.h.in |
||||
--- Python-2.7rc1/pyconfig.h.in.systemtap 2010-05-08 07:04:18.000000000 -0400 |
||||
+++ Python-2.7rc1/pyconfig.h.in 2010-06-06 10:53:15.521974070 -0400 |
||||
@@ -1074,6 +1074,9 @@ |
||||
/* Define if you want documentation strings in extension modules */ |
||||
#undef WITH_DOC_STRINGS |
||||
|
||||
+/* Define if you want to compile in Dtrace support */ |
||||
+#undef WITH_DTRACE |
||||
+ |
||||
/* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic |
||||
linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). |
||||
Dyld is necessary to support frameworks. */ |
||||
diff -up Python-2.7rc1/Python/ceval.c.systemtap Python-2.7rc1/Python/ceval.c |
||||
--- Python-2.7rc1/Python/ceval.c.systemtap 2010-05-09 10:46:46.000000000 -0400 |
||||
+++ Python-2.7rc1/Python/ceval.c 2010-06-06 11:08:40.683100500 -0400 |
||||
@@ -19,6 +19,10 @@ |
||||
|
||||
#include <ctype.h> |
||||
|
||||
+#include "ceval_systemtap.h" |
||||
+#ifdef WITH_DTRACE |
||||
+#include "pydtrace.h" |
||||
+#endif |
||||
+ |
||||
#ifndef WITH_TSC |
||||
|
||||
#define READ_TIMESTAMP(var) |
||||
@@ -1160,6 +1162,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int |
||||
} |
||||
} |
||||
|
||||
+ if (PYTHON_FUNCTION_ENTRY_ENABLED()) { |
||||
+ systemtap_function_entry(f); |
||||
+ } |
||||
+ |
||||
co = f->f_code; |
||||
names = co->co_names; |
||||
consts = co->co_consts; |
||||
@@ -3077,6 +3083,11 @@ fast_yield: |
||||
@@ -671,6 +675,55 @@ PyEval_EvalCode(PyCodeObject *co, PyObje |
||||
NULL); |
||||
} |
||||
|
||||
/* pop frame */ |
||||
exit_eval_frame: |
||||
+ |
||||
+ if (PYTHON_FUNCTION_RETURN_ENABLED()) { |
||||
+ systemtap_function_return(f); |
||||
+ } |
||||
+ |
||||
Py_LeaveRecursiveCall(); |
||||
f->f_executing = 0; |
||||
tstate->frame = f->f_back; |
||||
diff -up Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap Python-3.3.0rc2/Python/ceval_systemtap.h |
||||
--- Python-3.3.0rc2/Python/ceval_systemtap.h.systemtap 2012-09-10 09:17:21.122511781 -0400 |
||||
+++ Python-3.3.0rc2/Python/ceval_systemtap.h 2012-09-10 09:17:21.122511781 -0400 |
||||
@@ -0,0 +1,86 @@ |
||||
+/* |
||||
+ Support for SystemTap static markers |
||||
+*/ |
||||
+ |
||||
+#ifdef WITH_SYSTEMTAP |
||||
+ |
||||
+#include "pysystemtap.h" |
||||
+ |
||||
+/* |
||||
+ A struct to hold all of the information gathered when one of the traceable |
||||
+ markers is triggered |
||||
+*/ |
||||
+struct frame_marker_info |
||||
+#ifdef WITH_DTRACE |
||||
+static void |
||||
+dtrace_entry(PyFrameObject *f) |
||||
+{ |
||||
+ PyObject *filename_obj; |
||||
+ PyObject *funcname_obj; |
||||
+ const char *filename; |
||||
+ const char *funcname; |
||||
+ const char *fname; |
||||
+ int lineno; |
||||
+}; |
||||
+ |
||||
+static void |
||||
+get_frame_marker_info(PyFrameObject *f, struct frame_marker_info *fmi) |
||||
+{ |
||||
+ PyObject *ptype; |
||||
+ PyObject *pvalue; |
||||
+ PyObject *ptraceback; |
||||
+ |
||||
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback); |
||||
+ |
||||
+ fmi->filename_obj = PyUnicode_EncodeFSDefault(f->f_code->co_filename); |
||||
+ if (fmi->filename_obj) { |
||||
+ fmi->filename = PyBytes_AsString(fmi->filename_obj); |
||||
+ } else { |
||||
+ fmi->filename = NULL; |
||||
+ } |
||||
+ filename = PyString_AsString(f->f_code->co_filename); |
||||
+ fname = PyString_AsString(f->f_code->co_name); |
||||
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); |
||||
+ |
||||
+ fmi->funcname_obj = PyUnicode_AsUTF8String(f->f_code->co_name); |
||||
+ if (fmi->funcname_obj) { |
||||
+ fmi->funcname = PyBytes_AsString(fmi->funcname_obj); |
||||
+ } else { |
||||
+ fmi->funcname = NULL; |
||||
+ } |
||||
+ |
||||
+ fmi->lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); |
||||
+ |
||||
+ PyErr_Restore(ptype, pvalue, ptraceback); |
||||
+ PYTHON_FUNCTION_ENTRY((char *)filename, (char *)fname, lineno); |
||||
+ |
||||
+ /* |
||||
+ * Currently a USDT tail-call will not receive the correct arguments. |
||||
+ * Disable the tail call here. |
||||
+ */ |
||||
+#if defined(__sparc) |
||||
+ asm("nop"); |
||||
+#endif |
||||
+} |
||||
+ |
||||
+static void |
||||
+release_frame_marker_info(struct frame_marker_info *fmi) |
||||
+dtrace_return(PyFrameObject *f) |
||||
+{ |
||||
+ Py_XDECREF(fmi->filename_obj); |
||||
+ Py_XDECREF(fmi->funcname_obj); |
||||
+} |
||||
+ const char *filename; |
||||
+ const char *fname; |
||||
+ int lineno; |
||||
+ |
||||
+static void |
||||
+systemtap_function_entry(PyFrameObject *f) |
||||
+{ |
||||
+ struct frame_marker_info fmi; |
||||
+ get_frame_marker_info(f, &fmi); |
||||
+ PYTHON_FUNCTION_ENTRY(fmi.filename, fmi.funcname, fmi.lineno, f); |
||||
+ release_frame_marker_info(&fmi); |
||||
+} |
||||
+ filename = PyString_AsString(f->f_code->co_filename); |
||||
+ fname = PyString_AsString(f->f_code->co_name); |
||||
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); |
||||
+ PYTHON_FUNCTION_RETURN((char *)filename, (char *)fname, lineno); |
||||
+ |
||||
+static void |
||||
+systemtap_function_return(PyFrameObject *f) |
||||
+{ |
||||
+ struct frame_marker_info fmi; |
||||
+ get_frame_marker_info(f, &fmi); |
||||
+ PYTHON_FUNCTION_RETURN(fmi.filename, fmi.funcname, fmi.lineno, f); |
||||
+ release_frame_marker_info(&fmi); |
||||
+ /* |
||||
+ * Currently a USDT tail-call will not receive the correct arguments. |
||||
+ * Disable the tail call here. |
||||
+ */ |
||||
+#if defined(__sparc) |
||||
+ asm("nop"); |
||||
+#endif |
||||
+} |
||||
+#else |
||||
+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0 |
||||
+#define PYTHON_FUNCTION_RETURN_ENABLED() 0 |
||||
+#define dtrace_entry(f) |
||||
+#define dtrace_return(f) |
||||
+#endif |
||||
|
||||
/* Interpreter main loop */ |
||||
|
||||
@@ -909,6 +962,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int |
||||
} |
||||
} |
||||
|
||||
+ if (PYTHON_FUNCTION_ENTRY_ENABLED()) |
||||
+ dtrace_entry(f); |
||||
+ |
||||
+#else /* #ifdef WITH_SYSTEMTAP */ |
||||
+ |
||||
+/* |
||||
+ When configured --without-systemtap, everything compiles away to nothing: |
||||
+*/ |
||||
+#define PYTHON_FUNCTION_ENTRY_ENABLED() 0 |
||||
+#define PYTHON_FUNCTION_RETURN_ENABLED() 0 |
||||
+#define systemtap_function_entry(f) |
||||
+#define systemtap_function_return(f) |
||||
co = f->f_code; |
||||
names = co->co_names; |
||||
consts = co->co_consts; |
||||
@@ -3000,6 +3056,9 @@ fast_yield: |
||||
|
||||
/* pop frame */ |
||||
exit_eval_frame: |
||||
+ if (PYTHON_FUNCTION_RETURN_ENABLED()) |
||||
+ dtrace_return(f); |
||||
+ |
||||
+#endif |
||||
diff -up Python-3.3.0rc2/Python/pysystemtap.d.systemtap Python-3.3.0rc2/Python/pysystemtap.d |
||||
--- Python-3.3.0rc2/Python/pysystemtap.d.systemtap 2012-09-10 09:17:21.122511781 -0400 |
||||
+++ Python-3.3.0rc2/Python/pysystemtap.d 2012-09-10 09:17:21.122511781 -0400 |
||||
@@ -0,0 +1,4 @@ |
||||
+provider python { |
||||
+ probe function__entry(const char *, const char *, int, PyFrameObject *); |
||||
+ probe function__return(const char *, const char *, int, PyFrameObject *); |
||||
+}; |
||||
Py_LeaveRecursiveCall(); |
||||
tstate->frame = f->f_back; |
||||
|
||||
|
@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
|
||||
diff -up Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py |
||||
--- Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py.skip-distutils-tests-that-fail-in-rpmbuild 2011-09-03 12:16:40.000000000 -0400 |
||||
+++ Python-3.2.2/Lib/distutils/tests/test_bdist_rpm.py 2011-09-10 05:04:56.328852558 -0400 |
||||
@@ -23,6 +23,7 @@ setup(name='foo', version='0.1', py_modu |
||||
diff -up Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py |
||||
--- Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py.mark-tests-that-fail-in-rpmbuild 2012-04-09 19:07:29.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/tests/test_bdist_rpm.py 2012-04-13 00:20:08.223819263 -0400 |
||||
@@ -24,6 +24,7 @@ setup(name='foo', version='0.1', py_modu |
||||
|
||||
""" |
||||
|
||||
+@unittest._skipInRpmBuild("don't try to nest one rpm build inside another rpm build") |
||||
class BuildRpmTestCase(support.TempdirManager, |
||||
support.EnvironGuard, |
||||
support.LoggingSilencer, |
||||
diff -up Python-3.2.2/Lib/distutils/tests/test_build_ext.py.skip-distutils-tests-that-fail-in-rpmbuild Python-3.2.2/Lib/distutils/tests/test_build_ext.py |
||||
unittest.TestCase): |
||||
diff -up Python-2.7.3/Lib/distutils/tests/test_build_ext.py.mark-tests-that-fail-in-rpmbuild Python-2.7.3/Lib/distutils/tests/test_build_ext.py |
||||
|
@ -1,13 +1,12 @@
@@ -1,13 +1,12 @@
|
||||
diff --git a/config.sub b/config.sub |
||||
index 40ea5df..932128b 100755 |
||||
--- a/config.sub |
||||
+++ b/config.sub |
||||
@@ -1045,7 +1045,7 @@ case $basic_machine in |
||||
diff -r de35eae9048a config.sub |
||||
--- a/config.sub Wed Apr 24 23:33:20 2013 +0200 |
||||
+++ b/config.sub Thu Apr 25 08:51:00 2013 +0200 |
||||
@@ -1008,7 +1008,7 @@ |
||||
;; |
||||
ppc64) basic_machine=powerpc64-unknown |
||||
;; |
||||
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` |
||||
+ ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` |
||||
;; |
||||
ppc64le | powerpc64little) |
||||
ppc64le | powerpc64little | ppc64-le | powerpc64-little) |
||||
basic_machine=powerpc64le-unknown |
||||
|
@ -0,0 +1,353 @@
@@ -0,0 +1,353 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1399849904 25200 |
||||
# Node ID b40f1a00b13460cc089450028280c4e52dd24a64 |
||||
# Parent 951775c68b1b7782750c213b0fce1f61d46b2f51 |
||||
backport hmac.compare_digest to partially implement PEP 466 (closes #21306) |
||||
|
||||
Backport from Alex Gaynor. |
||||
|
||||
diff --git a/Doc/library/hmac.rst b/Doc/library/hmac.rst |
||||
--- a/Doc/library/hmac.rst |
||||
+++ b/Doc/library/hmac.rst |
||||
@@ -38,6 +38,13 @@ An HMAC object has the following methods |
||||
This string will be the same length as the *digest_size* of the digest given to |
||||
the constructor. It may contain non-ASCII characters, including NUL bytes. |
||||
|
||||
+ .. warning:: |
||||
+ |
||||
+ When comparing the output of :meth:`digest` to an externally-supplied |
||||
+ digest during a verification routine, it is recommended to use the |
||||
+ :func:`compare_digest` function instead of the ``==`` operator |
||||
+ to reduce the vulnerability to timing attacks. |
||||
+ |
||||
|
||||
.. method:: HMAC.hexdigest() |
||||
|
||||
@@ -45,6 +52,13 @@ An HMAC object has the following methods |
||||
containing only hexadecimal digits. This may be used to exchange the value |
||||
safely in email or other non-binary environments. |
||||
|
||||
+ .. warning:: |
||||
+ |
||||
+ When comparing the output of :meth:`hexdigest` to an externally-supplied |
||||
+ digest during a verification routine, it is recommended to use the |
||||
+ :func:`compare_digest` function instead of the ``==`` operator |
||||
+ to reduce the vulnerability to timing attacks. |
||||
+ |
||||
|
||||
.. method:: HMAC.copy() |
||||
|
||||
@@ -52,6 +66,25 @@ An HMAC object has the following methods |
||||
compute the digests of strings that share a common initial substring. |
||||
|
||||
|
||||
+This module also provides the following helper function: |
||||
+ |
||||
+.. function:: compare_digest(a, b) |
||||
+ |
||||
+ Return ``a == b``. This function uses an approach designed to prevent |
||||
+ timing analysis by avoiding content-based short circuiting behaviour, |
||||
+ making it appropriate for cryptography. *a* and *b* must both be of the |
||||
+ same type: either :class:`unicode` or a :term:`bytes-like object`. |
||||
+ |
||||
+ .. note:: |
||||
+ |
||||
+ If *a* and *b* are of different lengths, or if an error occurs, |
||||
+ a timing attack could theoretically reveal information about the |
||||
+ types and lengths of *a* and *b*--but not their values. |
||||
+ |
||||
+ |
||||
+ .. versionadded:: 2.7.7 |
||||
+ |
||||
+ |
||||
.. seealso:: |
||||
|
||||
Module :mod:`hashlib` |
||||
diff --git a/Lib/hmac.py b/Lib/hmac.py |
||||
--- a/Lib/hmac.py |
||||
+++ b/Lib/hmac.py |
||||
@@ -5,6 +5,9 @@ Implements the HMAC algorithm as describ |
||||
|
||||
import warnings as _warnings |
||||
|
||||
+from operator import _compare_digest as compare_digest |
||||
+ |
||||
+ |
||||
trans_5C = "".join ([chr (x ^ 0x5C) for x in xrange(256)]) |
||||
trans_36 = "".join ([chr (x ^ 0x36) for x in xrange(256)]) |
||||
|
||||
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py |
||||
--- a/Lib/test/test_hmac.py |
||||
+++ b/Lib/test/test_hmac.py |
||||
@@ -302,12 +302,122 @@ class CopyTestCase(unittest.TestCase): |
||||
self.assertTrue(h1.hexdigest() == h2.hexdigest(), |
||||
"Hexdigest of copy doesn't match original hexdigest.") |
||||
|
||||
+ |
||||
+class CompareDigestTestCase(unittest.TestCase): |
||||
+ |
||||
+ def test_compare_digest(self): |
||||
+ # Testing input type exception handling |
||||
+ a, b = 100, 200 |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = 100, b"foobar" |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = b"foobar", 200 |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = u"foobar", b"foobar" |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = b"foobar", u"foobar" |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ |
||||
+ # Testing bytes of different lengths |
||||
+ a, b = b"foobar", b"foo" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ a, b = b"\xde\xad\xbe\xef", b"\xde\xad" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytes of same lengths, different values |
||||
+ a, b = b"foobar", b"foobaz" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ a, b = b"\xde\xad\xbe\xef", b"\xab\xad\x1d\xea" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytes of same lengths, same values |
||||
+ a, b = b"foobar", b"foobar" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ a, b = b"\xde\xad\xbe\xef", b"\xde\xad\xbe\xef" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytearrays of same lengths, same values |
||||
+ a, b = bytearray(b"foobar"), bytearray(b"foobar") |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytearrays of diffeent lengths |
||||
+ a, b = bytearray(b"foobar"), bytearray(b"foo") |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytearrays of same lengths, different values |
||||
+ a, b = bytearray(b"foobar"), bytearray(b"foobaz") |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing byte and bytearray of same lengths, same values |
||||
+ a, b = bytearray(b"foobar"), b"foobar" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ self.assertTrue(hmac.compare_digest(b, a)) |
||||
+ |
||||
+ # Testing byte bytearray of diffeent lengths |
||||
+ a, b = bytearray(b"foobar"), b"foo" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ self.assertFalse(hmac.compare_digest(b, a)) |
||||
+ |
||||
+ # Testing byte and bytearray of same lengths, different values |
||||
+ a, b = bytearray(b"foobar"), b"foobaz" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ self.assertFalse(hmac.compare_digest(b, a)) |
||||
+ |
||||
+ # Testing str of same lengths |
||||
+ a, b = "foobar", "foobar" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing str of diffeent lengths |
||||
+ a, b = "foo", "foobar" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing bytes of same lengths, different values |
||||
+ a, b = "foobar", "foobaz" |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # Testing error cases |
||||
+ a, b = u"foobar", b"foobar" |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = b"foobar", u"foobar" |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = b"foobar", 1 |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = 100, 200 |
||||
+ self.assertRaises(TypeError, hmac.compare_digest, a, b) |
||||
+ a, b = "fooä", "fooä" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ # subclasses are supported by ignore __eq__ |
||||
+ class mystr(str): |
||||
+ def __eq__(self, other): |
||||
+ return False |
||||
+ |
||||
+ a, b = mystr("foobar"), mystr("foobar") |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ a, b = mystr("foobar"), "foobar" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ a, b = mystr("foobar"), mystr("foobaz") |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ class mybytes(bytes): |
||||
+ def __eq__(self, other): |
||||
+ return False |
||||
+ |
||||
+ a, b = mybytes(b"foobar"), mybytes(b"foobar") |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ a, b = mybytes(b"foobar"), b"foobar" |
||||
+ self.assertTrue(hmac.compare_digest(a, b)) |
||||
+ a, b = mybytes(b"foobar"), mybytes(b"foobaz") |
||||
+ self.assertFalse(hmac.compare_digest(a, b)) |
||||
+ |
||||
+ |
||||
def test_main(): |
||||
test_support.run_unittest( |
||||
TestVectorsTestCase, |
||||
ConstructorTestCase, |
||||
SanityTestCase, |
||||
- CopyTestCase |
||||
+ CopyTestCase, |
||||
+ CompareDigestTestCase, |
||||
) |
||||
|
||||
if __name__ == "__main__": |
||||
diff --git a/Modules/operator.c b/Modules/operator.c |
||||
--- a/Modules/operator.c |
||||
+++ b/Modules/operator.c |
||||
@@ -235,6 +235,132 @@ op_delslice(PyObject *s, PyObject *a) |
||||
#define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \ |
||||
{#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)}, |
||||
|
||||
+ |
||||
+ |
||||
+/* compare_digest **********************************************************/ |
||||
+ |
||||
+/* |
||||
+ * timing safe compare |
||||
+ * |
||||
+ * Returns 1 of the strings are equal. |
||||
+ * In case of len(a) != len(b) the function tries to keep the timing |
||||
+ * dependent on the length of b. CPU cache locally may still alter timing |
||||
+ * a bit. |
||||
+ */ |
||||
+static int |
||||
+_tscmp(const unsigned char *a, const unsigned char *b, |
||||
+ Py_ssize_t len_a, Py_ssize_t len_b) |
||||
+{ |
||||
+ /* The volatile type declarations make sure that the compiler has no |
||||
+ * chance to optimize and fold the code in any way that may change |
||||
+ * the timing. |
||||
+ */ |
||||
+ volatile Py_ssize_t length; |
||||
+ volatile const unsigned char *left; |
||||
+ volatile const unsigned char *right; |
||||
+ Py_ssize_t i; |
||||
+ unsigned char result; |
||||
+ |
||||
+ /* loop count depends on length of b */ |
||||
+ length = len_b; |
||||
+ left = NULL; |
||||
+ right = b; |
||||
+ |
||||
+ /* don't use else here to keep the amount of CPU instructions constant, |
||||
+ * volatile forces re-evaluation |
||||
+ * */ |
||||
+ if (len_a == length) { |
||||
+ left = *((volatile const unsigned char**)&a); |
||||
+ result = 0; |
||||
+ } |
||||
+ if (len_a != length) { |
||||
+ left = b; |
||||
+ result = 1; |
||||
+ } |
||||
+ |
||||
+ for (i=0; i < length; i++) { |
||||
+ result |= *left++ ^ *right++; |
||||
+ } |
||||
+ |
||||
+ return (result == 0); |
||||
+} |
||||
+ |
||||
+PyDoc_STRVAR(compare_digest__doc__, |
||||
+"compare_digest(a, b) -> bool\n" |
||||
+"\n" |
||||
+"Return 'a == b'. This function uses an approach designed to prevent\n" |
||||
+"timing analysis, making it appropriate for cryptography.\n" |
||||
+"a and b must both be of the same type: either str (ASCII only),\n" |
||||
+"or any type that supports the buffer protocol (e.g. bytes).\n" |
||||
+"\n" |
||||
+"Note: If a and b are of different lengths, or if an error occurs,\n" |
||||
+"a timing attack could theoretically reveal information about the\n" |
||||
+"types and lengths of a and b--but not their values.\n"); |
||||
+ |
||||
+static PyObject* |
||||
+compare_digest(PyObject *self, PyObject *args) |
||||
+{ |
||||
+ PyObject *a, *b; |
||||
+ int rc; |
||||
+ |
||||
+ if (!PyArg_ParseTuple(args, "OO:compare_digest", &a, &b)) { |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ /* Unicode string */ |
||||
+ if (PyUnicode_Check(a) && PyUnicode_Check(b)) { |
||||
+ rc = _tscmp(PyUnicode_AS_DATA(a), |
||||
+ PyUnicode_AS_DATA(b), |
||||
+ PyUnicode_GET_DATA_SIZE(a), |
||||
+ PyUnicode_GET_DATA_SIZE(b)); |
||||
+ } |
||||
+ /* fallback to buffer interface for bytes, bytesarray and other */ |
||||
+ else { |
||||
+ Py_buffer view_a; |
||||
+ Py_buffer view_b; |
||||
+ |
||||
+ if ((PyObject_CheckBuffer(a) == 0) & (PyObject_CheckBuffer(b) == 0)) { |
||||
+ PyErr_Format(PyExc_TypeError, |
||||
+ "unsupported operand types(s) or combination of types: " |
||||
+ "'%.100s' and '%.100s'", |
||||
+ Py_TYPE(a)->tp_name, Py_TYPE(b)->tp_name); |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ if (PyObject_GetBuffer(a, &view_a, PyBUF_SIMPLE) == -1) { |
||||
+ return NULL; |
||||
+ } |
||||
+ if (view_a.ndim > 1) { |
||||
+ PyErr_SetString(PyExc_BufferError, |
||||
+ "Buffer must be single dimension"); |
||||
+ PyBuffer_Release(&view_a); |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ if (PyObject_GetBuffer(b, &view_b, PyBUF_SIMPLE) == -1) { |
||||
+ PyBuffer_Release(&view_a); |
||||
+ return NULL; |
||||
+ } |
||||
+ if (view_b.ndim > 1) { |
||||
+ PyErr_SetString(PyExc_BufferError, |
||||
+ "Buffer must be single dimension"); |
||||
+ PyBuffer_Release(&view_a); |
||||
+ PyBuffer_Release(&view_b); |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ rc = _tscmp((const unsigned char*)view_a.buf, |
||||
+ (const unsigned char*)view_b.buf, |
||||
+ view_a.len, |
||||
+ view_b.len); |
||||
+ |
||||
+ PyBuffer_Release(&view_a); |
||||
+ PyBuffer_Release(&view_b); |
||||
+ } |
||||
+ |
||||
+ return PyBool_FromLong(rc); |
||||
+} |
||||
+ |
||||
static struct PyMethodDef operator_methods[] = { |
||||
|
||||
spam1o(isCallable, |
||||
@@ -318,6 +444,8 @@ spam2(ne,__ne__, "ne(a, b) -- Same as a! |
||||
spam2(gt,__gt__, "gt(a, b) -- Same as a>b.") |
||||
spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.") |
||||
|
||||
+ {"_compare_digest", (PyCFunction)compare_digest, METH_VARARGS, |
||||
+ compare_digest__doc__}, |
||||
{NULL, NULL} /* sentinel */ |
||||
|
||||
}; |
||||
|
@ -0,0 +1,489 @@
@@ -0,0 +1,489 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1401567982 25200 |
||||
# Node ID e4da3ba9dcac4374ca0ccc46a48c32be6f951038 |
||||
# Parent 8fa8c290c165dccd613632b69a816623b51e801e |
||||
backport hashlib.pbkdf2_hmac per PEP 466 (closes #21304) |
||||
|
||||
Backport by Alex Gaynor. |
||||
|
||||
diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst |
||||
--- a/Doc/library/hashlib.rst |
||||
+++ b/Doc/library/hashlib.rst |
||||
@@ -135,6 +135,46 @@ A hash object has the following methods: |
||||
compute the digests of strings that share a common initial substring. |
||||
|
||||
|
||||
+Key Derivation Function |
||||
+----------------------- |
||||
+ |
||||
+Key derivation and key stretching algorithms are designed for secure password |
||||
+hashing. Naive algorithms such as ``sha1(password)`` are not resistant against |
||||
+brute-force attacks. A good password hashing function must be tunable, slow, and |
||||
+include a `salt <https://en.wikipedia.org/wiki/Salt_%28cryptography%29>`_. |
||||
+ |
||||
+ |
||||
+.. function:: pbkdf2_hmac(name, password, salt, rounds, dklen=None) |
||||
+ |
||||
+ The function provides PKCS#5 password-based key derivation function 2. It |
||||
+ uses HMAC as pseudorandom function. |
||||
+ |
||||
+ The string *name* is the desired name of the hash digest algorithm for |
||||
+ HMAC, e.g. 'sha1' or 'sha256'. *password* and *salt* are interpreted as |
||||
+ buffers of bytes. Applications and libraries should limit *password* to |
||||
+ a sensible value (e.g. 1024). *salt* should be about 16 or more bytes from |
||||
+ a proper source, e.g. :func:`os.urandom`. |
||||
+ |
||||
+ The number of *rounds* should be chosen based on the hash algorithm and |
||||
+ computing power. As of 2013, at least 100,000 rounds of SHA-256 is suggested. |
||||
+ |
||||
+ *dklen* is the length of the derived key. If *dklen* is ``None`` then the |
||||
+ digest size of the hash algorithm *name* is used, e.g. 64 for SHA-512. |
||||
+ |
||||
+ >>> import hashlib, binascii |
||||
+ >>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000) |
||||
+ >>> binascii.hexlify(dk) |
||||
+ b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5' |
||||
+ |
||||
+ .. versionadded:: 2.7.8 |
||||
+ |
||||
+ .. note:: |
||||
+ |
||||
+ A fast implementation of *pbkdf2_hmac* is available with OpenSSL. The |
||||
+ Python implementation uses an inline version of :mod:`hmac`. It is about |
||||
+ three times slower and doesn't release the GIL. |
||||
+ |
||||
+ |
||||
.. seealso:: |
||||
|
||||
Module :mod:`hmac` |
||||
diff --git a/Lib/hashlib.py b/Lib/hashlib.py |
||||
--- a/Lib/hashlib.py |
||||
+++ b/Lib/hashlib.py |
||||
@@ -77,7 +77,7 @@ __always_supported = ('md5', 'sha1', 'sh |
||||
|
||||
algorithms = __always_supported |
||||
|
||||
-__all__ = __always_supported + ('new', 'algorithms') |
||||
+__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac') |
||||
|
||||
|
||||
def __get_openssl_constructor(name): |
||||
@@ -123,6 +123,72 @@ for __func_name in __always_supported: |
||||
import logging |
||||
logging.exception('code for hash %s was not found.', __func_name) |
||||
|
||||
+try: |
||||
+ # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA |
||||
+ from _hashlib import pbkdf2_hmac |
||||
+except ImportError: |
||||
+ import binascii |
||||
+ import struct |
||||
+ |
||||
+ _trans_5C = b"".join(chr(x ^ 0x5C) for x in range(256)) |
||||
+ _trans_36 = b"".join(chr(x ^ 0x36) for x in range(256)) |
||||
+ |
||||
+ def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None): |
||||
+ """Password based key derivation function 2 (PKCS #5 v2.0) |
||||
+ |
||||
+ This Python implementations based on the hmac module about as fast |
||||
+ as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster |
||||
+ for long passwords. |
||||
+ """ |
||||
+ if not isinstance(hash_name, str): |
||||
+ raise TypeError(hash_name) |
||||
+ |
||||
+ if not isinstance(password, (bytes, bytearray)): |
||||
+ password = bytes(buffer(password)) |
||||
+ if not isinstance(salt, (bytes, bytearray)): |
||||
+ salt = bytes(buffer(salt)) |
||||
+ |
||||
+ # Fast inline HMAC implementation |
||||
+ inner = new(hash_name) |
||||
+ outer = new(hash_name) |
||||
+ blocksize = getattr(inner, 'block_size', 64) |
||||
+ if len(password) > blocksize: |
||||
+ password = new(hash_name, password).digest() |
||||
+ password = password + b'\x00' * (blocksize - len(password)) |
||||
+ inner.update(password.translate(_trans_36)) |
||||
+ outer.update(password.translate(_trans_5C)) |
||||
+ |
||||
+ def prf(msg, inner=inner, outer=outer): |
||||
+ # PBKDF2_HMAC uses the password as key. We can re-use the same |
||||
+ # digest objects and and just update copies to skip initialization. |
||||
+ icpy = inner.copy() |
||||
+ ocpy = outer.copy() |
||||
+ icpy.update(msg) |
||||
+ ocpy.update(icpy.digest()) |
||||
+ return ocpy.digest() |
||||
+ |
||||
+ if iterations < 1: |
||||
+ raise ValueError(iterations) |
||||
+ if dklen is None: |
||||
+ dklen = outer.digest_size |
||||
+ if dklen < 1: |
||||
+ raise ValueError(dklen) |
||||
+ |
||||
+ hex_format_string = "%%0%ix" % (new(hash_name).digest_size * 2) |
||||
+ |
||||
+ dkey = b'' |
||||
+ loop = 1 |
||||
+ while len(dkey) < dklen: |
||||
+ prev = prf(salt + struct.pack(b'>I', loop)) |
||||
+ rkey = int(binascii.hexlify(prev), 16) |
||||
+ for i in xrange(iterations - 1): |
||||
+ prev = prf(prev) |
||||
+ rkey ^= int(binascii.hexlify(prev), 16) |
||||
+ loop += 1 |
||||
+ dkey += binascii.unhexlify(hex_format_string % rkey) |
||||
+ |
||||
+ return dkey[:dklen] |
||||
+ |
||||
# Cleanup locals() |
||||
del __always_supported, __func_name, __get_hash |
||||
del __hash_new, __get_openssl_constructor |
||||
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py |
||||
--- a/Lib/test/test_hashlib.py |
||||
+++ b/Lib/test/test_hashlib.py |
||||
@@ -16,6 +16,8 @@ except ImportError: |
||||
threading = None |
||||
import unittest |
||||
import warnings |
||||
+from binascii import unhexlify |
||||
+ |
||||
from test import test_support |
||||
from test.test_support import _4G, precisionbigmemtest |
||||
|
||||
@@ -436,8 +438,72 @@ class HashLibTestCase(unittest.TestCase) |
||||
|
||||
|
||||
|
||||
+class KDFTests(unittest.TestCase): |
||||
+ pbkdf2_test_vectors = [ |
||||
+ (b'password', b'salt', 1, None), |
||||
+ (b'password', b'salt', 2, None), |
||||
+ (b'password', b'salt', 4096, None), |
||||
+ # too slow, it takes over a minute on a fast CPU. |
||||
+ #(b'password', b'salt', 16777216, None), |
||||
+ (b'passwordPASSWORDpassword', b'saltSALTsaltSALTsaltSALTsaltSALTsalt', |
||||
+ 4096, -1), |
||||
+ (b'pass\0word', b'sa\0lt', 4096, 16), |
||||
+ ] |
||||
+ |
||||
+ pbkdf2_results = { |
||||
+ "sha1": [ |
||||
+ # offical test vectors from RFC 6070 |
||||
+ (unhexlify('0c60c80f961f0e71f3a9b524af6012062fe037a6'), None), |
||||
+ (unhexlify('ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'), None), |
||||
+ (unhexlify('4b007901b765489abead49d926f721d065a429c1'), None), |
||||
+ #(unhexlify('eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'), None), |
||||
+ (unhexlify('3d2eec4fe41c849b80c8d83662c0e44a8b291a964c' |
||||
+ 'f2f07038'), 25), |
||||
+ (unhexlify('56fa6aa75548099dcc37d7f03425e0c3'), None),], |
||||
+ "sha256": [ |
||||
+ (unhexlify('120fb6cffcf8b32c43e7225256c4f837' |
||||
+ 'a86548c92ccc35480805987cb70be17b'), None), |
||||
+ (unhexlify('ae4d0c95af6b46d32d0adff928f06dd0' |
||||
+ '2a303f8ef3c251dfd6e2d85a95474c43'), None), |
||||
+ (unhexlify('c5e478d59288c841aa530db6845c4c8d' |
||||
+ '962893a001ce4e11a4963873aa98134a'), None), |
||||
+ #(unhexlify('cf81c66fe8cfc04d1f31ecb65dab4089' |
||||
+ # 'f7f179e89b3b0bcb17ad10e3ac6eba46'), None), |
||||
+ (unhexlify('348c89dbcbd32b2f32d814b8116e84cf2b17' |
||||
+ '347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9'), 40), |
||||
+ (unhexlify('89b69d0516f829893c696226650a8687'), None),], |
||||
+ "sha512": [ |
||||
+ (unhexlify('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5' |
||||
+ 'd513554e1c8cf252c02d470a285a0501bad999bfe943c08f' |
||||
+ '050235d7d68b1da55e63f73b60a57fce'), None), |
||||
+ (unhexlify('e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f004071' |
||||
+ '3f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82' |
||||
+ 'be67335c77a6068e04112754f27ccf4e'), None), |
||||
+ (unhexlify('d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f8' |
||||
+ '7f6902e072f457b5143f30602641b3d55cd335988cb36b84' |
||||
+ '376060ecd532e039b742a239434af2d5'), None), |
||||
+ (unhexlify('8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b8' |
||||
+ '68c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30' |
||||
+ '225c583a186cd82bd4daea9724a3d3b8'), 64), |
||||
+ (unhexlify('9d9e9c4cd21fe4be24d5b8244c759665'), None),], |
||||
+ } |
||||
+ |
||||
+ def test_pbkdf2_hmac(self): |
||||
+ for digest_name, results in self.pbkdf2_results.items(): |
||||
+ for i, vector in enumerate(self.pbkdf2_test_vectors): |
||||
+ password, salt, rounds, dklen = vector |
||||
+ expected, overwrite_dklen = results[i] |
||||
+ if overwrite_dklen: |
||||
+ dklen = overwrite_dklen |
||||
+ out = hashlib.pbkdf2_hmac( |
||||
+ digest_name, password, salt, rounds, dklen) |
||||
+ self.assertEqual(out, expected, |
||||
+ (digest_name, password, salt, rounds, dklen)) |
||||
+ |
||||
+ |
||||
+ |
||||
def test_main(): |
||||
- test_support.run_unittest(HashLibTestCase) |
||||
+ test_support.run_unittest(HashLibTestCase, KDFTests) |
||||
|
||||
if __name__ == "__main__": |
||||
test_main() |
||||
diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c |
||||
--- a/Modules/_hashopenssl.c |
||||
+++ b/Modules/_hashopenssl.c |
||||
@@ -39,6 +39,7 @@ |
||||
#include <openssl/ssl.h> |
||||
#include <openssl/err.h> |
||||
#include <openssl/evp.h> |
||||
+#include <openssl/hmac.h> |
||||
|
||||
#define MUNCH_SIZE INT_MAX |
||||
|
||||
@@ -563,6 +564,226 @@ EVP_new(PyObject *self, PyObject *args, |
||||
return ret_obj; |
||||
} |
||||
|
||||
+ |
||||
+ |
||||
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000 && !defined(OPENSSL_NO_HMAC) \ |
||||
+ && !defined(OPENSSL_NO_SHA)) |
||||
+ |
||||
+#define PY_PBKDF2_HMAC 1 |
||||
+ |
||||
+/* Improved implementation of PKCS5_PBKDF2_HMAC() |
||||
+ * |
||||
+ * PKCS5_PBKDF2_HMAC_fast() hashes the password exactly one time instead of |
||||
+ * `iter` times. Today (2013) the iteration count is typically 100,000 or |
||||
+ * more. The improved algorithm is not subject to a Denial-of-Service |
||||
+ * vulnerability with overly large passwords. |
||||
+ * |
||||
+ * Also OpenSSL < 1.0 don't provide PKCS5_PBKDF2_HMAC(), only |
||||
+ * PKCS5_PBKDF2_SHA1. |
||||
+ */ |
||||
+static int |
||||
+PKCS5_PBKDF2_HMAC_fast(const char *pass, int passlen, |
||||
+ const unsigned char *salt, int saltlen, |
||||
+ int iter, const EVP_MD *digest, |
||||
+ int keylen, unsigned char *out) |
||||
+{ |
||||
+ unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4]; |
||||
+ int cplen, j, k, tkeylen, mdlen; |
||||
+ unsigned long i = 1; |
||||
+ HMAC_CTX hctx_tpl, hctx; |
||||
+ |
||||
+ mdlen = EVP_MD_size(digest); |
||||
+ if (mdlen < 0) |
||||
+ return 0; |
||||
+ |
||||
+ HMAC_CTX_init(&hctx_tpl); |
||||
+ HMAC_CTX_init(&hctx); |
||||
+ p = out; |
||||
+ tkeylen = keylen; |
||||
+ if (!HMAC_Init_ex(&hctx_tpl, pass, passlen, digest, NULL)) { |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ return 0; |
||||
+ } |
||||
+ while(tkeylen) { |
||||
+ if(tkeylen > mdlen) |
||||
+ cplen = mdlen; |
||||
+ else |
||||
+ cplen = tkeylen; |
||||
+ /* We are unlikely to ever use more than 256 blocks (5120 bits!) |
||||
+ * but just in case... |
||||
+ */ |
||||
+ itmp[0] = (unsigned char)((i >> 24) & 0xff); |
||||
+ itmp[1] = (unsigned char)((i >> 16) & 0xff); |
||||
+ itmp[2] = (unsigned char)((i >> 8) & 0xff); |
||||
+ itmp[3] = (unsigned char)(i & 0xff); |
||||
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ return 0; |
||||
+ } |
||||
+ if (!HMAC_Update(&hctx, salt, saltlen) |
||||
+ || !HMAC_Update(&hctx, itmp, 4) |
||||
+ || !HMAC_Final(&hctx, digtmp, NULL)) { |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ HMAC_CTX_cleanup(&hctx); |
||||
+ return 0; |
||||
+ } |
||||
+ HMAC_CTX_cleanup(&hctx); |
||||
+ memcpy(p, digtmp, cplen); |
||||
+ for (j = 1; j < iter; j++) { |
||||
+ if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ return 0; |
||||
+ } |
||||
+ if (!HMAC_Update(&hctx, digtmp, mdlen) |
||||
+ || !HMAC_Final(&hctx, digtmp, NULL)) { |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ HMAC_CTX_cleanup(&hctx); |
||||
+ return 0; |
||||
+ } |
||||
+ HMAC_CTX_cleanup(&hctx); |
||||
+ for (k = 0; k < cplen; k++) { |
||||
+ p[k] ^= digtmp[k]; |
||||
+ } |
||||
+ } |
||||
+ tkeylen-= cplen; |
||||
+ i++; |
||||
+ p+= cplen; |
||||
+ } |
||||
+ HMAC_CTX_cleanup(&hctx_tpl); |
||||
+ return 1; |
||||
+} |
||||
+ |
||||
+/* LCOV_EXCL_START */ |
||||
+static PyObject * |
||||
+_setException(PyObject *exc) |
||||
+{ |
||||
+ unsigned long errcode; |
||||
+ const char *lib, *func, *reason; |
||||
+ |
||||
+ errcode = ERR_peek_last_error(); |
||||
+ if (!errcode) { |
||||
+ PyErr_SetString(exc, "unknown reasons"); |
||||
+ return NULL; |
||||
+ } |
||||
+ ERR_clear_error(); |
||||
+ |
||||
+ lib = ERR_lib_error_string(errcode); |
||||
+ func = ERR_func_error_string(errcode); |
||||
+ reason = ERR_reason_error_string(errcode); |
||||
+ |
||||
+ if (lib && func) { |
||||
+ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); |
||||
+ } |
||||
+ else if (lib) { |
||||
+ PyErr_Format(exc, "[%s] %s", lib, reason); |
||||
+ } |
||||
+ else { |
||||
+ PyErr_SetString(exc, reason); |
||||
+ } |
||||
+ return NULL; |
||||
+} |
||||
+/* LCOV_EXCL_STOP */ |
||||
+ |
||||
+PyDoc_STRVAR(pbkdf2_hmac__doc__, |
||||
+"pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None) -> key\n\ |
||||
+\n\ |
||||
+Password based key derivation function 2 (PKCS #5 v2.0) with HMAC as\n\ |
||||
+pseudorandom function."); |
||||
+ |
||||
+static PyObject * |
||||
+pbkdf2_hmac(PyObject *self, PyObject *args, PyObject *kwdict) |
||||
+{ |
||||
+ static char *kwlist[] = {"hash_name", "password", "salt", "iterations", |
||||
+ "dklen", NULL}; |
||||
+ PyObject *key_obj = NULL, *dklen_obj = Py_None; |
||||
+ char *name, *key; |
||||
+ Py_buffer password, salt; |
||||
+ long iterations, dklen; |
||||
+ int retval; |
||||
+ const EVP_MD *digest; |
||||
+ |
||||
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "ss*s*l|O:pbkdf2_hmac", |
||||
+ kwlist, &name, &password, &salt, |
||||
+ &iterations, &dklen_obj)) { |
||||
+ return NULL; |
||||
+ } |
||||
+ |
||||
+ digest = EVP_get_digestbyname(name); |
||||
+ if (digest == NULL) { |
||||
+ PyErr_SetString(PyExc_ValueError, "unsupported hash type"); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ if (password.len > INT_MAX) { |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "password is too long."); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ if (salt.len > INT_MAX) { |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "salt is too long."); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ if (iterations < 1) { |
||||
+ PyErr_SetString(PyExc_ValueError, |
||||
+ "iteration value must be greater than 0."); |
||||
+ goto end; |
||||
+ } |
||||
+ if (iterations > INT_MAX) { |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "iteration value is too great."); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ if (dklen_obj == Py_None) { |
||||
+ dklen = EVP_MD_size(digest); |
||||
+ } else { |
||||
+ dklen = PyLong_AsLong(dklen_obj); |
||||
+ if ((dklen == -1) && PyErr_Occurred()) { |
||||
+ goto end; |
||||
+ } |
||||
+ } |
||||
+ if (dklen < 1) { |
||||
+ PyErr_SetString(PyExc_ValueError, |
||||
+ "key length must be greater than 0."); |
||||
+ goto end; |
||||
+ } |
||||
+ if (dklen > INT_MAX) { |
||||
+ /* INT_MAX is always smaller than dkLen max (2^32 - 1) * hLen */ |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "key length is too great."); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ key_obj = PyBytes_FromStringAndSize(NULL, dklen); |
||||
+ if (key_obj == NULL) { |
||||
+ goto end; |
||||
+ } |
||||
+ key = PyBytes_AS_STRING(key_obj); |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ retval = PKCS5_PBKDF2_HMAC_fast((char*)password.buf, (int)password.len, |
||||
+ (unsigned char *)salt.buf, (int)salt.len, |
||||
+ iterations, digest, dklen, |
||||
+ (unsigned char *)key); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (!retval) { |
||||
+ Py_CLEAR(key_obj); |
||||
+ _setException(PyExc_ValueError); |
||||
+ goto end; |
||||
+ } |
||||
+ |
||||
+ end: |
||||
+ PyBuffer_Release(&password); |
||||
+ PyBuffer_Release(&salt); |
||||
+ return key_obj; |
||||
+} |
||||
+ |
||||
+#endif |
||||
+ |
||||
/* |
||||
* This macro and function generates a family of constructor function |
||||
* definitions for specific hash algorithms. These constructors are much |
||||
@@ -690,6 +911,10 @@ static struct PyMethodDef EVP_functions[ |
||||
CONSTRUCTOR_METH_DEF(sha384), |
||||
CONSTRUCTOR_METH_DEF(sha512), |
||||
#endif |
||||
+#ifdef PY_PBKDF2_HMAC |
||||
+ {"pbkdf2_hmac", (PyCFunction)pbkdf2_hmac, METH_VARARGS|METH_KEYWORDS, |
||||
+ pbkdf2_hmac__doc__}, |
||||
+#endif |
||||
{NULL, NULL} /* Sentinel */ |
||||
}; |
||||
|
||||
diff -up Python-2.7.5/Lib/test/test_hmac.py.cod Python-2.7.5/Lib/test/test_hmac.py |
||||
--- Python-2.7.5/Lib/test/test_hmac.py.cod 2015-02-23 10:37:13.448594606 +0100 |
||||
+++ Python-2.7.5/Lib/test/test_hmac.py 2015-02-23 10:37:27.581717509 +0100 |
||||
@@ -1,3 +1,5 @@ |
||||
+# coding: utf-8 |
||||
+ |
||||
import hmac |
||||
import hashlib |
||||
import unittest |
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Serhiy Storchaka <storchaka@gmail.com> |
||||
# Date 1382204269 -10800 |
||||
# Node ID 214c0aac7540947d88a38ff0061734547ef86710 |
||||
# Parent c207ac413457a1b834e4b7dcf1a6836cd6e036e3 |
||||
Issue #19279: UTF-7 decoder no more produces illegal unicode strings. |
||||
|
||||
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py |
||||
--- a/Lib/test/test_codecs.py |
||||
+++ b/Lib/test/test_codecs.py |
||||
@@ -611,6 +611,35 @@ class UTF7Test(ReadTest): |
||||
] |
||||
) |
||||
|
||||
+ def test_errors(self): |
||||
+ tests = [ |
||||
+ ('a\xffb', u'a\ufffdb'), |
||||
+ ('a+IK', u'a\ufffd'), |
||||
+ ('a+IK-b', u'a\ufffdb'), |
||||
+ ('a+IK,b', u'a\ufffdb'), |
||||
+ ('a+IKx', u'a\u20ac\ufffd'), |
||||
+ ('a+IKx-b', u'a\u20ac\ufffdb'), |
||||
+ ('a+IKwgr', u'a\u20ac\ufffd'), |
||||
+ ('a+IKwgr-b', u'a\u20ac\ufffdb'), |
||||
+ ('a+IKwgr,', u'a\u20ac\ufffd'), |
||||
+ ('a+IKwgr,-b', u'a\u20ac\ufffd-b'), |
||||
+ ('a+IKwgrB', u'a\u20ac\u20ac\ufffd'), |
||||
+ ('a+IKwgrB-b', u'a\u20ac\u20ac\ufffdb'), |
||||
+ ('a+/,+IKw-b', u'a\ufffd\u20acb'), |
||||
+ ('a+//,+IKw-b', u'a\ufffd\u20acb'), |
||||
+ ('a+///,+IKw-b', u'a\uffff\ufffd\u20acb'), |
||||
+ ('a+////,+IKw-b', u'a\uffff\ufffd\u20acb'), |
||||
+ ] |
||||
+ for raw, expected in tests: |
||||
+ self.assertRaises(UnicodeDecodeError, codecs.utf_7_decode, |
||||
+ raw, 'strict', True) |
||||
+ self.assertEqual(raw.decode('utf-7', 'replace'), expected) |
||||
+ |
||||
+ def test_nonbmp(self): |
||||
+ self.assertEqual(u'\U000104A0'.encode(self.encoding), '+2AHcoA-') |
||||
+ self.assertEqual(u'\ud801\udca0'.encode(self.encoding), '+2AHcoA-') |
||||
+ self.assertEqual('+2AHcoA-'.decode(self.encoding), u'\U000104A0') |
||||
+ |
||||
class UTF16ExTest(unittest.TestCase): |
||||
|
||||
def test_errors(self): |
||||
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c |
||||
--- a/Objects/unicodeobject.c |
||||
+++ b/Objects/unicodeobject.c |
||||
@@ -1671,6 +1671,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c |
||||
(base64buffer >> (base64bits-16)); |
||||
base64bits -= 16; |
||||
base64buffer &= (1 << base64bits) - 1; /* clear high bits */ |
||||
+ assert(outCh <= 0xffff); |
||||
if (surrogate) { |
||||
/* expecting a second surrogate */ |
||||
if (outCh >= 0xDC00 && outCh <= 0xDFFF) { |
||||
@@ -1737,6 +1738,7 @@ PyObject *PyUnicode_DecodeUTF7Stateful(c |
||||
inShift = 1; |
||||
shiftOutStart = p; |
||||
base64bits = 0; |
||||
+ base64buffer = 0; |
||||
} |
||||
} |
||||
else if (DECODE_DIRECT(ch)) { /* character decodes as itself */ |
||||
|
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Serhiy Storchaka <storchaka@gmail.com> |
||||
# Date 1372008129 -10800 |
||||
# Node ID 2f1e8b7fa534b147280fdc9b92e44a7c7305338a |
||||
# Parent 8f0adcb66633ee97e4f7bdeee2104268113b86c3 |
||||
Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise |
||||
OverflowError when an argument of %c format is out of range. |
||||
|
||||
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c |
||||
--- a/Objects/unicodeobject.c |
||||
+++ b/Objects/unicodeobject.c |
||||
@@ -740,8 +740,25 @@ PyUnicode_FromFormatV(const char *format |
||||
|
||||
switch (*f) { |
||||
case 'c': |
||||
- (void)va_arg(count, int); |
||||
+ { |
||||
+ int ordinal = va_arg(count, int); |
||||
+#ifdef Py_UNICODE_WIDE |
||||
+ if (ordinal < 0 || ordinal > 0x10ffff) { |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "%c arg not in range(0x110000) " |
||||
+ "(wide Python build)"); |
||||
+ goto fail; |
||||
+ } |
||||
+#else |
||||
+ if (ordinal < 0 || ordinal > 0xffff) { |
||||
+ PyErr_SetString(PyExc_OverflowError, |
||||
+ "%c arg not in range(0x10000) " |
||||
+ "(narrow Python build)"); |
||||
+ goto fail; |
||||
+ } |
||||
+#endif |
||||
/* fall through... */ |
||||
+ } |
||||
case '%': |
||||
n++; |
||||
break; |
||||
|
@ -0,0 +1,176 @@
@@ -0,0 +1,176 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Victor Stinner <victor.stinner@gmail.com> |
||||
# Date 1406673545 -7200 |
||||
# Node ID 263701e0b77e3160bc6a835087f838bd6b24092a |
||||
# Parent 6c47c6d2033e20e9b35f1d22e0e797961d6e680f |
||||
Issue #22023: Fix %S, %R and %V formats of PyUnicode_FromFormat(). |
||||
|
||||
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c |
||||
--- a/Objects/unicodeobject.c |
||||
+++ b/Objects/unicodeobject.c |
||||
@@ -690,7 +690,12 @@ makefmt(char *fmt, int longflag, int siz |
||||
*fmt = '\0'; |
||||
} |
||||
|
||||
-#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;} |
||||
+#define appendstring(string) \ |
||||
+ do { \ |
||||
+ for (copy = string;*copy; copy++) { \ |
||||
+ *s++ = (unsigned char)*copy; \ |
||||
+ } \ |
||||
+ } while (0) |
||||
|
||||
PyObject * |
||||
PyUnicode_FromFormatV(const char *format, va_list vargs) |
||||
@@ -845,7 +850,7 @@ PyUnicode_FromFormatV(const char *format |
||||
str = PyObject_Str(obj); |
||||
if (!str) |
||||
goto fail; |
||||
- n += PyUnicode_GET_SIZE(str); |
||||
+ n += PyString_GET_SIZE(str); |
||||
/* Remember the str and switch to the next slot */ |
||||
*callresult++ = str; |
||||
break; |
||||
@@ -1006,15 +1011,10 @@ PyUnicode_FromFormatV(const char *format |
||||
case 'S': |
||||
case 'R': |
||||
{ |
||||
- Py_UNICODE *ucopy; |
||||
- Py_ssize_t usize; |
||||
- Py_ssize_t upos; |
||||
+ const char *str = PyString_AS_STRING(*callresult); |
||||
/* unused, since we already have the result */ |
||||
(void) va_arg(vargs, PyObject *); |
||||
- ucopy = PyUnicode_AS_UNICODE(*callresult); |
||||
- usize = PyUnicode_GET_SIZE(*callresult); |
||||
- for (upos = 0; upos<usize;) |
||||
- *s++ = ucopy[upos++]; |
||||
+ appendstring(str); |
||||
/* We're done with the unicode()/repr() => forget it */ |
||||
Py_DECREF(*callresult); |
||||
/* switch to next unicode()/repr() result */ |
||||
|
||||
diff -up Python-2.7.5/Lib/test/test_unicode.py.uni Python-2.7.5/Lib/test/test_unicode.py |
||||
--- Python-2.7.5/Lib/test/test_unicode.py.uni 2015-02-24 13:37:01.704739438 +0100 |
||||
+++ Python-2.7.5/Lib/test/test_unicode.py 2015-02-24 13:38:38.439482167 +0100 |
||||
@@ -1633,6 +1633,119 @@ class UnicodeTest( |
||||
self.assertEqual("%s" % u, u'__unicode__ overridden') |
||||
self.assertEqual("{}".format(u), '__unicode__ overridden') |
||||
|
||||
+ # Test PyUnicode_FromFormat() |
||||
+ def test_from_format(self): |
||||
+ test_support.import_module('ctypes') |
||||
+ from ctypes import ( |
||||
+ pythonapi, py_object, sizeof, |
||||
+ c_int, c_long, c_longlong, c_ssize_t, |
||||
+ c_uint, c_ulong, c_ulonglong, c_size_t, c_void_p) |
||||
+ if sys.maxunicode == 0xffff: |
||||
+ name = "PyUnicodeUCS2_FromFormat" |
||||
+ else: |
||||
+ name = "PyUnicodeUCS4_FromFormat" |
||||
+ _PyUnicode_FromFormat = getattr(pythonapi, name) |
||||
+ _PyUnicode_FromFormat.restype = py_object |
||||
+ |
||||
+ def PyUnicode_FromFormat(format, *args): |
||||
+ cargs = tuple( |
||||
+ py_object(arg) if isinstance(arg, unicode) else arg |
||||
+ for arg in args) |
||||
+ return _PyUnicode_FromFormat(format, *cargs) |
||||
+ |
||||
+ def check_format(expected, format, *args): |
||||
+ text = PyUnicode_FromFormat(format, *args) |
||||
+ self.assertEqual(expected, text) |
||||
+ |
||||
+ # ascii format, non-ascii argument |
||||
+ check_format(u'ascii\x7f=unicode\xe9', |
||||
+ b'ascii\x7f=%U', u'unicode\xe9') |
||||
+ |
||||
+ # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV() |
||||
+ # raises an error |
||||
+ #self.assertRaisesRegex(ValueError, |
||||
+ # '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format ' |
||||
+ # 'string, got a non-ASCII byte: 0xe9$', |
||||
+ # PyUnicode_FromFormat, b'unicode\xe9=%s', u'ascii') |
||||
+ |
||||
+ # test "%c" |
||||
+ check_format(u'\uabcd', |
||||
+ b'%c', c_int(0xabcd)) |
||||
+ if sys.maxunicode > 0xffff: |
||||
+ check_format(u'\U0010ffff', |
||||
+ b'%c', c_int(0x10ffff)) |
||||
+ with self.assertRaises(OverflowError): |
||||
+ PyUnicode_FromFormat(b'%c', c_int(0x110000)) |
||||
+ # Issue #18183 |
||||
+ if sys.maxunicode > 0xffff: |
||||
+ check_format(u'\U00010000\U00100000', |
||||
+ b'%c%c', c_int(0x10000), c_int(0x100000)) |
||||
+ |
||||
+ # test "%" |
||||
+ check_format(u'%', |
||||
+ b'%') |
||||
+ check_format(u'%', |
||||
+ b'%%') |
||||
+ check_format(u'%s', |
||||
+ b'%%s') |
||||
+ check_format(u'[%]', |
||||
+ b'[%%]') |
||||
+ check_format(u'%abc', |
||||
+ b'%%%s', b'abc') |
||||
+ |
||||
+ # test %S |
||||
+ check_format(u"repr=abc", |
||||
+ b'repr=%S', u'abc') |
||||
+ |
||||
+ # test %R |
||||
+ check_format(u"repr=u'abc'", |
||||
+ b'repr=%R', u'abc') |
||||
+ |
||||
+ # test integer formats (%i, %d, %u) |
||||
+ check_format(u'010', |
||||
+ b'%03i', c_int(10)) |
||||
+ check_format(u'0010', |
||||
+ b'%0.4i', c_int(10)) |
||||
+ check_format(u'-123', |
||||
+ b'%i', c_int(-123)) |
||||
+ |
||||
+ check_format(u'-123', |
||||
+ b'%d', c_int(-123)) |
||||
+ check_format(u'-123', |
||||
+ b'%ld', c_long(-123)) |
||||
+ check_format(u'-123', |
||||
+ b'%zd', c_ssize_t(-123)) |
||||
+ |
||||
+ check_format(u'123', |
||||
+ b'%u', c_uint(123)) |
||||
+ check_format(u'123', |
||||
+ b'%lu', c_ulong(123)) |
||||
+ check_format(u'123', |
||||
+ b'%zu', c_size_t(123)) |
||||
+ |
||||
+ # test long output |
||||
+ PyUnicode_FromFormat(b'%p', c_void_p(-1)) |
||||
+ |
||||
+ # test %V |
||||
+ check_format(u'repr=abc', |
||||
+ b'repr=%V', u'abc', b'xyz') |
||||
+ check_format(u'repr=\xe4\xba\xba\xe6\xb0\x91', |
||||
+ b'repr=%V', None, b'\xe4\xba\xba\xe6\xb0\x91') |
||||
+ check_format(u'repr=abc\xff', |
||||
+ b'repr=%V', None, b'abc\xff') |
||||
+ |
||||
+ # not supported: copy the raw format string. these tests are just here |
||||
+ # to check for crashs and should not be considered as specifications |
||||
+ check_format(u'%s', |
||||
+ b'%1%s', b'abc') |
||||
+ check_format(u'%1abc', |
||||
+ b'%1abc') |
||||
+ check_format(u'%+i', |
||||
+ b'%+i', c_int(10)) |
||||
+ check_format(u'%s', |
||||
+ b'%.%s', b'abc') |
||||
+ |
||||
+ |
||||
def test_encode_decimal(self): |
||||
from _testcapi import unicode_encodedecimal |
||||
self.assertEqual(unicode_encodedecimal(u'123'), |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
diff -up Python-2.7.5/Lib/test/test_ssl.py.ssl2 Python-2.7.5/Lib/test/test_ssl.py |
||||
--- Python-2.7.5/Lib/test/test_ssl.py.ssl2 2015-03-04 12:19:26.345387741 +0100 |
||||
+++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-04 12:32:43.485702679 +0100 |
||||
@@ -689,7 +689,8 @@ class ContextTests(unittest.TestCase): |
||||
@skip_if_broken_ubuntu_ssl |
||||
def test_options(self): |
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
- # OP_ALL | OP_NO_SSLv2 is the default value |
||||
+ self.assertEqual(ssl.OP_ALL, ctx.options) |
||||
+ ctx.options |= ssl.OP_NO_SSLv2 |
||||
self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, |
||||
ctx.options) |
||||
ctx.options |= ssl.OP_NO_SSLv3 |
||||
@@ -2142,9 +2143,9 @@ else: |
||||
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_SSLv2) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, |
||||
client_options=ssl.OP_NO_SSLv3) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, |
||||
client_options=ssl.OP_NO_TLSv1) |
||||
|
||||
@skip_if_broken_ubuntu_ssl |
||||
|
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1409232801 14400 |
||||
# Node ID 97081a80f487841d81aeed55d398a1dba1faca00 |
||||
# Parent 3ae399c6ecf685086ebf07e17717955f21e14cb8 |
||||
fix load_verify_locations on unicode paths (closes #22244) |
||||
|
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -850,11 +850,14 @@ class ContextTests(unittest.TestCase): |
||||
ctx.load_verify_locations(cafile=CERTFILE, capath=None) |
||||
ctx.load_verify_locations(BYTES_CERTFILE) |
||||
ctx.load_verify_locations(cafile=BYTES_CERTFILE, capath=None) |
||||
+ ctx.load_verify_locations(cafile=BYTES_CERTFILE.decode('utf-8')) |
||||
self.assertRaises(TypeError, ctx.load_verify_locations) |
||||
self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None) |
||||
with self.assertRaises(IOError) as cm: |
||||
ctx.load_verify_locations(WRONGCERT) |
||||
self.assertEqual(cm.exception.errno, errno.ENOENT) |
||||
+ with self.assertRaises(IOError): |
||||
+ ctx.load_verify_locations(u'') |
||||
with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): |
||||
ctx.load_verify_locations(BADCERT) |
||||
ctx.load_verify_locations(CERTFILE, CAPATH) |
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -2628,17 +2628,33 @@ load_verify_locations(PySSLContext *self |
||||
} |
||||
|
||||
if (cafile) { |
||||
- cafile_bytes = PyString_AsEncodedObject( |
||||
- cafile, Py_FileSystemDefaultEncoding, "strict"); |
||||
- if (!cafile_bytes) { |
||||
- goto error; |
||||
+ if (PyString_Check(cafile)) { |
||||
+ Py_INCREF(cafile); |
||||
+ cafile_bytes = cafile; |
||||
+ } else { |
||||
+ PyObject *u = PyUnicode_FromObject(cafile); |
||||
+ if (!u) |
||||
+ goto error; |
||||
+ cafile_bytes = PyUnicode_AsEncodedString( |
||||
+ u, Py_FileSystemDefaultEncoding, NULL); |
||||
+ Py_DECREF(u); |
||||
+ if (!cafile_bytes) |
||||
+ goto error; |
||||
} |
||||
} |
||||
if (capath) { |
||||
- capath_bytes = PyString_AsEncodedObject( |
||||
- capath, Py_FileSystemDefaultEncoding, "strict"); |
||||
- if (!capath_bytes) { |
||||
- goto error; |
||||
+ if (PyString_Check(capath)) { |
||||
+ Py_INCREF(capath); |
||||
+ capath_bytes = capath; |
||||
+ } else { |
||||
+ PyObject *u = PyUnicode_FromObject(capath); |
||||
+ if (!u) |
||||
+ goto error; |
||||
+ capath_bytes = PyUnicode_AsEncodedString( |
||||
+ u, Py_FileSystemDefaultEncoding, NULL); |
||||
+ Py_DECREF(u); |
||||
+ if (!capath_bytes) |
||||
+ goto error; |
||||
} |
||||
} |
||||
|
||||
|
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1409233289 14400 |
||||
# Node ID 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 |
||||
# Parent 97081a80f487841d81aeed55d398a1dba1faca00 |
||||
PEP 466: backport hashlib algorithm constants (closes #21307) |
||||
|
||||
diff --git a/Doc/library/hashlib.rst b/Doc/library/hashlib.rst |
||||
--- a/Doc/library/hashlib.rst |
||||
+++ b/Doc/library/hashlib.rst |
||||
@@ -88,6 +88,24 @@ This module provides the following const |
||||
|
||||
.. versionadded:: 2.7 |
||||
|
||||
+.. data:: algorithms_guaranteed |
||||
+ |
||||
+ A set containing the names of the hash algorithms guaranteed to be supported |
||||
+ by this module on all platforms. |
||||
+ |
||||
+ .. versionadded:: 2.7.9 |
||||
+ |
||||
+.. data:: algorithms_available |
||||
+ |
||||
+ A set containing the names of the hash algorithms that are available in the |
||||
+ running Python interpreter. These names will be recognized when passed to |
||||
+ :func:`new`. :attr:`algorithms_guaranteed` will always be a subset. The |
||||
+ same algorithm may appear multiple times in this set under different names |
||||
+ (thanks to OpenSSL). |
||||
+ |
||||
+ .. versionadded:: 2.7.9 |
||||
+ |
||||
+ |
||||
The following values are provided as constant attributes of the hash objects |
||||
returned by the constructors: |
||||
|
||||
diff -up Python-2.7.5/Lib/hashlib.py.hash Python-2.7.5/Lib/hashlib.py |
||||
--- Python-2.7.5/Lib/hashlib.py.hash 2015-03-04 17:05:57.496598686 +0100 |
||||
+++ Python-2.7.5/Lib/hashlib.py 2015-03-04 17:11:34.872739103 +0100 |
||||
@@ -18,8 +18,9 @@ than using new(): |
||||
|
||||
md5(), sha1(), sha224(), sha256(), sha384(), and sha512() |
||||
|
||||
-More algorithms may be available on your platform but the above are |
||||
-guaranteed to exist. |
||||
+More algorithms may be available on your platform but the above are guaranteed |
||||
+to exist. See the algorithms_guaranteed and algorithms_available attributes |
||||
+to find out what algorithm names can be passed to new(). |
||||
|
||||
NOTE: If you want the adler32 or crc32 hash functions they are available in |
||||
the zlib module. |
||||
@@ -75,9 +76,14 @@ More condensed: |
||||
# always available algorithm is added. |
||||
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') |
||||
|
||||
+algorithms_guaranteed = set(__always_supported) |
||||
+algorithms_available = set(__always_supported) |
||||
+ |
||||
algorithms = __always_supported |
||||
|
||||
-__all__ = __always_supported + ('new', 'algorithms', 'pbkdf2_hmac') |
||||
+__all__ = __always_supported + ('new', 'algorithms_guaranteed', |
||||
+ 'algorithms_available', 'algorithms', |
||||
+ 'pbkdf2_hmac') |
||||
|
||||
|
||||
def __get_openssl_constructor(name): |
||||
@@ -110,6 +116,8 @@ try: |
||||
import _hashlib |
||||
new = __hash_new |
||||
__get_hash = __get_openssl_constructor |
||||
+ algorithms_available = algorithms_available.union( |
||||
+ _hashlib.openssl_md_meth_names) |
||||
except ImportError: |
||||
# We don't build the legacy modules |
||||
raise |
||||
diff -up Python-2.7.5/Modules/_hashopenssl.c.hash Python-2.7.5/Modules/_hashopenssl.c |
||||
--- Python-2.7.5/Modules/_hashopenssl.c.hash 2015-03-04 17:06:18.246791837 +0100 |
||||
+++ Python-2.7.5/Modules/_hashopenssl.c 2015-03-04 17:16:17.696369000 +0100 |
||||
@@ -784,6 +784,61 @@ pbkdf2_hmac(PyObject *self, PyObject *ar |
||||
|
||||
#endif |
||||
|
||||
+/* State for our callback function so that it can accumulate a result. */ |
||||
+typedef struct _internal_name_mapper_state { |
||||
+ PyObject *set; |
||||
+ int error; |
||||
+} _InternalNameMapperState; |
||||
+ |
||||
+ |
||||
+/* A callback function to pass to OpenSSL's OBJ_NAME_do_all(...) */ |
||||
+static void |
||||
+_openssl_hash_name_mapper(const OBJ_NAME *openssl_obj_name, void *arg) |
||||
+{ |
||||
+ _InternalNameMapperState *state = (_InternalNameMapperState *)arg; |
||||
+ PyObject *py_name; |
||||
+ |
||||
+ assert(state != NULL); |
||||
+ if (openssl_obj_name == NULL) |
||||
+ return; |
||||
+ /* Ignore aliased names, they pollute the list and OpenSSL appears to |
||||
+ * have a its own definition of alias as the resulting list still |
||||
+ * contains duplicate and alternate names for several algorithms. */ |
||||
+ if (openssl_obj_name->alias) |
||||
+ return; |
||||
+ |
||||
+ py_name = PyString_FromString(openssl_obj_name->name); |
||||
+ if (py_name == NULL) { |
||||
+ state->error = 1; |
||||
+ } else { |
||||
+ if (PySet_Add(state->set, py_name) != 0) { |
||||
+ state->error = 1; |
||||
+ } |
||||
+ Py_DECREF(py_name); |
||||
+ } |
||||
+} |
||||
+ |
||||
+ |
||||
+/* Ask OpenSSL for a list of supported ciphers, filling in a Python set. */ |
||||
+static PyObject* |
||||
+generate_hash_name_list(void) |
||||
+{ |
||||
+ _InternalNameMapperState state; |
||||
+ state.set = PyFrozenSet_New(NULL); |
||||
+ if (state.set == NULL) |
||||
+ return NULL; |
||||
+ state.error = 0; |
||||
+ |
||||
+ OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, &_openssl_hash_name_mapper, &state); |
||||
+ |
||||
+ if (state.error) { |
||||
+ Py_DECREF(state.set); |
||||
+ return NULL; |
||||
+ } |
||||
+ return state.set; |
||||
+} |
||||
+ |
||||
+ |
||||
/* |
||||
* This macro and function generates a family of constructor function |
||||
* definitions for specific hash algorithms. These constructors are much |
||||
@@ -924,11 +979,11 @@ static struct PyMethodDef EVP_functions[ |
||||
PyMODINIT_FUNC |
||||
init_hashlib(void) |
||||
{ |
||||
- PyObject *m; |
||||
+ PyObject *m, *openssl_md_meth_names; |
||||
|
||||
SSL_load_error_strings(); |
||||
SSL_library_init(); |
||||
- OpenSSL_add_all_digests(); |
||||
+ ERR_load_crypto_strings(); |
||||
|
||||
Py_TYPE(&EVPtype) = &PyType_Type; |
||||
if (PyType_Ready(&EVPtype) < 0) |
||||
@@ -938,6 +993,14 @@ init_hashlib(void) |
||||
if (m == NULL) |
||||
return; |
||||
|
||||
+ openssl_md_meth_names = generate_hash_name_list(); |
||||
+ if (openssl_md_meth_names == NULL) { |
||||
+ return; |
||||
+ } |
||||
+ if (PyModule_AddObject(m, "openssl_md_meth_names", openssl_md_meth_names)) { |
||||
+ return; |
||||
+ } |
||||
+ |
||||
#if HASH_OBJ_CONSTRUCTOR |
||||
Py_INCREF(&EVPtype); |
||||
PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); |
||||
diff -up Python-2.7.5/Lib/test/test_hashlib.py.hash Python-2.7.5/Lib/test/test_hashlib.py |
||||
--- Python-2.7.5/Lib/test/test_hashlib.py.hash 2015-03-04 18:04:57.823553474 +0100 |
||||
+++ Python-2.7.5/Lib/test/test_hashlib.py 2015-03-04 18:06:39.395499123 +0100 |
||||
@@ -107,6 +107,15 @@ class HashLibTestCase(unittest.TestCase) |
||||
tuple([_algo for _algo in self.supported_hash_names if |
||||
_algo.islower()])) |
||||
|
||||
+ def test_algorithms_guaranteed(self): |
||||
+ self.assertEqual(hashlib.algorithms_guaranteed, |
||||
+ set(_algo for _algo in self.supported_hash_names |
||||
+ if _algo.islower())) |
||||
+ |
||||
+ def test_algorithms_available(self): |
||||
+ self.assertTrue(set(hashlib.algorithms_guaranteed). |
||||
+ issubset(hashlib.algorithms_available)) |
||||
+ |
||||
def test_unknown_hash(self): |
||||
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') |
||||
self.assertRaises(TypeError, hashlib.new, 1) |
@ -0,0 +1,165 @@
@@ -0,0 +1,165 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1409243400 14400 |
||||
# Node ID 3e7f8855078855a9409bc2c1372de89cb021d6c8 |
||||
# Parent 3f73c44b1fd1d442d6841493328e9756fb5e7ef5 |
||||
PEP 466: backport persistent urandom fd (closes #21305) |
||||
|
||||
Patch from Alex Gaynor. |
||||
|
||||
diff --git a/Python/pythonrun.c b/Python/pythonrun.c |
||||
--- a/Python/pythonrun.c |
||||
+++ b/Python/pythonrun.c |
||||
@@ -536,6 +536,7 @@ Py_Finalize(void) |
||||
PyInt_Fini(); |
||||
PyFloat_Fini(); |
||||
PyDict_Fini(); |
||||
+ _PyRandom_Fini(); |
||||
|
||||
#ifdef Py_USING_UNICODE |
||||
/* Cleanup Unicode implementation */ |
||||
diff -up Python-2.7.5/Include/pythonrun.h.urandom Python-2.7.5/Include/pythonrun.h |
||||
--- Python-2.7.5/Include/pythonrun.h.urandom 2015-03-06 08:16:47.638584015 +0100 |
||||
+++ Python-2.7.5/Include/pythonrun.h 2015-03-06 08:21:48.009485462 +0100 |
||||
@@ -145,6 +145,7 @@ PyAPI_FUNC(void) PyInt_Fini(void); |
||||
PyAPI_FUNC(void) PyFloat_Fini(void); |
||||
PyAPI_FUNC(void) PyOS_FiniInterrupts(void); |
||||
PyAPI_FUNC(void) PyByteArray_Fini(void); |
||||
+PyAPI_FUNC(void) _PyRandom_Fini(void); |
||||
|
||||
/* Stuff with no proper home (yet) */ |
||||
PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *); |
||||
diff -up Python-2.7.5/Python/random.c.urandom Python-2.7.5/Python/random.c |
||||
--- Python-2.7.5/Python/random.c.urandom 2015-03-06 08:22:10.244699950 +0100 |
||||
+++ Python-2.7.5/Python/random.c 2015-03-06 08:24:57.907317272 +0100 |
||||
@@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ss |
||||
|
||||
#if !defined(MS_WINDOWS) && !defined(__VMS) |
||||
|
||||
+static struct { |
||||
+ int fd; |
||||
+ dev_t st_dev; |
||||
+ ino_t st_ino; |
||||
+} urandom_cache = { -1 }; |
||||
+ |
||||
/* Read size bytes from /dev/urandom into buffer. |
||||
Call Py_FatalError() on error. */ |
||||
static void |
||||
-dev_urandom_noraise(char *buffer, Py_ssize_t size) |
||||
+dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size) |
||||
{ |
||||
int fd; |
||||
Py_ssize_t n; |
||||
@@ -156,18 +162,56 @@ dev_urandom_python(char *buffer, Py_ssiz |
||||
{ |
||||
int fd; |
||||
Py_ssize_t n; |
||||
+ struct stat st; |
||||
|
||||
if (size <= 0) |
||||
return 0; |
||||
|
||||
- Py_BEGIN_ALLOW_THREADS |
||||
- fd = open("/dev/urandom", O_RDONLY); |
||||
- Py_END_ALLOW_THREADS |
||||
- if (fd < 0) |
||||
- { |
||||
- PyErr_SetString(PyExc_NotImplementedError, |
||||
- "/dev/urandom (or equivalent) not found"); |
||||
- return -1; |
||||
+ if (urandom_cache.fd >= 0) { |
||||
+ /* Does the fd point to the same thing as before? (issue #21207) */ |
||||
+ if (fstat(urandom_cache.fd, &st) |
||||
+ || st.st_dev != urandom_cache.st_dev |
||||
+ || st.st_ino != urandom_cache.st_ino) { |
||||
+ /* Something changed: forget the cached fd (but don't close it, |
||||
+ since it probably points to something important for some |
||||
+ third-party code). */ |
||||
+ urandom_cache.fd = -1; |
||||
+ } |
||||
+ } |
||||
+ if (urandom_cache.fd >= 0) |
||||
+ fd = urandom_cache.fd; |
||||
+ else { |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ fd = open("/dev/urandom", O_RDONLY); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ if (fd < 0) |
||||
+ { |
||||
+ if (errno == ENOENT || errno == ENXIO || |
||||
+ errno == ENODEV || errno == EACCES) |
||||
+ PyErr_SetString(PyExc_NotImplementedError, |
||||
+ "/dev/urandom (or equivalent) not found"); |
||||
+ else |
||||
+ PyErr_SetFromErrno(PyExc_OSError); |
||||
+ return -1; |
||||
+ } |
||||
+ if (urandom_cache.fd >= 0) { |
||||
+ /* urandom_fd was initialized by another thread while we were |
||||
+ not holding the GIL, keep it. */ |
||||
+ close(fd); |
||||
+ fd = urandom_cache.fd; |
||||
+ } |
||||
+ else { |
||||
+ if (fstat(fd, &st)) { |
||||
+ PyErr_SetFromErrno(PyExc_OSError); |
||||
+ close(fd); |
||||
+ return -1; |
||||
+ } |
||||
+ else { |
||||
+ urandom_cache.fd = fd; |
||||
+ urandom_cache.st_dev = st.st_dev; |
||||
+ urandom_cache.st_ino = st.st_ino; |
||||
+ } |
||||
+ } |
||||
} |
||||
|
||||
Py_BEGIN_ALLOW_THREADS |
||||
@@ -191,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssiz |
||||
PyErr_Format(PyExc_RuntimeError, |
||||
"Failed to read %zi bytes from /dev/urandom", |
||||
size); |
||||
- close(fd); |
||||
return -1; |
||||
} |
||||
- close(fd); |
||||
return 0; |
||||
} |
||||
+ |
||||
+static void |
||||
+dev_urandom_close(void) |
||||
+{ |
||||
+ if (urandom_cache.fd >= 0) { |
||||
+ close(urandom_cache.fd); |
||||
+ urandom_cache.fd = -1; |
||||
+ } |
||||
+} |
||||
+ |
||||
+ |
||||
#endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ |
||||
|
||||
/* Fill buffer with pseudo-random bytes generated by a linear congruent |
||||
@@ -300,8 +353,21 @@ _PyRandom_Init(void) |
||||
# ifdef __VMS |
||||
vms_urandom((unsigned char *)secret, secret_size, 0); |
||||
# else |
||||
- dev_urandom_noraise((char*)secret, secret_size); |
||||
+ dev_urandom_noraise((unsigned char*)secret, secret_size); |
||||
# endif |
||||
#endif |
||||
} |
||||
} |
||||
+ |
||||
+void |
||||
+_PyRandom_Fini(void) |
||||
+{ |
||||
+#ifdef MS_WINDOWS |
||||
+ if (hCryptProv) { |
||||
+ CryptReleaseContext(hCryptProv, 0); |
||||
+ hCryptProv = 0; |
||||
+ } |
||||
+#else |
||||
+ dev_urandom_close(); |
||||
+#endif |
||||
+} |
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1412221981 14400 |
||||
# Node ID 1a36d4e8cf4edfdc4c7d59a40075b8cf00e3ad3c |
||||
# Parent 222e0faa5fa9567f657f13fc78a60069142e09ae |
||||
fix sslwrap_simple (closes #22523) |
||||
|
||||
Thanks Alex Gaynor. |
||||
|
||||
diff --git a/Lib/ssl.py b/Lib/ssl.py |
||||
--- a/Lib/ssl.py |
||||
+++ b/Lib/ssl.py |
||||
@@ -969,16 +969,16 @@ def get_protocol_name(protocol_code): |
||||
# a replacement for the old socket.ssl function |
||||
|
||||
def sslwrap_simple(sock, keyfile=None, certfile=None): |
||||
- |
||||
"""A replacement for the old socket.ssl function. Designed |
||||
for compability with Python 2.5 and earlier. Will disappear in |
||||
Python 3.0.""" |
||||
- |
||||
if hasattr(sock, "_sock"): |
||||
sock = sock._sock |
||||
|
||||
- ssl_sock = _ssl.sslwrap(sock, 0, keyfile, certfile, CERT_NONE, |
||||
- PROTOCOL_SSLv23, None) |
||||
+ ctx = SSLContext(PROTOCOL_SSLv23) |
||||
+ if keyfile or certfile: |
||||
+ ctx.load_cert_chain(certfile, keyfile) |
||||
+ ssl_sock = ctx._wrap_socket(sock, server_side=False) |
||||
try: |
||||
sock.getpeername() |
||||
except socket_error: |
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -94,6 +94,8 @@ class BasicTests(unittest.TestCase): |
||||
pass |
||||
else: |
||||
raise |
||||
+ |
||||
+ |
||||
def can_clear_options(): |
||||
# 0.9.8m or higher |
||||
return ssl._OPENSSL_API_VERSION >= (0, 9, 8, 13, 15) |
||||
@@ -2944,7 +2946,7 @@ def test_main(verbose=False): |
||||
if not os.path.exists(filename): |
||||
raise support.TestFailed("Can't read certificate file %r" % filename) |
||||
|
||||
- tests = [ContextTests, BasicSocketTests, SSLErrorTests] |
||||
+ tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] |
||||
|
||||
if support.is_resource_enabled('network'): |
||||
tests.append(NetworkedTests) |
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -517,10 +517,12 @@ newPySSLSocket(PySSLContext *sslctx, PyS |
||||
self->socket_type = socket_type; |
||||
self->Socket = sock; |
||||
Py_INCREF(self->Socket); |
||||
- self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); |
||||
- if (self->ssl_sock == NULL) { |
||||
- Py_DECREF(self); |
||||
- return NULL; |
||||
+ if (ssl_sock != Py_None) { |
||||
+ self->ssl_sock = PyWeakref_NewRef(ssl_sock, NULL); |
||||
+ if (self->ssl_sock == NULL) { |
||||
+ Py_DECREF(self); |
||||
+ return NULL; |
||||
+ } |
||||
} |
||||
return self; |
||||
} |
||||
@@ -2931,8 +2933,12 @@ static int |
||||
|
||||
ssl = SSL_get_app_data(s); |
||||
assert(PySSLSocket_Check(ssl)); |
||||
- ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); |
||||
- Py_INCREF(ssl_socket); |
||||
+ if (ssl->ssl_sock == NULL) { |
||||
+ ssl_socket = Py_None; |
||||
+ } else { |
||||
+ ssl_socket = PyWeakref_GetObject(ssl->ssl_sock); |
||||
+ Py_INCREF(ssl_socket); |
||||
+ } |
||||
if (ssl_socket == Py_None) { |
||||
goto error; |
||||
} |
||||
|
@ -0,0 +1,673 @@
@@ -0,0 +1,673 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1416764565 21600 |
||||
# Node ID 1882157b298a164291d2b3a8b9525eb0902895f6 |
||||
# Parent 588ebc8fd3daf7307961cd614c4da9525bb67313 |
||||
allow passing cert/ssl information to urllib2.urlopen and httplib.HTTPSConnection |
||||
|
||||
This is basically a backport of issues #9003 and #22366. |
||||
|
||||
diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst |
||||
--- a/Doc/library/httplib.rst |
||||
+++ b/Doc/library/httplib.rst |
||||
@@ -70,12 +70,25 @@ The module provides the following classe |
||||
*source_address* was added. |
||||
|
||||
|
||||
-.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address]]]]]]) |
||||
+.. class:: HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout[, source_address, context, check_hostname]]]]]]) |
||||
|
||||
A subclass of :class:`HTTPConnection` that uses SSL for communication with |
||||
- secure servers. Default port is ``443``. *key_file* is the name of a PEM |
||||
- formatted file that contains your private key. *cert_file* is a PEM formatted |
||||
- certificate chain file. |
||||
+ secure servers. Default port is ``443``. If *context* is specified, it must |
||||
+ be a :class:`ssl.SSLContext` instance describing the various SSL options. |
||||
+ |
||||
+ *key_file* and *cert_file* are deprecated, please use |
||||
+ :meth:`ssl.SSLContext.load_cert_chain` instead, or let |
||||
+ :func:`ssl.create_default_context` select the system's trusted CA |
||||
+ certificates for you. |
||||
+ |
||||
+ Please read :ref:`ssl-security` for more information on best practices. |
||||
+ |
||||
+ .. note:: |
||||
+ If *context* is specified and has a :attr:`~ssl.SSLContext.verify_mode` |
||||
+ of either :data:`~ssl.CERT_OPTIONAL` or :data:`~ssl.CERT_REQUIRED`, then |
||||
+ by default *host* is matched against the host name(s) allowed by the |
||||
+ server's certificate. If you want to change that behaviour, you can |
||||
+ explicitly set *check_hostname* to False. |
||||
|
||||
.. warning:: |
||||
This does not do any verification of the server's certificate. |
||||
@@ -88,6 +101,9 @@ The module provides the following classe |
||||
.. versionchanged:: 2.7 |
||||
*source_address* was added. |
||||
|
||||
+ .. versionchanged:: 2.7.9 |
||||
+ *context* and *check_hostname* was added. |
||||
+ |
||||
|
||||
.. class:: HTTPResponse(sock, debuglevel=0, strict=0) |
||||
|
||||
diff --git a/Lib/test/keycert2.pem b/Lib/test/keycert2.pem |
||||
new file mode 100644 |
||||
--- /dev/null |
||||
+++ b/Lib/test/keycert2.pem |
||||
@@ -0,0 +1,31 @@ |
||||
+-----BEGIN PRIVATE KEY----- |
||||
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANcLaMB7T/Wi9DBc |
||||
+PltGzgt8cxsv55m7PQPHMZvn6Ke8xmNqcmEzib8opRwKGrCV6TltKeFlNSg8dwQK |
||||
+Tl4ktyTkGCVweRQJ37AkBayvEBml5s+QD4vlhqkJPsL/Nsd+fnqngOGc5+59+C6r |
||||
+s3XpiLlF5ah/z8q92Mnw54nypw1JAgMBAAECgYBE3t2Mj7GbDLZB6rj5yKJioVfI |
||||
+BD6bSJEQ7bGgqdQkLFwpKMU7BiN+ekjuwvmrRkesYZ7BFgXBPiQrwhU5J28Tpj5B |
||||
+EOMYSIOHfzdalhxDGM1q2oK9LDFiCotTaSdEzMYadel5rmKXJ0zcK2Jho0PCuECf |
||||
+tf/ghRxK+h1Hm0tKgQJBAO6MdGDSmGKYX6/5kPDje7we/lSLorSDkYmV0tmVShsc |
||||
+JxgaGaapazceA/sHL3Myx7Eenkip+yPYDXEDFvAKNDECQQDmxsT9NOp6mo7ISvky |
||||
+GFr2vVHsJ745BMWoma4rFjPBVnS8RkgK+b2EpDCdZSrQ9zw2r8sKTgrEyrDiGTEg |
||||
+wJyZAkA8OOc0flYMJg2aHnYR6kwVjPmGHI5h5gk648EMPx0rROs1sXkiUwkHLCOz |
||||
+HvhCq+Iv+9vX2lnVjbiu/CmxRdIxAkA1YEfzoKeTD+hyXxTgB04Sv5sRGegfXAEz |
||||
+i8gC4zG5R/vcCA1lrHmvEiLEZL/QcT6WD3bQvVg0SAU9ZkI8pxARAkA7yqMSvP1l |
||||
+gJXy44R+rzpLYb1/PtiLkIkaKG3x9TUfPnfD2jY09fPkZlfsRU3/uS09IkhSwimV |
||||
+d5rWoljEfdou |
||||
+-----END PRIVATE KEY----- |
||||
+-----BEGIN CERTIFICATE----- |
||||
+MIICXTCCAcagAwIBAgIJALVQzebTtrXFMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNV |
||||
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u |
||||
+IFNvZnR3YXJlIEZvdW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTAeFw0x |
||||
+NDExMjMxNzAwMDdaFw0yNDExMjAxNzAwMDdaMGIxCzAJBgNVBAYTAlhZMRcwFQYD |
||||
+VQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9uIFNvZnR3YXJlIEZv |
||||
+dW5kYXRpb24xFTATBgNVBAMMDGZha2Vob3N0bmFtZTCBnzANBgkqhkiG9w0BAQEF |
||||
+AAOBjQAwgYkCgYEA1wtowHtP9aL0MFw+W0bOC3xzGy/nmbs9A8cxm+fop7zGY2py |
||||
+YTOJvyilHAoasJXpOW0p4WU1KDx3BApOXiS3JOQYJXB5FAnfsCQFrK8QGaXmz5AP |
||||
+i+WGqQk+wv82x35+eqeA4Zzn7n34LquzdemIuUXlqH/Pyr3YyfDnifKnDUkCAwEA |
||||
+AaMbMBkwFwYDVR0RBBAwDoIMZmFrZWhvc3RuYW1lMA0GCSqGSIb3DQEBBQUAA4GB |
||||
+AKuay3vDKfWzt5+ch/HHBsert84ISot4fUjzXDA/oOgTOEjVcSShHxqNShMOW1oA |
||||
+QYBpBB/5Kx5RkD/w6imhucxt2WQPRgjX4x4bwMipVH/HvFDp03mG51/Cpi1TyZ74 |
||||
+El7qa/Pd4lHhOLzMKBA6503fpeYSFUIBxZbGLqylqRK7 |
||||
+-----END CERTIFICATE----- |
||||
diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem |
||||
new file mode 100644 |
||||
--- /dev/null |
||||
+++ b/Lib/test/selfsigned_pythontestdotnet.pem |
||||
@@ -0,0 +1,16 @@ |
||||
+-----BEGIN CERTIFICATE----- |
||||
+MIIChzCCAfCgAwIBAgIJAKGU95wKR8pSMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV |
||||
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u |
||||
+IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv |
||||
+bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG |
||||
+A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo |
||||
+b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 |
||||
+aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ |
||||
+Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm |
||||
+Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv |
||||
+EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjKTAnMCUGA1UdEQQeMByCGnNl |
||||
+bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MA0GCSqGSIb3DQEBBQUAA4GBAIOXmdtM |
||||
+eG9qzP9TiXW/Gc/zI4cBfdCpC+Y4gOfC9bQUC7hefix4iO3+iZjgy3X/FaRxUUoV |
||||
+HKiXcXIaWqTSUWp45cSh0MbwZXudp6JIAptzdAhvvCrPKeC9i9GvxsPD4LtDAL97 |
||||
+vSaxQBezA7hdxZd90/EeyMgVZgAnTCnvAWX9 |
||||
+-----END CERTIFICATE----- |
||||
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py |
||||
--- a/Lib/test/test_urllib2.py |
||||
+++ b/Lib/test/test_urllib2.py |
||||
@@ -8,6 +8,11 @@ import StringIO |
||||
import urllib2 |
||||
from urllib2 import Request, OpenerDirector |
||||
|
||||
+try: |
||||
+ import ssl |
||||
+except ImportError: |
||||
+ ssl = None |
||||
+ |
||||
# XXX |
||||
# Request |
||||
# CacheFTPHandler (hard to write) |
||||
@@ -47,6 +52,14 @@ class TrivialTests(unittest.TestCase): |
||||
for string, list in tests: |
||||
self.assertEqual(urllib2.parse_http_list(string), list) |
||||
|
||||
+ @unittest.skipUnless(ssl, "ssl module required") |
||||
+ def test_cafile_and_context(self): |
||||
+ context = ssl.create_default_context() |
||||
+ with self.assertRaises(ValueError): |
||||
+ urllib2.urlopen( |
||||
+ "https://localhost", cafile="/nonexistent/path", context=context |
||||
+ ) |
||||
+ |
||||
|
||||
def test_request_headers_dict(): |
||||
""" |
||||
diff --git a/Lib/urllib2.py b/Lib/urllib2.py |
||||
--- a/Lib/urllib2.py |
||||
+++ b/Lib/urllib2.py |
||||
@@ -109,6 +109,14 @@ try: |
||||
except ImportError: |
||||
from StringIO import StringIO |
||||
|
||||
+# check for SSL |
||||
+try: |
||||
+ import ssl |
||||
+except ImportError: |
||||
+ _have_ssl = False |
||||
+else: |
||||
+ _have_ssl = True |
||||
+ |
||||
from urllib import (unwrap, unquote, splittype, splithost, quote, |
||||
addinfourl, splitport, splittag, toBytes, |
||||
splitattr, ftpwrapper, splituser, splitpasswd, splitvalue) |
||||
@@ -120,11 +128,30 @@ from urllib import localhost, url2pathna |
||||
__version__ = sys.version[:3] |
||||
|
||||
_opener = None |
||||
-def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT): |
||||
+def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, |
||||
+ cafile=None, capath=None, cadefault=False, context=None): |
||||
global _opener |
||||
- if _opener is None: |
||||
- _opener = build_opener() |
||||
- return _opener.open(url, data, timeout) |
||||
+ if cafile or capath or cadefault: |
||||
+ if context is not None: |
||||
+ raise ValueError( |
||||
+ "You can't pass both context and any of cafile, capath, and " |
||||
+ "cadefault" |
||||
+ ) |
||||
+ if not _have_ssl: |
||||
+ raise ValueError('SSL support not available') |
||||
+ context = ssl._create_stdlib_context(cert_reqs=ssl.CERT_REQUIRED, |
||||
+ cafile=cafile, |
||||
+ capath=capath) |
||||
+ https_handler = HTTPSHandler(context=context, check_hostname=True) |
||||
+ opener = build_opener(https_handler) |
||||
+ elif context: |
||||
+ https_handler = HTTPSHandler(context=context) |
||||
+ opener = build_opener(https_handler) |
||||
+ elif _opener is None: |
||||
+ _opener = opener = build_opener() |
||||
+ else: |
||||
+ opener = _opener |
||||
+ return opener.open(url, data, timeout) |
||||
|
||||
def install_opener(opener): |
||||
global _opener |
||||
@@ -1121,7 +1148,7 @@ class AbstractHTTPHandler(BaseHandler): |
||||
|
||||
return request |
||||
|
||||
- def do_open(self, http_class, req): |
||||
+ def do_open(self, http_class, req, **http_conn_args): |
||||
"""Return an addinfourl object for the request, using http_class. |
||||
|
||||
http_class must implement the HTTPConnection API from httplib. |
||||
@@ -1135,7 +1162,8 @@ class AbstractHTTPHandler(BaseHandler): |
||||
if not host: |
||||
raise URLError('no host given') |
||||
|
||||
- h = http_class(host, timeout=req.timeout) # will parse host:port |
||||
+ # will parse host:port |
||||
+ h = http_class(host, timeout=req.timeout, **http_conn_args) |
||||
h.set_debuglevel(self._debuglevel) |
||||
|
||||
headers = dict(req.unredirected_hdrs) |
||||
@@ -1203,8 +1231,14 @@ class HTTPHandler(AbstractHTTPHandler): |
||||
if hasattr(httplib, 'HTTPS'): |
||||
class HTTPSHandler(AbstractHTTPHandler): |
||||
|
||||
+ def __init__(self, debuglevel=0, context=None, check_hostname=None): |
||||
+ AbstractHTTPHandler.__init__(self, debuglevel) |
||||
+ self._context = context |
||||
+ self._check_hostname = check_hostname |
||||
+ |
||||
def https_open(self, req): |
||||
- return self.do_open(httplib.HTTPSConnection, req) |
||||
+ return self.do_open(httplib.HTTPSConnection, req, |
||||
+ context=self._context, check_hostname=self._check_hostname) |
||||
|
||||
https_request = AbstractHTTPHandler.do_request_ |
||||
|
||||
diff -up Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx Python-2.7.5/Lib/test/test_urllib2_localnet.py |
||||
--- Python-2.7.5/Lib/test/test_urllib2_localnet.py.ctx 2015-03-30 10:13:48.351310552 +0200 |
||||
+++ Python-2.7.5/Lib/test/test_urllib2_localnet.py 2015-03-30 10:14:54.715713679 +0200 |
||||
@@ -1,5 +1,6 @@ |
||||
#!/usr/bin/env python |
||||
|
||||
+import os |
||||
import urlparse |
||||
import urllib2 |
||||
import BaseHTTPServer |
||||
@@ -11,6 +12,17 @@ from test import test_support |
||||
mimetools = test_support.import_module('mimetools', deprecated=True) |
||||
threading = test_support.import_module('threading') |
||||
|
||||
+try: |
||||
+ import ssl |
||||
+except ImportError: |
||||
+ ssl = None |
||||
+ |
||||
+here = os.path.dirname(__file__) |
||||
+# Self-signed cert file for 'localhost' |
||||
+CERT_localhost = os.path.join(here, 'keycert.pem') |
||||
+# Self-signed cert file for 'fakehostname' |
||||
+CERT_fakehostname = os.path.join(here, 'keycert2.pem') |
||||
+ |
||||
# Loopback http server infrastructure |
||||
|
||||
class LoopbackHttpServer(BaseHTTPServer.HTTPServer): |
||||
@@ -25,7 +37,7 @@ class LoopbackHttpServer(BaseHTTPServer. |
||||
|
||||
# Set the timeout of our listening socket really low so |
||||
# that we can stop the server easily. |
||||
- self.socket.settimeout(1.0) |
||||
+ self.socket.settimeout(0.1) |
||||
|
||||
def get_request(self): |
||||
"""BaseHTTPServer method, overridden.""" |
||||
@@ -354,6 +366,19 @@ class TestUrlopen(BaseTestCase): |
||||
urllib2.install_opener(opener) |
||||
super(TestUrlopen, self).setUp() |
||||
|
||||
+ def urlopen(self, url, data=None, **kwargs): |
||||
+ l = [] |
||||
+ f = urllib2.urlopen(url, data, **kwargs) |
||||
+ try: |
||||
+ # Exercise various methods |
||||
+ l.extend(f.readlines(200)) |
||||
+ l.append(f.readline()) |
||||
+ l.append(f.read(1024)) |
||||
+ l.append(f.read()) |
||||
+ finally: |
||||
+ f.close() |
||||
+ return b"".join(l) |
||||
+ |
||||
def start_server(self, responses): |
||||
handler = GetRequestHandler(responses) |
||||
|
||||
@@ -364,6 +389,16 @@ class TestUrlopen(BaseTestCase): |
||||
handler.port = port |
||||
return handler |
||||
|
||||
+ def start_https_server(self, responses=None, **kwargs): |
||||
+ if not hasattr(urllib2, 'HTTPSHandler'): |
||||
+ self.skipTest('ssl support required') |
||||
+ from test.ssl_servers import make_https_server |
||||
+ if responses is None: |
||||
+ responses = [(200, [], b"we care a bit")] |
||||
+ handler = GetRequestHandler(responses) |
||||
+ server = make_https_server(self, handler_class=handler, **kwargs) |
||||
+ handler.port = server.port |
||||
+ return handler |
||||
|
||||
def test_redirection(self): |
||||
expected_response = 'We got here...' |
||||
@@ -434,6 +469,28 @@ class TestUrlopen(BaseTestCase): |
||||
finally: |
||||
self.server.stop() |
||||
|
||||
+ def test_https(self): |
||||
+ handler = self.start_https_server() |
||||
+ context = ssl.create_default_context(cafile=CERT_localhost) |
||||
+ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, context=context) |
||||
+ self.assertEqual(data, b"we care a bit") |
||||
+ |
||||
+ def test_https_with_cafile(self): |
||||
+ handler = self.start_https_server(certfile=CERT_localhost) |
||||
+ import ssl |
||||
+ # Good cert |
||||
+ data = self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
+ cafile=CERT_localhost) |
||||
+ self.assertEqual(data, b"we care a bit") |
||||
+ # Bad cert |
||||
+ with self.assertRaises(urllib2.URLError) as cm: |
||||
+ self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
+ cafile=CERT_fakehostname) |
||||
+ # Good cert, but mismatching hostname |
||||
+ handler = self.start_https_server(certfile=CERT_fakehostname) |
||||
+ with self.assertRaises(ssl.CertificateError) as cm: |
||||
+ self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
+ cafile=CERT_fakehostname) |
||||
|
||||
def test_sending_headers(self): |
||||
handler = self.start_server([(200, [], "we don't care")]) |
||||
diff -up Python-2.7.5/Doc/library/urllib2.rst.ctx Python-2.7.5/Doc/library/urllib2.rst |
||||
--- Python-2.7.5/Doc/library/urllib2.rst.ctx 2015-03-30 10:20:15.958747076 +0200 |
||||
+++ Python-2.7.5/Doc/library/urllib2.rst 2015-03-30 10:30:46.172779366 +0200 |
||||
@@ -22,13 +22,10 @@ redirections, cookies and more. |
||||
The :mod:`urllib2` module defines the following functions: |
||||
|
||||
|
||||
-.. function:: urlopen(url[, data][, timeout]) |
||||
+.. function:: urlopen(url[, data[, timeout[, cafile[, capath[, cadefault[, context]]]]]) |
||||
|
||||
Open the URL *url*, which can be either a string or a :class:`Request` object. |
||||
|
||||
- .. warning:: |
||||
- HTTPS requests do not do any verification of the server's certificate. |
||||
- |
||||
*data* may be a string specifying additional data to send to the server, or |
||||
``None`` if no such data is needed. Currently HTTP requests are the only ones |
||||
that use *data*; the HTTP request will be a POST instead of a GET when the |
||||
@@ -41,7 +38,19 @@ The :mod:`urllib2` module defines the fo |
||||
The optional *timeout* parameter specifies a timeout in seconds for blocking |
||||
operations like the connection attempt (if not specified, the global default |
||||
timeout setting will be used). This actually only works for HTTP, HTTPS and |
||||
- FTP connections. |
||||
+ FTP connections. |
||||
+ |
||||
+ If *context* is specified, it must be a :class:`ssl.SSLContext` instance |
||||
+ describing the various SSL options. See :class:`~httplib.HTTPSConnection` for |
||||
+ more details. |
||||
+ |
||||
+ The optional *cafile* and *capath* parameters specify a set of trusted CA |
||||
+ certificates for HTTPS requests. *cafile* should point to a single file |
||||
+ containing a bundle of CA certificates, whereas *capath* should point to a |
||||
+ directory of hashed certificate files. More information can be found in |
||||
+ :meth:`ssl.SSLContext.load_verify_locations`. |
||||
+ |
||||
+ The *cadefault* parameter is ignored. |
||||
|
||||
This function returns a file-like object with two additional methods: |
||||
|
||||
@@ -66,7 +75,10 @@ The :mod:`urllib2` module defines the fo |
||||
handled through the proxy. |
||||
|
||||
.. versionchanged:: 2.6 |
||||
- *timeout* was added. |
||||
+ *timeout* was added. |
||||
+ |
||||
+ .. versionchanged:: 2.7.9 |
||||
+ *cafile*, *capath*, *cadefault*, and *context* were added. |
||||
|
||||
|
||||
.. function:: install_opener(opener) |
||||
@@ -280,9 +292,13 @@ The following classes are provided: |
||||
A class to handle opening of HTTP URLs. |
||||
|
||||
|
||||
-.. class:: HTTPSHandler() |
||||
+.. class:: HTTPSHandler([debuglevel[, context[, check_hostname]]]) |
||||
+ |
||||
+ A class to handle opening of HTTPS URLs. *context* and *check_hostname* have |
||||
+ the same meaning as for :class:`httplib.HTTPSConnection`. |
||||
|
||||
- A class to handle opening of HTTPS URLs. |
||||
+ .. versionchanged:: 2.7.9 |
||||
+ *context* and *check_hostname* were added. |
||||
|
||||
|
||||
.. class:: FileHandler() |
||||
diff -up Python-2.7.5/Lib/httplib.py.ctx Python-2.7.5/Lib/httplib.py |
||||
--- Python-2.7.5/Lib/httplib.py.ctx 2015-03-30 10:19:52.551521393 +0200 |
||||
+++ Python-2.7.5/Lib/httplib.py 2015-03-30 10:30:05.045386751 +0200 |
||||
@@ -1159,21 +1159,44 @@ else: |
||||
|
||||
def __init__(self, host, port=None, key_file=None, cert_file=None, |
||||
strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, |
||||
- source_address=None): |
||||
+ source_address=None, context=None, check_hostname=None): |
||||
HTTPConnection.__init__(self, host, port, strict, timeout, |
||||
source_address) |
||||
self.key_file = key_file |
||||
self.cert_file = cert_file |
||||
+ if context is None: |
||||
+ context = ssl.create_default_context() |
||||
+ will_verify = context.verify_mode != ssl.CERT_NONE |
||||
+ if check_hostname is None: |
||||
+ check_hostname = will_verify |
||||
+ elif check_hostname and not will_verify: |
||||
+ raise ValueError("check_hostname needs a SSL context with " |
||||
+ "either CERT_OPTIONAL or CERT_REQUIRED") |
||||
+ if key_file or cert_file: |
||||
+ context.load_cert_chain(cert_file, key_file) |
||||
+ self._context = context |
||||
+ self._check_hostname = check_hostname |
||||
|
||||
def connect(self): |
||||
"Connect to a host on a given (SSL) port." |
||||
|
||||
- sock = socket.create_connection((self.host, self.port), |
||||
- self.timeout, self.source_address) |
||||
+ HTTPConnection.connect(self) |
||||
+ |
||||
if self._tunnel_host: |
||||
- self.sock = sock |
||||
- self._tunnel() |
||||
- self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file) |
||||
+ server_hostname = self._tunnel_host |
||||
+ else: |
||||
+ server_hostname = self.host |
||||
+ sni_hostname = server_hostname if ssl.HAS_SNI else None |
||||
+ |
||||
+ self.sock = self._context.wrap_socket(self.sock, |
||||
+ server_hostname=sni_hostname) |
||||
+ if not self._context.check_hostname and self._check_hostname: |
||||
+ try: |
||||
+ ssl.match_hostname(self.sock.getpeercert(), server_hostname) |
||||
+ except Exception: |
||||
+ self.sock.shutdown(socket.SHUT_RDWR) |
||||
+ self.sock.close() |
||||
+ raise |
||||
|
||||
__all__.append("HTTPSConnection") |
||||
|
||||
diff -up Python-2.7.5/Lib/test/test_httplib.py.ctx Python-2.7.5/Lib/test/test_httplib.py |
||||
--- Python-2.7.5/Lib/test/test_httplib.py.ctx 2015-03-30 10:19:12.905139139 +0200 |
||||
+++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 10:27:41.822017804 +0200 |
||||
@@ -1,6 +1,7 @@ |
||||
import httplib |
||||
import array |
||||
import httplib |
||||
+import os |
||||
import StringIO |
||||
import socket |
||||
import errno |
||||
@@ -10,6 +11,14 @@ TestCase = unittest.TestCase |
||||
|
||||
from test import test_support |
||||
|
||||
+here = os.path.dirname(__file__) |
||||
+# Self-signed cert file for 'localhost' |
||||
+CERT_localhost = os.path.join(here, 'keycert.pem') |
||||
+# Self-signed cert file for 'fakehostname' |
||||
+CERT_fakehostname = os.path.join(here, 'keycert2.pem') |
||||
+# Self-signed cert file for self-signed.pythontest.net |
||||
+CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotnet.pem') |
||||
+ |
||||
HOST = test_support.HOST |
||||
|
||||
class FakeSocket: |
||||
@@ -493,40 +502,147 @@ class TimeoutTest(TestCase): |
||||
httpConn.close() |
||||
|
||||
|
||||
-class HTTPSTimeoutTest(TestCase): |
||||
+class HTTPSTest(TestCase): |
||||
# XXX Here should be tests for HTTPS, there isn't any right now! |
||||
+ def setUp(self): |
||||
+ if not hasattr(httplib, 'HTTPSConnection'): |
||||
+ self.skipTest('ssl support required') |
||||
+ |
||||
+ def make_server(self, certfile): |
||||
+ from test.ssl_servers import make_https_server |
||||
+ return make_https_server(self, certfile=certfile) |
||||
|
||||
def test_attributes(self): |
||||
- # simple test to check it's storing it |
||||
- if hasattr(httplib, 'HTTPSConnection'): |
||||
- h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) |
||||
- self.assertEqual(h.timeout, 30) |
||||
+ # simple test to check it's storing the timeout |
||||
+ h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) |
||||
+ self.assertEqual(h.timeout, 30) |
||||
+ |
||||
+ def test_networked(self): |
||||
+ # Default settings: requires a valid cert from a trusted CA |
||||
+ import ssl |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('self-signed.pythontest.net'): |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) |
||||
+ with self.assertRaises(ssl.SSLError) as exc_info: |
||||
+ h.request('GET', '/') |
||||
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') |
||||
+ |
||||
+ def test_networked_noverification(self): |
||||
+ # Switch off cert verification |
||||
+ import ssl |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('self-signed.pythontest.net'): |
||||
+ context = ssl._create_stdlib_context() |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, |
||||
+ context=context) |
||||
+ h.request('GET', '/') |
||||
+ resp = h.getresponse() |
||||
+ self.assertIn('nginx', resp.getheader('server')) |
||||
+ |
||||
+ def test_networked_trusted_by_default_cert(self): |
||||
+ # Default settings: requires a valid cert from a trusted CA |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('www.python.org'): |
||||
+ h = httplib.HTTPSConnection('www.python.org', 443) |
||||
+ h.request('GET', '/') |
||||
+ resp = h.getresponse() |
||||
+ content_type = resp.getheader('content-type') |
||||
+ self.assertIn('text/html', content_type) |
||||
+ |
||||
+ def test_networked_good_cert(self): |
||||
+ # We feed the server's cert as a validating cert |
||||
+ import ssl |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('self-signed.pythontest.net'): |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ context.verify_mode = ssl.CERT_REQUIRED |
||||
+ context.load_verify_locations(CERT_selfsigned_pythontestdotnet) |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) |
||||
+ h.request('GET', '/') |
||||
+ resp = h.getresponse() |
||||
+ server_string = resp.getheader('server') |
||||
+ self.assertIn('nginx', server_string) |
||||
+ |
||||
+ def test_networked_bad_cert(self): |
||||
+ # We feed a "CA" cert that is unrelated to the server's cert |
||||
+ import ssl |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('self-signed.pythontest.net'): |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ context.verify_mode = ssl.CERT_REQUIRED |
||||
+ context.load_verify_locations(CERT_localhost) |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) |
||||
+ with self.assertRaises(ssl.SSLError) as exc_info: |
||||
+ h.request('GET', '/') |
||||
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') |
||||
+ |
||||
+ def test_local_unknown_cert(self): |
||||
+ # The custom cert isn't known to the default trust bundle |
||||
+ import ssl |
||||
+ server = self.make_server(CERT_localhost) |
||||
+ h = httplib.HTTPSConnection('localhost', server.port) |
||||
+ with self.assertRaises(ssl.SSLError) as exc_info: |
||||
+ h.request('GET', '/') |
||||
+ self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') |
||||
+ |
||||
+ def test_local_good_hostname(self): |
||||
+ # The (valid) cert validates the HTTP hostname |
||||
+ import ssl |
||||
+ server = self.make_server(CERT_localhost) |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ context.verify_mode = ssl.CERT_REQUIRED |
||||
+ context.load_verify_locations(CERT_localhost) |
||||
+ h = httplib.HTTPSConnection('localhost', server.port, context=context) |
||||
+ h.request('GET', '/nonexistent') |
||||
+ resp = h.getresponse() |
||||
+ self.assertEqual(resp.status, 404) |
||||
+ |
||||
+ def test_local_bad_hostname(self): |
||||
+ # The (valid) cert doesn't validate the HTTP hostname |
||||
+ import ssl |
||||
+ server = self.make_server(CERT_fakehostname) |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ context.verify_mode = ssl.CERT_REQUIRED |
||||
+ context.load_verify_locations(CERT_fakehostname) |
||||
+ h = httplib.HTTPSConnection('localhost', server.port, context=context) |
||||
+ with self.assertRaises(ssl.CertificateError): |
||||
+ h.request('GET', '/') |
||||
+ # Same with explicit check_hostname=True |
||||
+ h = httplib.HTTPSConnection('localhost', server.port, context=context, |
||||
+ check_hostname=True) |
||||
+ with self.assertRaises(ssl.CertificateError): |
||||
+ h.request('GET', '/') |
||||
+ # With check_hostname=False, the mismatching is ignored |
||||
+ h = httplib.HTTPSConnection('localhost', server.port, context=context, |
||||
+ check_hostname=False) |
||||
+ h.request('GET', '/nonexistent') |
||||
+ resp = h.getresponse() |
||||
+ self.assertEqual(resp.status, 404) |
||||
|
||||
- @unittest.skipIf(not hasattr(httplib, 'HTTPS'), 'httplib.HTTPS not available') |
||||
def test_host_port(self): |
||||
# Check invalid host_port |
||||
|
||||
- # Note that httplib does not accept user:password@ in the host-port. |
||||
for hp in ("www.python.org:abc", "user:password@www.python.org"): |
||||
- self.assertRaises(httplib.InvalidURL, httplib.HTTP, hp) |
||||
+ self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) |
||||
|
||||
- for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", "fe80::207:e9ff:fe9b", |
||||
- 8000), |
||||
- ("pypi.python.org:443", "pypi.python.org", 443), |
||||
- ("pypi.python.org", "pypi.python.org", 443), |
||||
- ("pypi.python.org:", "pypi.python.org", 443), |
||||
- ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443)): |
||||
- http = httplib.HTTPS(hp) |
||||
- c = http._conn |
||||
- if h != c.host: |
||||
- self.fail("Host incorrectly parsed: %s != %s" % (h, c.host)) |
||||
- if p != c.port: |
||||
- self.fail("Port incorrectly parsed: %s != %s" % (p, c.host)) |
||||
+ for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", |
||||
+ "fe80::207:e9ff:fe9b", 8000), |
||||
+ ("www.python.org:443", "www.python.org", 443), |
||||
+ ("www.python.org:", "www.python.org", 443), |
||||
+ ("www.python.org", "www.python.org", 443), |
||||
+ ("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), |
||||
+ ("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", |
||||
+ 443)): |
||||
+ c = httplib.HTTPSConnection(hp) |
||||
+ self.assertEqual(h, c.host) |
||||
+ self.assertEqual(p, c.port) |
||||
+ |
||||
|
||||
|
||||
+@test_support.reap_threads |
||||
def test_main(verbose=None): |
||||
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, |
||||
- HTTPSTimeoutTest, SourceAddressTest) |
||||
+ HTTPSTest, SourceAddressTest) |
||||
|
||||
if __name__ == '__main__': |
||||
test_main() |
||||
diff -up Python-2.7.5/Lib/test/test_ssl.py.ctx Python-2.7.5/Lib/test/test_ssl.py |
||||
--- Python-2.7.5/Lib/test/test_ssl.py.ctx 2015-03-30 10:18:55.677973042 +0200 |
||||
+++ Python-2.7.5/Lib/test/test_ssl.py 2015-03-30 10:22:02.323772604 +0200 |
||||
@@ -14,7 +14,7 @@ import os |
||||
import errno |
||||
import pprint |
||||
import tempfile |
||||
-import urllib |
||||
+import urllib2 |
||||
import traceback |
||||
import weakref |
||||
import platform |
||||
@@ -2332,9 +2332,10 @@ else: |
||||
d1 = f.read() |
||||
d2 = '' |
||||
# now fetch the same data from the HTTPS server |
||||
- url = 'https://%s:%d/%s' % ( |
||||
- HOST, server.port, os.path.split(CERTFILE)[1]) |
||||
- f = urllib.urlopen(url) |
||||
+ url = 'https://localhost:%d/%s' % ( |
||||
+ server.port, os.path.split(CERTFILE)[1]) |
||||
+ context = ssl.create_default_context(cafile=CERTFILE) |
||||
+ f = urllib2.urlopen(url, context=context) |
||||
try: |
||||
dlen = f.info().getheader("content-length") |
||||
if dlen and (int(dlen) > 0): |
@ -0,0 +1,49 @@
@@ -0,0 +1,49 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1427947446 14400 |
||||
# Node ID 4f2391e866434a94ca6d87dff5ea01fcab91d08a |
||||
# Parent 5d88f653187203d85f4cfd4877f093af3919035b |
||||
replace 512 bit dh key with a 2014 bit one (closes #23844) |
||||
|
||||
Patch by Cédric Krier. |
||||
|
||||
diff --git a/Lib/test/dh1024.pem b/Lib/test/dh1024.pem |
||||
new file mode 100644 |
||||
--- /dev/null |
||||
+++ b/Lib/test/dh1024.pem |
||||
@@ -0,0 +1,7 @@ |
||||
+-----BEGIN DH PARAMETERS----- |
||||
+MIGHAoGBAIbzw1s9CT8SV5yv6L7esdAdZYZjPi3qWFs61CYTFFQnf2s/d09NYaJt |
||||
+rrvJhIzWavqnue71qXCf83/J3nz3FEwUU/L0mGyheVbsSHiI64wUo3u50wK5Igo0 |
||||
+RNs/LD0irs7m0icZ//hijafTU+JOBiuA8zMI+oZfU7BGuc9XrUprAgEC |
||||
+-----END DH PARAMETERS----- |
||||
+ |
||||
+Generated with: openssl dhparam -out dh1024.pem 1024 |
||||
diff --git a/Lib/test/dh512.pem b/Lib/test/dh512.pem |
||||
deleted file mode 100644 |
||||
--- a/Lib/test/dh512.pem |
||||
+++ /dev/null |
||||
@@ -1,9 +0,0 @@ |
||||
------BEGIN DH PARAMETERS----- |
||||
-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak |
||||
-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC |
||||
------END DH PARAMETERS----- |
||||
- |
||||
-These are the 512 bit DH parameters from "Assigned Number for SKIP Protocols" |
||||
-(http://www.skip-vpn.org/spec/numbers.html). |
||||
-See there for how they were generated. |
||||
-Note that g is not a generator, but this is not a problem since p is a safe prime. |
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -66,7 +66,7 @@ BADKEY = data_file("badkey.pem") |
||||
NOKIACERT = data_file("nokia.pem") |
||||
NULLBYTECERT = data_file("nullbytecert.pem") |
||||
|
||||
-DHFILE = data_file("dh512.pem") |
||||
+DHFILE = data_file("dh1024.pem") |
||||
BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) |
||||
|
||||
|
||||
|
@ -0,0 +1,153 @@
@@ -0,0 +1,153 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1416798122 21600 |
||||
# Node ID fb83916c3ea12899569e88a7505469a90ab1f674 |
||||
# Parent c84f36a5f556867c2ec50453dc879a500032d377 |
||||
pep 476: verify certificates by default (#22417) |
||||
|
||||
diff --git a/Doc/library/httplib.rst b/Doc/library/httplib.rst |
||||
--- a/Doc/library/httplib.rst |
||||
+++ b/Doc/library/httplib.rst |
||||
@@ -90,9 +90,6 @@ The module provides the following classe |
||||
server's certificate. If you want to change that behaviour, you can |
||||
explicitly set *check_hostname* to False. |
||||
|
||||
- .. warning:: |
||||
- This does not do any verification of the server's certificate. |
||||
- |
||||
.. versionadded:: 2.0 |
||||
|
||||
.. versionchanged:: 2.6 |
||||
@@ -104,6 +101,11 @@ The module provides the following classe |
||||
.. versionchanged:: 2.7.9 |
||||
*context* and *check_hostname* was added. |
||||
|
||||
+ This class now performs all the necessary certificate and hostname checks |
||||
+ by default. To revert to the previous, unverified, behavior |
||||
+ :func:`ssl._create_unverified_context` can be passed to the *context* |
||||
+ parameter. |
||||
+ |
||||
|
||||
.. class:: HTTPResponse(sock, debuglevel=0, strict=0) |
||||
|
||||
diff --git a/Lib/httplib.py b/Lib/httplib.py |
||||
--- a/Lib/httplib.py |
||||
+++ b/Lib/httplib.py |
||||
@@ -1193,7 +1193,7 @@ else: |
||||
self.key_file = key_file |
||||
self.cert_file = cert_file |
||||
if context is None: |
||||
- context = ssl.create_default_context() |
||||
+ context = ssl._create_default_https_context() |
||||
will_verify = context.verify_mode != ssl.CERT_NONE |
||||
if check_hostname is None: |
||||
check_hostname = will_verify |
||||
diff --git a/Lib/ssl.py b/Lib/ssl.py |
||||
--- a/Lib/ssl.py |
||||
+++ b/Lib/ssl.py |
||||
@@ -427,8 +427,7 @@ def create_default_context(purpose=Purpo |
||||
context.load_default_certs(purpose) |
||||
return context |
||||
|
||||
- |
||||
-def _create_stdlib_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, |
||||
+def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, |
||||
check_hostname=False, purpose=Purpose.SERVER_AUTH, |
||||
certfile=None, keyfile=None, |
||||
cafile=None, capath=None, cadata=None): |
||||
@@ -469,6 +468,14 @@ def _create_stdlib_context(protocol=PROT |
||||
|
||||
return context |
||||
|
||||
+# Used by http.client if no context is explicitly passed. |
||||
+_create_default_https_context = create_default_context |
||||
+ |
||||
+ |
||||
+# Backwards compatibility alias, even though it's not a public name. |
||||
+_create_stdlib_context = _create_unverified_context |
||||
+ |
||||
+ |
||||
class SSLSocket(socket): |
||||
"""This class implements a subtype of socket.socket that wraps |
||||
the underlying OS socket in an SSL context when necessary, and |
||||
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py |
||||
--- a/Lib/test/test_httplib.py |
||||
+++ b/Lib/test/test_httplib.py |
||||
@@ -1,10 +1,9 @@ |
||||
import httplib |
||||
import array |
||||
-import httplib |
||||
-import os |
||||
import StringIO |
||||
import socket |
||||
import errno |
||||
+import os |
||||
|
||||
import unittest |
||||
TestCase = unittest.TestCase |
||||
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py |
||||
--- a/Lib/test/test_urllib2_localnet.py |
||||
+++ b/Lib/test/test_urllib2_localnet.py |
||||
@@ -5,6 +5,7 @@ import urllib2 |
||||
import BaseHTTPServer |
||||
import unittest |
||||
import hashlib |
||||
+import ssl |
||||
|
||||
from test import test_support |
||||
|
||||
@@ -562,15 +563,37 @@ class TestUrlopen(BaseTestCase): |
||||
cafile=CERT_localhost) |
||||
self.assertEqual(data, b"we care a bit") |
||||
# Bad cert |
||||
- with self.assertRaises(urllib2.URLError) as cm: |
||||
+ with self.assertRaises(urllib2.URLError): |
||||
self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
cafile=CERT_fakehostname) |
||||
# Good cert, but mismatching hostname |
||||
handler = self.start_https_server(certfile=CERT_fakehostname) |
||||
- with self.assertRaises(ssl.CertificateError) as cm: |
||||
+ with self.assertRaises(ssl.CertificateError): |
||||
self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
cafile=CERT_fakehostname) |
||||
|
||||
+ def test_https_with_cadefault(self): |
||||
+ handler = self.start_https_server(certfile=CERT_localhost) |
||||
+ # Self-signed cert should fail verification with system certificate store |
||||
+ with self.assertRaises(urllib2.URLError): |
||||
+ self.urlopen("https://localhost:%s/bizarre" % handler.port, |
||||
+ cadefault=True) |
||||
+ |
||||
+ def test_https_sni(self): |
||||
+ if ssl is None: |
||||
+ self.skipTest("ssl module required") |
||||
+ if not ssl.HAS_SNI: |
||||
+ self.skipTest("SNI support required in OpenSSL") |
||||
+ sni_name = [None] |
||||
+ def cb_sni(ssl_sock, server_name, initial_context): |
||||
+ sni_name[0] = server_name |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ context.set_servername_callback(cb_sni) |
||||
+ handler = self.start_https_server(context=context, certfile=CERT_localhost) |
||||
+ context = ssl.create_default_context(cafile=CERT_localhost) |
||||
+ self.urlopen("https://localhost:%s" % handler.port, context=context) |
||||
+ self.assertEqual(sni_name[0], "localhost") |
||||
+ |
||||
def test_sending_headers(self): |
||||
handler = self.start_server([(200, [], "we don't care")]) |
||||
|
||||
diff -up Python-2.7.5/Doc/library/xmlrpclib.rst.ver Python-2.7.5/Doc/library/xmlrpclib.rst |
||||
--- Python-2.7.5/Doc/library/xmlrpclib.rst.ver 2015-03-30 13:59:29.243493601 +0200 |
||||
+++ Python-2.7.5/Doc/library/xmlrpclib.rst 2015-03-30 14:03:40.509532180 +0200 |
||||
@@ -34,6 +34,10 @@ between conformable Python objects and X |
||||
constructed data. If you need to parse untrusted or unauthenticated data see |
||||
:ref:`xml-vulnerabilities`. |
||||
|
||||
+.. versionchanged:: 2.7.9 |
||||
+ |
||||
+ For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate |
||||
+ and hostname checks by default |
||||
|
||||
.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) |
||||
|
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
diff -up Python-2.7.5/Lib/ssl.py.cert Python-2.7.5/Lib/ssl.py |
||||
--- Python-2.7.5/Lib/ssl.py.cert 2015-03-30 14:52:12.172241615 +0200 |
||||
+++ Python-2.7.5/Lib/ssl.py 2015-03-30 15:16:49.168185354 +0200 |
||||
@@ -466,8 +466,27 @@ def _create_unverified_context(protocol= |
||||
|
||||
return context |
||||
|
||||
+_cert_verification_config = '/etc/python/cert-verification.cfg' |
||||
+ |
||||
+def _get_verify_status(protocol): |
||||
+ context_factory = { |
||||
+ 'platform_default': _create_unverified_context, |
||||
+ 'enable': create_default_context, |
||||
+ 'disable': _create_unverified_context |
||||
+ } |
||||
+ import ConfigParser |
||||
+ try: |
||||
+ config = ConfigParser.RawConfigParser() |
||||
+ config.read(_cert_verification_config) |
||||
+ status = config.get(protocol, 'verify') |
||||
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): |
||||
+ status = 'platform_default' |
||||
+ default = context_factory.get('platform_default') |
||||
+ return context_factory.get(status, default) |
||||
+ |
||||
+ |
||||
# Used by http.client if no context is explicitly passed. |
||||
-_create_default_https_context = create_default_context |
||||
+_create_default_https_context = _get_verify_status('https') |
||||
|
||||
|
||||
# Backwards compatibility alias, even though it's not a public name. |
||||
diff -up Python-2.7.5/Lib/test/test_httplib.py.cert Python-2.7.5/Lib/test/test_httplib.py |
||||
--- Python-2.7.5/Lib/test/test_httplib.py.cert 2015-03-30 16:45:30.738794461 +0200 |
||||
+++ Python-2.7.5/Lib/test/test_httplib.py 2015-03-30 16:54:48.065062351 +0200 |
||||
@@ -516,12 +516,24 @@ class HTTPSTest(TestCase): |
||||
h = httplib.HTTPSConnection(HOST, TimeoutTest.PORT, timeout=30) |
||||
self.assertEqual(h.timeout, 30) |
||||
|
||||
+ def test_networked_default(self): |
||||
+ # specific to RHEL |
||||
+ # Default settings: doesnt requires a valid cert from a trusted CA |
||||
+ test_support.requires('network') |
||||
+ with test_support.transient_internet('self-signed.pythontest.net'): |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) |
||||
+ h.request('GET', '/') |
||||
+ resp = h.getresponse() |
||||
+ self.assertIn('nginx', resp.getheader('server')) |
||||
+ |
||||
+ # We have to pass safe context to test cert verification |
||||
+ # RHEL by default disable cert verification |
||||
def test_networked(self): |
||||
- # Default settings: requires a valid cert from a trusted CA |
||||
import ssl |
||||
test_support.requires('network') |
||||
with test_support.transient_internet('self-signed.pythontest.net'): |
||||
- h = httplib.HTTPSConnection('self-signed.pythontest.net', 443) |
||||
+ context = ssl.create_default_context() |
||||
+ h = httplib.HTTPSConnection('self-signed.pythontest.net', 443, context=context) |
||||
with self.assertRaises(ssl.SSLError) as exc_info: |
||||
h.request('GET', '/') |
||||
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') |
||||
@@ -542,8 +554,10 @@ class HTTPSTest(TestCase): |
||||
def test_networked_trusted_by_default_cert(self): |
||||
# Default settings: requires a valid cert from a trusted CA |
||||
test_support.requires('network') |
||||
+ import ssl |
||||
with test_support.transient_internet('www.python.org'): |
||||
- h = httplib.HTTPSConnection('www.python.org', 443) |
||||
+ context = ssl.create_default_context() |
||||
+ h = httplib.HTTPSConnection('www.python.org', 443, context=context) |
||||
h.request('GET', '/') |
||||
resp = h.getresponse() |
||||
content_type = resp.getheader('content-type') |
||||
@@ -579,7 +592,8 @@ class HTTPSTest(TestCase): |
||||
# The custom cert isn't known to the default trust bundle |
||||
import ssl |
||||
server = self.make_server(CERT_localhost) |
||||
- h = httplib.HTTPSConnection('localhost', server.port) |
||||
+ context = ssl.create_default_context() |
||||
+ h = httplib.HTTPSConnection('localhost', server.port, context=context) |
||||
with self.assertRaises(ssl.SSLError) as exc_info: |
||||
h.request('GET', '/') |
||||
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED') |
||||
@@ -624,6 +638,9 @@ class HTTPSTest(TestCase): |
||||
for hp in ("www.python.org:abc", "user:password@www.python.org"): |
||||
self.assertRaises(httplib.InvalidURL, httplib.HTTPSConnection, hp) |
||||
|
||||
+ import ssl |
||||
+ context = ssl.create_default_context() |
||||
+ |
||||
for hp, h, p in (("[fe80::207:e9ff:fe9b]:8000", |
||||
"fe80::207:e9ff:fe9b", 8000), |
||||
("www.python.org:443", "www.python.org", 443), |
||||
@@ -632,7 +648,7 @@ class HTTPSTest(TestCase): |
||||
("[fe80::207:e9ff:fe9b]", "fe80::207:e9ff:fe9b", 443), |
||||
("[fe80::207:e9ff:fe9b]:", "fe80::207:e9ff:fe9b", |
||||
443)): |
||||
- c = httplib.HTTPSConnection(hp) |
||||
+ c = httplib.HTTPSConnection(hp, context=context) |
||||
self.assertEqual(h, c.host) |
||||
self.assertEqual(p, c.port) |
||||
|
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
diff -up Python-2.7.5/Lib/cProfile.py.sort Python-2.7.5/Lib/cProfile.py |
||||
--- Python-2.7.5/Lib/cProfile.py.sort 2015-02-09 12:45:46.525657065 +0100 |
||||
+++ Python-2.7.5/Lib/cProfile.py 2015-02-09 12:45:05.266316315 +0100 |
||||
@@ -161,7 +161,7 @@ def label(code): |
||||
# ____________________________________________________________ |
||||
|
||||
def main(): |
||||
- import os, sys |
||||
+ import os, pstats, sys |
||||
from optparse import OptionParser |
||||
usage = "cProfile.py [-o output_file_path] [-s sort] scriptfile [arg] ..." |
||||
parser = OptionParser(usage=usage) |
||||
@@ -169,8 +169,9 @@ def main(): |
||||
parser.add_option('-o', '--outfile', dest="outfile", |
||||
help="Save stats to <outfile>", default=None) |
||||
parser.add_option('-s', '--sort', dest="sort", |
||||
- help="Sort order when printing to stdout, based on pstats.Stats class", |
||||
- default=-1) |
||||
+ help="Sort order when printing to stdout, based on pstats.Stats class", |
||||
+ default=-1, |
||||
+ choices=pstats.Stats.sort_arg_dict_default.keys()) |
||||
|
||||
if not sys.argv[1:]: |
||||
parser.print_usage() |
||||
|
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
From c1f4979e7019f6c1ce9e5a02c2e3f8ca146645bc Mon Sep 17 00:00:00 2001 |
||||
From: Charalampos Stratakis <cstratak@redhat.com> |
||||
Date: Mon, 11 Jul 2016 14:20:01 +0200 |
||||
Subject: [PATCH] Allow the keyfile argument of SSLContext.load_cert_chain to |
||||
be set to None |
||||
|
||||
--- |
||||
Modules/_ssl.c | 30 +++++++++++++++++++++++------- |
||||
1 file changed, 23 insertions(+), 7 deletions(-) |
||||
|
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
index 38eba1d..1786afd 100644 |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -2445,8 +2445,8 @@ static PyObject * |
||||
load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
||||
{ |
||||
char *kwlist[] = {"certfile", "keyfile", "password", NULL}; |
||||
- PyObject *password = NULL; |
||||
- char *certfile_bytes = NULL, *keyfile_bytes = NULL; |
||||
+ PyObject *keyfile = NULL, *keyfile_bytes = NULL, *password = NULL; |
||||
+ char *certfile_bytes = NULL; |
||||
pem_password_cb *orig_passwd_cb = self->ctx->default_passwd_callback; |
||||
void *orig_passwd_userdata = self->ctx->default_passwd_callback_userdata; |
||||
_PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; |
||||
@@ -2455,11 +2455,27 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
||||
errno = 0; |
||||
ERR_clear_error(); |
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, |
||||
- "et|etO:load_cert_chain", kwlist, |
||||
+ "et|OO:load_cert_chain", kwlist, |
||||
Py_FileSystemDefaultEncoding, &certfile_bytes, |
||||
- Py_FileSystemDefaultEncoding, &keyfile_bytes, |
||||
- &password)) |
||||
+ &keyfile, &password)) |
||||
return NULL; |
||||
+ |
||||
+ if (keyfile && keyfile != Py_None) { |
||||
+ if (PyString_Check(keyfile)) { |
||||
+ Py_INCREF(keyfile); |
||||
+ keyfile_bytes = keyfile; |
||||
+ } else { |
||||
+ PyObject *u = PyUnicode_FromObject(keyfile); |
||||
+ if (!u) |
||||
+ goto error; |
||||
+ keyfile_bytes = PyUnicode_AsEncodedString( |
||||
+ u, Py_FileSystemDefaultEncoding, NULL); |
||||
+ Py_DECREF(u); |
||||
+ if (!keyfile_bytes) |
||||
+ goto error; |
||||
+ } |
||||
+ } |
||||
+ |
||||
if (password && password != Py_None) { |
||||
if (PyCallable_Check(password)) { |
||||
pw_info.callable = password; |
||||
@@ -2489,7 +2505,7 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
||||
} |
||||
PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state); |
||||
r = SSL_CTX_use_PrivateKey_file(self->ctx, |
||||
- keyfile_bytes ? keyfile_bytes : certfile_bytes, |
||||
+ keyfile_bytes ? PyBytes_AS_STRING(keyfile_bytes) : certfile_bytes, |
||||
SSL_FILETYPE_PEM); |
||||
PySSL_END_ALLOW_THREADS_S(pw_info.thread_state); |
||||
if (r != 1) { |
||||
@@ -2521,8 +2537,8 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
||||
error: |
||||
SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); |
||||
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); |
||||
+ Py_XDECREF(keyfile_bytes); |
||||
PyMem_Free(pw_info.password); |
||||
- PyMem_Free(keyfile_bytes); |
||||
PyMem_Free(certfile_bytes); |
||||
return NULL; |
||||
} |
||||
-- |
||||
2.7.4 |
||||
|
@ -0,0 +1,260 @@
@@ -0,0 +1,260 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Alex Gaynor <alex.gaynor@gmail.com> |
||||
# Date 1409862802 25200 |
||||
# Node ID 16c86a6bdbe2a545dd2de02dc9f347c2b3ae7220 |
||||
# Parent f17ab9fed3b03191df975ecdde2cc07cee915319 |
||||
Issue #20421: Add a .version() method to SSL sockets exposing the actual protocol version in use. |
||||
|
||||
Backport from default. |
||||
|
||||
diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst |
||||
--- a/Doc/library/ssl.rst |
||||
+++ b/Doc/library/ssl.rst |
||||
@@ -867,10 +867,10 @@ SSL sockets also have the following addi |
||||
|
||||
.. method:: SSLSocket.selected_npn_protocol() |
||||
|
||||
- Returns the protocol that was selected during the TLS/SSL handshake. If |
||||
- :meth:`SSLContext.set_npn_protocols` was not called, or if the other party |
||||
- does not support NPN, or if the handshake has not yet happened, this will |
||||
- return ``None``. |
||||
+ Returns the higher-level protocol that was selected during the TLS/SSL |
||||
+ handshake. If :meth:`SSLContext.set_npn_protocols` was not called, or |
||||
+ if the other party does not support NPN, or if the handshake has not yet |
||||
+ happened, this will return ``None``. |
||||
|
||||
.. versionadded:: 2.7.9 |
||||
|
||||
@@ -882,6 +882,16 @@ SSL sockets also have the following addi |
||||
returned socket should always be used for further communication with the |
||||
other side of the connection, rather than the original socket. |
||||
|
||||
+.. method:: SSLSocket.version() |
||||
+ |
||||
+ Return the actual SSL protocol version negotiated by the connection |
||||
+ as a string, or ``None`` is no secure connection is established. |
||||
+ As of this writing, possible return values include ``"SSLv2"``, |
||||
+ ``"SSLv3"``, ``"TLSv1"``, ``"TLSv1.1"`` and ``"TLSv1.2"``. |
||||
+ Recent OpenSSL versions may define more return values. |
||||
+ |
||||
+ .. versionadded:: 3.5 |
||||
+ |
||||
.. attribute:: SSLSocket.context |
||||
|
||||
The :class:`SSLContext` object this SSL socket is tied to. If the SSL |
||||
diff --git a/Lib/ssl.py b/Lib/ssl.py |
||||
--- a/Lib/ssl.py |
||||
+++ b/Lib/ssl.py |
||||
@@ -862,6 +862,15 @@ class SSLSocket(socket): |
||||
return None |
||||
return self._sslobj.tls_unique_cb() |
||||
|
||||
+ def version(self): |
||||
+ """ |
||||
+ Return a string identifying the protocol version used by the |
||||
+ current SSL channel, or None if there is no established channel. |
||||
+ """ |
||||
+ if self._sslobj is None: |
||||
+ return None |
||||
+ return self._sslobj.version() |
||||
+ |
||||
|
||||
def wrap_socket(sock, keyfile=None, certfile=None, |
||||
server_side=False, cert_reqs=CERT_NONE, |
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -1904,7 +1904,8 @@ else: |
||||
'compression': s.compression(), |
||||
'cipher': s.cipher(), |
||||
'peercert': s.getpeercert(), |
||||
- 'client_npn_protocol': s.selected_npn_protocol() |
||||
+ 'client_npn_protocol': s.selected_npn_protocol(), |
||||
+ 'version': s.version(), |
||||
}) |
||||
s.close() |
||||
stats['server_npn_protocols'] = server.selected_protocols |
||||
@@ -1912,6 +1913,13 @@ else: |
||||
|
||||
def try_protocol_combo(server_protocol, client_protocol, expect_success, |
||||
certsreqs=None, server_options=0, client_options=0): |
||||
+ """ |
||||
+ Try to SSL-connect using *client_protocol* to *server_protocol*. |
||||
+ If *expect_success* is true, assert that the connection succeeds, |
||||
+ if it's false, assert that the connection fails. |
||||
+ Also, if *expect_success* is a string, assert that it is the protocol |
||||
+ version actually used by the connection. |
||||
+ """ |
||||
if certsreqs is None: |
||||
certsreqs = ssl.CERT_NONE |
||||
certtype = { |
||||
@@ -1941,8 +1949,8 @@ else: |
||||
ctx.load_cert_chain(CERTFILE) |
||||
ctx.load_verify_locations(CERTFILE) |
||||
try: |
||||
- server_params_test(client_context, server_context, |
||||
- chatty=False, connectionchatty=False) |
||||
+ stats = server_params_test(client_context, server_context, |
||||
+ chatty=False, connectionchatty=False) |
||||
# Protocol mismatch can result in either an SSLError, or a |
||||
# "Connection reset by peer" error. |
||||
except ssl.SSLError: |
||||
@@ -1957,6 +1965,10 @@ else: |
||||
"Client protocol %s succeeded with server protocol %s!" |
||||
% (ssl.get_protocol_name(client_protocol), |
||||
ssl.get_protocol_name(server_protocol))) |
||||
+ elif (expect_success is not True |
||||
+ and expect_success != stats['version']): |
||||
+ raise AssertionError("version mismatch: expected %r, got %r" |
||||
+ % (expect_success, stats['version'])) |
||||
|
||||
|
||||
class ThreadedTests(unittest.TestCase): |
||||
@@ -2186,17 +2198,17 @@ else: |
||||
sys.stdout.write( |
||||
" SSL2 client to SSL23 server test unexpectedly failed:\n %s\n" |
||||
% str(x)) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3') |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1') |
||||
|
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) |
||||
|
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) |
||||
|
||||
# Server with specific SSL options |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, |
||||
@@ -2213,9 +2225,9 @@ else: |
||||
"""Connecting to an SSLv3 server with various client options""" |
||||
if support.verbose: |
||||
sys.stdout.write("\n") |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3') |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_OPTIONAL) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, 'SSLv3', ssl.CERT_REQUIRED) |
||||
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False, |
||||
@@ -2223,7 +2235,7 @@ else: |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False) |
||||
if no_sslv2_implies_sslv3_hello(): |
||||
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True, |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, 'SSLv3', |
||||
client_options=ssl.OP_NO_SSLv2) |
||||
|
||||
@skip_if_broken_ubuntu_ssl |
||||
@@ -2231,9 +2243,9 @@ else: |
||||
"""Connecting to a TLSv1 server with various client options""" |
||||
if support.verbose: |
||||
sys.stdout.write("\n") |
||||
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True) |
||||
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL) |
||||
- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED) |
||||
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1') |
||||
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) |
||||
+ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) |
||||
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False) |
||||
@@ -2248,14 +2260,14 @@ else: |
||||
Testing against older TLS versions.""" |
||||
if support.verbose: |
||||
sys.stdout.write("\n") |
||||
- try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') |
||||
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv3, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_TLSv1_1) |
||||
|
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) |
||||
|
||||
@@ -2268,7 +2280,7 @@ else: |
||||
Testing against older TLS versions.""" |
||||
if support.verbose: |
||||
sys.stdout.write("\n") |
||||
- try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, True, |
||||
+ try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2', |
||||
server_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2, |
||||
client_options=ssl.OP_NO_SSLv3|ssl.OP_NO_SSLv2,) |
||||
if hasattr(ssl, 'PROTOCOL_SSLv2'): |
||||
@@ -2277,7 +2289,7 @@ else: |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_TLSv1_2) |
||||
|
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_2, 'TLSv1.2') |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_2, False) |
||||
try_protocol_combo(ssl.PROTOCOL_TLSv1_2, ssl.PROTOCOL_TLSv1_1, False) |
||||
@@ -2619,6 +2631,21 @@ else: |
||||
s.connect((HOST, server.port)) |
||||
self.assertIn("no shared cipher", str(server.conn_errors[0])) |
||||
|
||||
+ def test_version_basic(self): |
||||
+ """ |
||||
+ Basic tests for SSLSocket.version(). |
||||
+ More tests are done in the test_protocol_*() methods. |
||||
+ """ |
||||
+ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
+ with ThreadedEchoServer(CERTFILE, |
||||
+ ssl_version=ssl.PROTOCOL_TLSv1, |
||||
+ chatty=False) as server: |
||||
+ with closing(context.wrap_socket(socket.socket())) as s: |
||||
+ self.assertIs(s.version(), None) |
||||
+ s.connect((HOST, server.port)) |
||||
+ self.assertEqual(s.version(), "TLSv1") |
||||
+ self.assertIs(s.version(), None) |
||||
+ |
||||
@unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") |
||||
def test_default_ecdh_curve(self): |
||||
# Issue #21015: elliptic curve-based Diffie Hellman key exchange |
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -1384,6 +1384,18 @@ static PyObject *PySSL_cipher (PySSLSock |
||||
return NULL; |
||||
} |
||||
|
||||
+static PyObject *PySSL_version(PySSLSocket *self) |
||||
+{ |
||||
+ const char *version; |
||||
+ |
||||
+ if (self->ssl == NULL) |
||||
+ Py_RETURN_NONE; |
||||
+ version = SSL_get_version(self->ssl); |
||||
+ if (!strcmp(version, "unknown")) |
||||
+ Py_RETURN_NONE; |
||||
+ return PyUnicode_FromString(version); |
||||
+} |
||||
+ |
||||
#ifdef OPENSSL_NPN_NEGOTIATED |
||||
static PyObject *PySSL_selected_npn_protocol(PySSLSocket *self) { |
||||
const unsigned char *out; |
||||
@@ -1907,6 +1919,7 @@ static PyMethodDef PySSLMethods[] = { |
||||
{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS, |
||||
PySSL_peercert_doc}, |
||||
{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS}, |
||||
+ {"version", (PyCFunction)PySSL_version, METH_NOARGS}, |
||||
#ifdef OPENSSL_NPN_NEGOTIATED |
||||
{"selected_npn_protocol", (PyCFunction)PySSL_selected_npn_protocol, METH_NOARGS}, |
||||
#endif |
||||
|
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
From a1d7acf899fccd0eda10e011e2d11d1d81c2d9e6 Mon Sep 17 00:00:00 2001 |
||||
From: Robert Kuska <rkuska@redhat.com> |
||||
Date: Wed, 9 Mar 2016 20:16:17 +0100 |
||||
Subject: [PATCH] Expect a failure when trying to connect with SSLv2 client to |
||||
SSLv23 server. Default value of options in tests enchanced to reflect SSLv2 |
||||
being disabled |
||||
|
||||
--- |
||||
Lib/test/test_ssl.py | 4 ++-- |
||||
1 file changed, 2 insertions(+), 2 deletions(-) |
||||
|
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
index 11122db..b2ba186 100644 |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -691,7 +691,7 @@ class ContextTests(unittest.TestCase): |
||||
@skip_if_broken_ubuntu_ssl |
||||
def test_options(self): |
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
- self.assertEqual(ssl.OP_ALL, ctx.options) |
||||
+ self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, ctx.options) |
||||
ctx.options |= ssl.OP_NO_SSLv2 |
||||
self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2, |
||||
ctx.options) |
||||
@@ -2152,17 +2152,17 @@ else: |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True) |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False) |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False) |
||||
# SSLv23 client with specific SSL options |
||||
if no_sslv2_implies_sslv3_hello(): |
||||
# No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs |
||||
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_SSLv2) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_SSLv3) |
||||
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True, |
||||
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False, |
||||
client_options=ssl.OP_NO_TLSv1) |
||||
|
||||
@skip_if_broken_ubuntu_ssl |
||||
-- |
||||
2.5.0 |
||||
|
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py |
||||
index 413889a..fb312aa 100644 |
||||
--- a/Lib/test/test_thread.py |
||||
+++ b/Lib/test/test_thread.py |
||||
@@ -237,7 +237,12 @@ class TestForkInThread(unittest.TestCase): |
||||
if pid == 0: # child |
||||
os.close(self.read_fd) |
||||
os.write(self.write_fd, "OK") |
||||
- sys.exit(0) |
||||
+ # Exiting the thread normally in the child process can leave |
||||
+ # any additional threads (such as the one started by |
||||
+ # importing _tkinter) still running, and this can prevent |
||||
+ # the half-zombie child process from being cleaned up. See |
||||
+ # Issue #26456. |
||||
+ os._exit(0) |
||||
else: # parent |
||||
os.close(self.write_fd) |
||||
|
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
diff -up Python-2.7.5/Modules/_hashopenssl.c.digest Python-2.7.5/Modules/_hashopenssl.c |
||||
--- Python-2.7.5/Modules/_hashopenssl.c.digest 2016-01-05 10:53:02.947312688 +0100 |
||||
+++ Python-2.7.5/Modules/_hashopenssl.c 2016-01-05 10:53:15.504431960 +0100 |
||||
@@ -984,6 +984,7 @@ init_hashlib(void) |
||||
SSL_load_error_strings(); |
||||
SSL_library_init(); |
||||
ERR_load_crypto_strings(); |
||||
+ OpenSSL_add_all_digests(); |
||||
|
||||
Py_TYPE(&EVPtype) = &PyType_Type; |
||||
if (PyType_Ready(&EVPtype) < 0) |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
diff -r 62e3b7af0697 -r db8d7f376d24 Misc/python.man |
||||
--- a/Misc/python.man Mon Mar 21 10:38:58 2016 +0100 |
||||
+++ b/Misc/python.man Mon Mar 21 13:54:28 2016 +0100 |
||||
@@ -1,4 +1,4 @@ |
||||
-.TH PYTHON "1" "$Date$" |
||||
+.TH PYTHON "1" |
||||
|
||||
.\" To view this file while editing, run it through groff: |
||||
.\" groff -Tascii -man python.man | less |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,137 @@
@@ -0,0 +1,137 @@
|
||||
@@ -, +, @@ |
||||
--- |
||||
Lib/ssl.py | 53 ++++++++++++++++++++++++++++++++++++++--------------- |
||||
1 file changed, 38 insertions(+), 15 deletions(-) |
||||
--- a/Lib/ssl.py |
||||
+++ a/Lib/ssl.py |
||||
@@ -466,24 +466,47 @@ def _create_unverified_context(protocol=PROTOCOL_SSLv23, cert_reqs=None, |
||||
|
||||
return context |
||||
|
||||
+_https_verify_envvar = 'PYTHONHTTPSVERIFY' |
||||
_cert_verification_config = '/etc/python/cert-verification.cfg' |
||||
|
||||
-def _get_verify_status(protocol): |
||||
- context_factory = { |
||||
- 'platform_default': _create_unverified_context, |
||||
- 'enable': create_default_context, |
||||
- 'disable': _create_unverified_context |
||||
- } |
||||
- import ConfigParser |
||||
- try: |
||||
- config = ConfigParser.RawConfigParser() |
||||
- config.read(_cert_verification_config) |
||||
- status = config.get(protocol, 'verify') |
||||
- except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): |
||||
- status = 'platform_default' |
||||
- default = context_factory.get('platform_default') |
||||
- return context_factory.get(status, default) |
||||
+# To provide same function name as specified in PEP493 with keeping |
||||
+# the old name as defined in our previous patch |
||||
+_get_https_context_factory = lambda: _get_verify_status('https') |
||||
|
||||
+def _get_verify_status(protocol): |
||||
+ # See https://www.python.org/dev/peps/pep-0493/#recommendation-for-combined-feature-backports |
||||
+ # Check for an environmental override of the default behaviour |
||||
+ if not sys.flags.ignore_environment: |
||||
+ config_setting = os.environ.get(_https_verify_envvar) |
||||
+ if config_setting is not None: |
||||
+ if config_setting == '0': |
||||
+ return _create_unverified_context |
||||
+ return create_default_context |
||||
+ |
||||
+ # Check for a system-wide override of the default behaviour |
||||
+ context_factory = { |
||||
+ 'platform_default': create_default_context, |
||||
+ 'enable': create_default_context, |
||||
+ 'disable': _create_unverified_context |
||||
+ } |
||||
+ import ConfigParser |
||||
+ try: |
||||
+ config = ConfigParser.RawConfigParser() |
||||
+ config.read(_cert_verification_config) |
||||
+ status = config.get(protocol, 'verify') |
||||
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): |
||||
+ status = 'platform_default' |
||||
+ default = context_factory.get('platform_default') |
||||
+ return context_factory.get(status, default) |
||||
+ |
||||
+# See https://www.python.org/dev/peps/pep-0493/#feature-configuration-api |
||||
+def _https_verify_certificates(enable=True): |
||||
+ """Verify server HTTPS certificates by default?""" |
||||
+ global _create_default_https_context |
||||
+ if enable: |
||||
+ _create_default_https_context = create_default_context |
||||
+ else: |
||||
+ _create_default_https_context = _create_unverified_context |
||||
|
||||
# Used by http.client if no context is explicitly passed. |
||||
_create_default_https_context = _get_verify_status('https') |
||||
--- a/Lib/test/test_ssl.py Thu Jan 14 21:57:57 2016 -0800 |
||||
+++ a/Lib/test/test_ssl.py Fri Jan 15 17:41:37 2016 +1000 |
||||
@@ -4,6 +4,7 @@ |
||||
import sys |
||||
import unittest |
||||
from test import test_support as support |
||||
+from test.script_helper import assert_python_ok |
||||
import asyncore |
||||
import socket |
||||
import select |
||||
@@ -1149,6 +1149,57 @@ |
||||
self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) |
||||
self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) |
||||
|
||||
+ def test__https_verify_certificates(self): |
||||
+ # Unit test to check the contect factory mapping |
||||
+ # The factories themselves are tested above |
||||
+ # This test will fail by design if run under PYTHONHTTPSVERIFY=0 |
||||
+ # (as will various test_httplib tests) |
||||
+ |
||||
+ # Uses a fresh SSL module to avoid affecting the real one |
||||
+ local_ssl = support.import_fresh_module("ssl") |
||||
+ # Certificate verification is enabled by default |
||||
+ self.assertIs(local_ssl._create_default_https_context, |
||||
+ local_ssl.create_default_context) |
||||
+ # Turn default verification off |
||||
+ local_ssl._https_verify_certificates(enable=False) |
||||
+ self.assertIs(local_ssl._create_default_https_context, |
||||
+ local_ssl._create_unverified_context) |
||||
+ # And back on |
||||
+ local_ssl._https_verify_certificates(enable=True) |
||||
+ self.assertIs(local_ssl._create_default_https_context, |
||||
+ local_ssl.create_default_context) |
||||
+ # The default behaviour is to enable |
||||
+ local_ssl._https_verify_certificates(enable=False) |
||||
+ local_ssl._https_verify_certificates() |
||||
+ self.assertIs(local_ssl._create_default_https_context, |
||||
+ local_ssl.create_default_context) |
||||
+ |
||||
+ def test__https_verify_envvar(self): |
||||
+ # Unit test to check the PYTHONHTTPSVERIFY handling |
||||
+ # Need to use a subprocess so it can still be run under -E |
||||
+ https_is_verified = """import ssl, sys; \ |
||||
+ status = "Error: _create_default_https_context does not verify certs" \ |
||||
+ if ssl._create_default_https_context is \ |
||||
+ ssl._create_unverified_context \ |
||||
+ else None; \ |
||||
+ sys.exit(status)""" |
||||
+ https_is_not_verified = """import ssl, sys; \ |
||||
+ status = "Error: _create_default_https_context verifies certs" \ |
||||
+ if ssl._create_default_https_context is \ |
||||
+ ssl.create_default_context \ |
||||
+ else None; \ |
||||
+ sys.exit(status)""" |
||||
+ extra_env = {} |
||||
+ # Omitting it leaves verification on |
||||
+ assert_python_ok("-c", https_is_verified, **extra_env) |
||||
+ # Setting it to zero turns verification off |
||||
+ extra_env[ssl._https_verify_envvar] = "0" |
||||
+ assert_python_ok("-c", https_is_not_verified, **extra_env) |
||||
+ # Any other value should also leave it on |
||||
+ for setting in ("", "1", "enabled", "foo"): |
||||
+ extra_env[ssl._https_verify_envvar] = setting |
||||
+ assert_python_ok("-c", https_is_verified, **extra_env) |
||||
+ |
||||
def test_check_hostname(self): |
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) |
||||
self.assertFalse(ctx.check_hostname) |
@ -0,0 +1,226 @@
@@ -0,0 +1,226 @@
|
||||
From 90986ef48c0df602ab38aa831a24e99e9ed61e7e Mon Sep 17 00:00:00 2001 |
||||
From: Charalampos Stratakis <cstratak@redhat.com> |
||||
Date: Mon, 4 Apr 2016 15:55:28 +0200 |
||||
Subject: [PATCH] JSON decoder now accepts lone surrogates |
||||
|
||||
--- |
||||
Lib/json/decoder.py | 35 ++++++++++++------------ |
||||
Lib/json/tests/test_scanstring.py | 56 ++++++++++++++++++++++++++++++++++++--- |
||||
Modules/_json.c | 49 +++++++++------------------------- |
||||
3 files changed, 83 insertions(+), 57 deletions(-) |
||||
|
||||
diff --git a/Lib/json/decoder.py b/Lib/json/decoder.py |
||||
index dfcc628..1b43238 100644 |
||||
--- a/Lib/json/decoder.py |
||||
+++ b/Lib/json/decoder.py |
||||
@@ -62,6 +62,16 @@ BACKSLASH = { |
||||
|
||||
DEFAULT_ENCODING = "utf-8" |
||||
|
||||
+def _decode_uXXXX(s, pos): |
||||
+ esc = s[pos + 1:pos + 5] |
||||
+ if len(esc) == 4 and esc[1] not in 'xX': |
||||
+ try: |
||||
+ return int(esc, 16) |
||||
+ except ValueError: |
||||
+ pass |
||||
+ msg = "Invalid \\uXXXX escape" |
||||
+ raise ValueError(errmsg(msg, s, pos)) |
||||
+ |
||||
def py_scanstring(s, end, encoding=None, strict=True, |
||||
_b=BACKSLASH, _m=STRINGCHUNK.match): |
||||
"""Scan the string s for a JSON string. End is the index of the |
||||
@@ -116,25 +126,16 @@ def py_scanstring(s, end, encoding=None, strict=True, |
||||
end += 1 |
||||
else: |
||||
# Unicode escape sequence |
||||
- esc = s[end + 1:end + 5] |
||||
- next_end = end + 5 |
||||
- if len(esc) != 4: |
||||
- msg = "Invalid \\uXXXX escape" |
||||
- raise ValueError(errmsg(msg, s, end)) |
||||
- uni = int(esc, 16) |
||||
+ uni = _decode_uXXXX(s, end) |
||||
+ end += 5 |
||||
# Check for surrogate pair on UCS-4 systems |
||||
- if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: |
||||
- msg = "Invalid \\uXXXX\\uXXXX surrogate pair" |
||||
- if not s[end + 5:end + 7] == '\\u': |
||||
- raise ValueError(errmsg(msg, s, end)) |
||||
- esc2 = s[end + 7:end + 11] |
||||
- if len(esc2) != 4: |
||||
- raise ValueError(errmsg(msg, s, end)) |
||||
- uni2 = int(esc2, 16) |
||||
- uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) |
||||
- next_end += 6 |
||||
+ if sys.maxunicode > 65535 and \ |
||||
+ 0xd800 <= uni <= 0xdbff and s[end:end + 2] == '\\u': |
||||
+ uni2 = _decode_uXXXX(s, end + 1) |
||||
+ if 0xdc00 <= uni2 <= 0xdfff: |
||||
+ uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) |
||||
+ end += 6 |
||||
char = unichr(uni) |
||||
- end = next_end |
||||
# Append the unescaped character |
||||
_append(char) |
||||
return u''.join(chunks), end |
||||
diff --git a/Lib/json/tests/test_scanstring.py b/Lib/json/tests/test_scanstring.py |
||||
index 4fef8cb..ed80a41 100644 |
||||
--- a/Lib/json/tests/test_scanstring.py |
||||
+++ b/Lib/json/tests/test_scanstring.py |
||||
@@ -5,10 +5,6 @@ from json.tests import PyTest, CTest |
||||
class TestScanstring(object): |
||||
def test_scanstring(self): |
||||
scanstring = self.json.decoder.scanstring |
||||
- self.assertEqual( |
||||
- scanstring('"z\\ud834\\udd20x"', 1, None, True), |
||||
- (u'z\U0001d120x', 16)) |
||||
- |
||||
if sys.maxunicode == 65535: |
||||
self.assertEqual( |
||||
scanstring(u'"z\U0001d120x"', 1, None, True), |
||||
@@ -94,6 +90,58 @@ class TestScanstring(object): |
||||
scanstring('["Bad value", truth]', 2, None, True), |
||||
(u'Bad value', 12)) |
||||
|
||||
+ def test_surrogates(self): |
||||
+ scanstring = self.json.decoder.scanstring |
||||
+ def assertScan(given, expect): |
||||
+ self.assertEqual(scanstring(given, 1, None, True), |
||||
+ (expect, len(given))) |
||||
+ if not isinstance(given, unicode): |
||||
+ given = unicode(given) |
||||
+ self.assertEqual(scanstring(given, 1, None, True), |
||||
+ (expect, len(given))) |
||||
+ |
||||
+ surrogates = unichr(0xd834) + unichr(0xdd20) |
||||
+ assertScan('"z\\ud834\\u0079x"', u'z\ud834yx') |
||||
+ assertScan('"z\\ud834\\udd20x"', u'z\U0001d120x') |
||||
+ assertScan('"z\\ud834\\ud834\\udd20x"', u'z\ud834\U0001d120x') |
||||
+ assertScan('"z\\ud834x"', u'z\ud834x') |
||||
+ assertScan(u'"z\\ud834\udd20x12345"', u'z%sx12345' % surrogates) |
||||
+ assertScan('"z\\udd20x"', u'z\udd20x') |
||||
+ assertScan(u'"z\ud834\udd20x"', u'z\ud834\udd20x') |
||||
+ assertScan(u'"z\ud834\\udd20x"', u'z%sx' % surrogates) |
||||
+ assertScan(u'"z\ud834x"', u'z\ud834x') |
||||
+ |
||||
+ def test_bad_escapes(self): |
||||
+ scanstring = self.json.decoder.scanstring |
||||
+ bad_escapes = [ |
||||
+ '"\\"', |
||||
+ '"\\x"', |
||||
+ '"\\u"', |
||||
+ '"\\u0"', |
||||
+ '"\\u01"', |
||||
+ '"\\u012"', |
||||
+ '"\\uz012"', |
||||
+ '"\\u0z12"', |
||||
+ '"\\u01z2"', |
||||
+ '"\\u012z"', |
||||
+ '"\\u0x12"', |
||||
+ '"\\u0X12"', |
||||
+ '"\\ud834\\"', |
||||
+ '"\\ud834\\u"', |
||||
+ '"\\ud834\\ud"', |
||||
+ '"\\ud834\\udd"', |
||||
+ '"\\ud834\\udd2"', |
||||
+ '"\\ud834\\uzdd2"', |
||||
+ '"\\ud834\\udzd2"', |
||||
+ '"\\ud834\\uddz2"', |
||||
+ '"\\ud834\\udd2z"', |
||||
+ '"\\ud834\\u0x20"', |
||||
+ '"\\ud834\\u0X20"', |
||||
+ ] |
||||
+ for s in bad_escapes: |
||||
+ with self.assertRaises(ValueError): |
||||
+ scanstring(s, 1, None, True) |
||||
+ |
||||
def test_issue3623(self): |
||||
self.assertRaises(ValueError, self.json.decoder.scanstring, b"xxx", 1, |
||||
"xxx") |
||||
diff --git a/Modules/_json.c b/Modules/_json.c |
||||
index 7c925fd..56d9ee4 100644 |
||||
--- a/Modules/_json.c |
||||
+++ b/Modules/_json.c |
||||
@@ -524,16 +524,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s |
||||
} |
||||
#ifdef Py_UNICODE_WIDE |
||||
/* Surrogate pair */ |
||||
- if ((c & 0xfc00) == 0xd800) { |
||||
+ if ((c & 0xfc00) == 0xd800 && end + 6 < len && |
||||
+ buf[next++] == '\\' && |
||||
+ buf[next++] == 'u') { |
||||
Py_UNICODE c2 = 0; |
||||
- if (end + 6 >= len) { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
- if (buf[next++] != '\\' || buf[next++] != 'u') { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
end += 6; |
||||
/* Decode 4 hex digits */ |
||||
for (; next < end; next++) { |
||||
@@ -554,15 +548,10 @@ scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_s |
||||
goto bail; |
||||
} |
||||
} |
||||
- if ((c2 & 0xfc00) != 0xdc00) { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); |
||||
- } |
||||
- else if ((c & 0xfc00) == 0xdc00) { |
||||
- raise_errmsg("Unpaired low surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
+ if ((c2 & 0xfc00) == 0xdc00) |
||||
+ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); |
||||
+ else |
||||
+ end -= 6; |
||||
} |
||||
#endif |
||||
} |
||||
@@ -703,16 +692,9 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next |
||||
} |
||||
#ifdef Py_UNICODE_WIDE |
||||
/* Surrogate pair */ |
||||
- if ((c & 0xfc00) == 0xd800) { |
||||
+ if ((c & 0xfc00) == 0xd800 && end + 6 < len && |
||||
+ buf[next++] == '\\' && buf[next++] == 'u') { |
||||
Py_UNICODE c2 = 0; |
||||
- if (end + 6 >= len) { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
- if (buf[next++] != '\\' || buf[next++] != 'u') { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
end += 6; |
||||
/* Decode 4 hex digits */ |
||||
for (; next < end; next++) { |
||||
@@ -733,15 +715,10 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next |
||||
goto bail; |
||||
} |
||||
} |
||||
- if ((c2 & 0xfc00) != 0xdc00) { |
||||
- raise_errmsg("Unpaired high surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
- } |
||||
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); |
||||
- } |
||||
- else if ((c & 0xfc00) == 0xdc00) { |
||||
- raise_errmsg("Unpaired low surrogate", pystr, end - 5); |
||||
- goto bail; |
||||
+ if ((c2 & 0xfc00) == 0xdc00) |
||||
+ c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00)); |
||||
+ else |
||||
+ end -= 6; |
||||
} |
||||
#endif |
||||
} |
||||
-- |
||||
2.5.5 |
||||
|
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
From 6bebd55022c82829c0b15d24d2ca99edd22562df Mon Sep 17 00:00:00 2001 |
||||
From: Charalampos Stratakis <cstratak@redhat.com> |
||||
Date: Wed, 4 May 2016 10:39:40 +0200 |
||||
Subject: [PATCH] use Py_ssize_t for file offset and length computations in |
||||
iteration |
||||
|
||||
--- |
||||
Lib/test/test_file2k.py | 16 +++++++++++++++- |
||||
Objects/fileobject.c | 15 +++++++-------- |
||||
2 files changed, 22 insertions(+), 9 deletions(-) |
||||
|
||||
diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py |
||||
index 5a3c354..8f94cee 100644 |
||||
--- a/Lib/test/test_file2k.py |
||||
+++ b/Lib/test/test_file2k.py |
||||
@@ -14,7 +14,7 @@ except ImportError: |
||||
threading = None |
||||
|
||||
from test import test_support |
||||
-from test.test_support import TESTFN, run_unittest |
||||
+from test.test_support import TESTFN, run_unittest, requires |
||||
from UserList import UserList |
||||
|
||||
class AutoFileTests(unittest.TestCase): |
||||
@@ -416,6 +416,20 @@ class OtherFileTests(unittest.TestCase): |
||||
finally: |
||||
os.unlink(TESTFN) |
||||
|
||||
+ @test_support.precisionbigmemtest(2**31, 2.5, dry_run=False) |
||||
+ def test_very_long_line(self, size): |
||||
+ # Issue #22526 |
||||
+ requires('largefile') |
||||
+ with open(TESTFN, "wb") as fp: |
||||
+ fp.seek(size - 1) |
||||
+ fp.write("\0") |
||||
+ with open(TESTFN, "rb") as fp: |
||||
+ for l in fp: |
||||
+ pass |
||||
+ self.assertEqual(len(l), size) |
||||
+ self.assertEqual(l.count("\0"), size) |
||||
+ l = None |
||||
+ |
||||
class FileSubclassTests(unittest.TestCase): |
||||
|
||||
def testExit(self): |
||||
diff --git a/Objects/fileobject.c b/Objects/fileobject.c |
||||
index 76cdf74..fabe207 100644 |
||||
--- a/Objects/fileobject.c |
||||
+++ b/Objects/fileobject.c |
||||
@@ -2230,7 +2230,7 @@ drop_readahead(PyFileObject *f) |
||||
(unless at EOF) and no more than bufsize. Returns negative value on |
||||
error, will set MemoryError if bufsize bytes cannot be allocated. */ |
||||
static int |
||||
-readahead(PyFileObject *f, int bufsize) |
||||
+readahead(PyFileObject *f, Py_ssize_t bufsize) |
||||
{ |
||||
Py_ssize_t chunksize; |
||||
|
||||
@@ -2268,7 +2268,7 @@ readahead(PyFileObject *f, int bufsize) |
||||
logarithmic buffer growth to about 50 even when reading a 1gb line. */ |
||||
|
||||
static PyStringObject * |
||||
-readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) |
||||
+readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize) |
||||
{ |
||||
PyStringObject* s; |
||||
char *bufptr; |
||||
@@ -2288,10 +2288,10 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) |
||||
bufptr++; /* Count the '\n' */ |
||||
len = bufptr - f->f_bufptr; |
||||
s = (PyStringObject *) |
||||
- PyString_FromStringAndSize(NULL, skip+len); |
||||
+ PyString_FromStringAndSize(NULL, skip + len); |
||||
if (s == NULL) |
||||
return NULL; |
||||
- memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); |
||||
+ memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len); |
||||
f->f_bufptr = bufptr; |
||||
if (bufptr == f->f_bufend) |
||||
drop_readahead(f); |
||||
@@ -2299,14 +2299,13 @@ readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) |
||||
bufptr = f->f_bufptr; |
||||
buf = f->f_buf; |
||||
f->f_buf = NULL; /* Force new readahead buffer */ |
||||
- assert(skip+len < INT_MAX); |
||||
- s = readahead_get_line_skip( |
||||
- f, (int)(skip+len), bufsize + (bufsize>>2) ); |
||||
+ assert(len <= PY_SSIZE_T_MAX - skip); |
||||
+ s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2)); |
||||
if (s == NULL) { |
||||
PyMem_Free(buf); |
||||
return NULL; |
||||
} |
||||
- memcpy(PyString_AS_STRING(s)+skip, bufptr, len); |
||||
+ memcpy(PyString_AS_STRING(s) + skip, bufptr, len); |
||||
PyMem_Free(buf); |
||||
} |
||||
return s; |
||||
-- |
||||
2.5.5 |
||||
|
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
From 5b67aca6fb4246e84981d6361ba218bd52e73ac2 Mon Sep 17 00:00:00 2001 |
||||
From: Tomas Orsava <torsava@redhat.com> |
||||
Date: Tue, 21 Jun 2016 15:52:03 +0200 |
||||
Subject: [PATCH] Raise an error when STARTTLS fails |
||||
|
||||
CVE-2016-0772 python: smtplib StartTLS stripping attack |
||||
rhbz#1303647: https://bugzilla.redhat.com/show_bug.cgi?id=1303647 |
||||
|
||||
Based on an upstream change by Benjamin Peterson <benjamin@python.org> |
||||
- in changeset 101886:b3ce713fb9be 2.7 |
||||
- https://hg.python.org/cpython/rev/b3ce713fb9be |
||||
--- |
||||
Lib/smtplib.py | 5 +++++ |
||||
1 file changed, 5 insertions(+) |
||||
|
||||
diff --git a/Lib/smtplib.py b/Lib/smtplib.py |
||||
index dc16ef6..8bc806b 100755 |
||||
--- a/Lib/smtplib.py |
||||
+++ b/Lib/smtplib.py |
||||
@@ -655,6 +655,11 @@ class SMTP: |
||||
self.ehlo_resp = None |
||||
self.esmtp_features = {} |
||||
self.does_esmtp = 0 |
||||
+ else: |
||||
+ # RFC 3207: |
||||
+ # 501 Syntax error (no parameters allowed) |
||||
+ # 454 TLS not available due to temporary reason |
||||
+ raise SMTPResponseException(resp, reply) |
||||
return (resp, reply) |
||||
|
||||
def sendmail(self, from_addr, to_addrs, msg, mail_options=[], |
||||
-- |
||||
2.5.5 |
||||
|
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
From e91c46c7a1a904eba04e29cdf896c99cb546d989 Mon Sep 17 00:00:00 2001 |
||||
From: Tomas Orsava <torsava@redhat.com> |
||||
Date: Wed, 22 Jun 2016 17:06:01 +0200 |
||||
Subject: [PATCH] Disabled HTTP header injections in httplib |
||||
|
||||
CVE-2016-5699 python: http protocol steam injection attack |
||||
rhbz#1303699 : https://bugzilla.redhat.com/show_bug.cgi?id=1303699 |
||||
|
||||
Based on an upstream change by Demian Brecht and Serhiy Storchaka |
||||
- in changeset 94951:1c45047c5102 2.7 |
||||
- https://hg.python.org/cpython/rev/1c45047c5102 |
||||
--- |
||||
Lib/httplib.py | 40 +++++++++++++++++++++++++++++++++- |
||||
Lib/test/test_httplib.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ |
||||
2 files changed, 95 insertions(+), 1 deletion(-) |
||||
|
||||
diff --git a/Lib/httplib.py b/Lib/httplib.py |
||||
index 8e02ac3..592ee57 100644 |
||||
--- a/Lib/httplib.py |
||||
+++ b/Lib/httplib.py |
||||
@@ -68,6 +68,7 @@ Req-sent-unread-response _CS_REQ_SENT <response_class> |
||||
|
||||
from array import array |
||||
import os |
||||
+import re |
||||
import socket |
||||
from sys import py3kwarning |
||||
from urlparse import urlsplit |
||||
@@ -218,6 +219,34 @@ _MAXLINE = 65536 |
||||
# maximum amount of headers accepted |
||||
_MAXHEADERS = 100 |
||||
|
||||
+# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) |
||||
+# |
||||
+# VCHAR = %x21-7E |
||||
+# obs-text = %x80-FF |
||||
+# header-field = field-name ":" OWS field-value OWS |
||||
+# field-name = token |
||||
+# field-value = *( field-content / obs-fold ) |
||||
+# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] |
||||
+# field-vchar = VCHAR / obs-text |
||||
+# |
||||
+# obs-fold = CRLF 1*( SP / HTAB ) |
||||
+# ; obsolete line folding |
||||
+# ; see Section 3.2.4 |
||||
+ |
||||
+# token = 1*tchar |
||||
+# |
||||
+# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" |
||||
+# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" |
||||
+# / DIGIT / ALPHA |
||||
+# ; any VCHAR, except delimiters |
||||
+# |
||||
+# VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 |
||||
+ |
||||
+# the patterns for both name and value are more leniant than RFC |
||||
+# definitions to allow for backwards compatibility |
||||
+_is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match |
||||
+_is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search |
||||
+ |
||||
|
||||
class HTTPMessage(mimetools.Message): |
||||
|
||||
@@ -956,7 +985,16 @@ class HTTPConnection: |
||||
if self.__state != _CS_REQ_STARTED: |
||||
raise CannotSendHeader() |
||||
|
||||
- hdr = '%s: %s' % (header, '\r\n\t'.join([str(v) for v in values])) |
||||
+ header = '%s' % header |
||||
+ if not _is_legal_header_name(header): |
||||
+ raise ValueError('Invalid header name %r' % (header,)) |
||||
+ |
||||
+ values = [str(v) for v in values] |
||||
+ for one_value in values: |
||||
+ if _is_illegal_header_value(one_value): |
||||
+ raise ValueError('Invalid header value %r' % (one_value,)) |
||||
+ |
||||
+ hdr = '%s: %s' % (header, '\r\n\t'.join(values)) |
||||
self._output(hdr) |
||||
|
||||
def endheaders(self, message_body=None): |
||||
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py |
||||
index c29aceb..29af589 100644 |
||||
--- a/Lib/test/test_httplib.py |
||||
+++ b/Lib/test/test_httplib.py |
||||
@@ -133,6 +133,33 @@ class HeaderTests(TestCase): |
||||
conn.putheader('Content-length',42) |
||||
self.assertTrue('Content-length: 42' in conn._buffer) |
||||
|
||||
+ conn.putheader('Foo', ' bar ') |
||||
+ self.assertIn(b'Foo: bar ', conn._buffer) |
||||
+ conn.putheader('Bar', '\tbaz\t') |
||||
+ self.assertIn(b'Bar: \tbaz\t', conn._buffer) |
||||
+ conn.putheader('Authorization', 'Bearer mytoken') |
||||
+ self.assertIn(b'Authorization: Bearer mytoken', conn._buffer) |
||||
+ conn.putheader('IterHeader', 'IterA', 'IterB') |
||||
+ self.assertIn(b'IterHeader: IterA\r\n\tIterB', conn._buffer) |
||||
+ conn.putheader('LatinHeader', b'\xFF') |
||||
+ self.assertIn(b'LatinHeader: \xFF', conn._buffer) |
||||
+ conn.putheader('Utf8Header', b'\xc3\x80') |
||||
+ self.assertIn(b'Utf8Header: \xc3\x80', conn._buffer) |
||||
+ conn.putheader('C1-Control', b'next\x85line') |
||||
+ self.assertIn(b'C1-Control: next\x85line', conn._buffer) |
||||
+ conn.putheader('Embedded-Fold-Space', 'is\r\n allowed') |
||||
+ self.assertIn(b'Embedded-Fold-Space: is\r\n allowed', conn._buffer) |
||||
+ conn.putheader('Embedded-Fold-Tab', 'is\r\n\tallowed') |
||||
+ self.assertIn(b'Embedded-Fold-Tab: is\r\n\tallowed', conn._buffer) |
||||
+ conn.putheader('Key Space', 'value') |
||||
+ self.assertIn(b'Key Space: value', conn._buffer) |
||||
+ conn.putheader('KeySpace ', 'value') |
||||
+ self.assertIn(b'KeySpace : value', conn._buffer) |
||||
+ conn.putheader(b'Nonbreak\xa0Space', 'value') |
||||
+ self.assertIn(b'Nonbreak\xa0Space: value', conn._buffer) |
||||
+ conn.putheader(b'\xa0NonbreakSpace', 'value') |
||||
+ self.assertIn(b'\xa0NonbreakSpace: value', conn._buffer) |
||||
+ |
||||
def test_ipv6host_header(self): |
||||
# Default host header on IPv6 transaction should wrapped by [] if |
||||
# its actual IPv6 address |
||||
@@ -152,6 +179,35 @@ class HeaderTests(TestCase): |
||||
conn.request('GET', '/foo') |
||||
self.assertTrue(sock.data.startswith(expected)) |
||||
|
||||
+ def test_invalid_headers(self): |
||||
+ conn = httplib.HTTPConnection('example.com') |
||||
+ conn.sock = FakeSocket('') |
||||
+ conn.putrequest('GET', '/') |
||||
+ |
||||
+ # http://tools.ietf.org/html/rfc7230#section-3.2.4, whitespace is no |
||||
+ # longer allowed in header names |
||||
+ cases = ( |
||||
+ (b'Invalid\r\nName', b'ValidValue'), |
||||
+ (b'Invalid\rName', b'ValidValue'), |
||||
+ (b'Invalid\nName', b'ValidValue'), |
||||
+ (b'\r\nInvalidName', b'ValidValue'), |
||||
+ (b'\rInvalidName', b'ValidValue'), |
||||
+ (b'\nInvalidName', b'ValidValue'), |
||||
+ (b' InvalidName', b'ValidValue'), |
||||
+ (b'\tInvalidName', b'ValidValue'), |
||||
+ (b'Invalid:Name', b'ValidValue'), |
||||
+ (b':InvalidName', b'ValidValue'), |
||||
+ (b'ValidName', b'Invalid\r\nValue'), |
||||
+ (b'ValidName', b'Invalid\rValue'), |
||||
+ (b'ValidName', b'Invalid\nValue'), |
||||
+ (b'ValidName', b'InvalidValue\r\n'), |
||||
+ (b'ValidName', b'InvalidValue\r'), |
||||
+ (b'ValidName', b'InvalidValue\n'), |
||||
+ ) |
||||
+ for name, value in cases: |
||||
+ with self.assertRaisesRegexp(ValueError, 'Invalid header'): |
||||
+ conn.putheader(name, value) |
||||
+ |
||||
|
||||
class BasicTest(TestCase): |
||||
def test_status_lines(self): |
||||
-- |
||||
2.9.0 |
||||
|
@ -0,0 +1,66 @@
@@ -0,0 +1,66 @@
|
||||
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py |
||||
index 14d0060d8ec..1bb66901880 100644 |
||||
--- a/Lib/test/test_smtplib.py |
||||
+++ b/Lib/test/test_smtplib.py |
||||
@@ -179,31 +179,31 @@ def tearDown(self): |
||||
|
||||
def testBasic(self): |
||||
# connect |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
smtp.quit() |
||||
|
||||
def testNOOP(self): |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
expected = (250, 'Ok') |
||||
self.assertEqual(smtp.noop(), expected) |
||||
smtp.quit() |
||||
|
||||
def testRSET(self): |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
expected = (250, 'Ok') |
||||
self.assertEqual(smtp.rset(), expected) |
||||
smtp.quit() |
||||
|
||||
def testNotImplemented(self): |
||||
# EHLO isn't implemented in DebuggingServer |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
expected = (502, 'Error: command "EHLO" not implemented') |
||||
self.assertEqual(smtp.ehlo(), expected) |
||||
smtp.quit() |
||||
|
||||
def testVRFY(self): |
||||
# VRFY isn't implemented in DebuggingServer |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
expected = (502, 'Error: command "VRFY" not implemented') |
||||
self.assertEqual(smtp.vrfy('nobody@nowhere.com'), expected) |
||||
self.assertEqual(smtp.verify('nobody@nowhere.com'), expected) |
||||
@@ -212,21 +212,21 @@ def testVRFY(self): |
||||
def testSecondHELO(self): |
||||
# check that a second HELO returns a message that it's a duplicate |
||||
# (this behavior is specific to smtpd.SMTPChannel) |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
smtp.helo() |
||||
expected = (503, 'Duplicate HELO/EHLO') |
||||
self.assertEqual(smtp.helo(), expected) |
||||
smtp.quit() |
||||
|
||||
def testHELP(self): |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
self.assertEqual(smtp.help(), 'Error: command "HELP" not implemented') |
||||
smtp.quit() |
||||
|
||||
def testSend(self): |
||||
# connect and send mail |
||||
m = 'A test message' |
||||
- smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=3) |
||||
+ smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) |
||||
smtp.sendmail('John', 'Sally', m) |
||||
# XXX(nnorwitz): this test is flaky and dies with a bad file descriptor |
||||
# in asyncore. This sleep might help, but should really be fixed |
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
From 0f12cb75c708978f9201c1dd3464d2a8572b4544 Mon Sep 17 00:00:00 2001 |
||||
From: Charalampos Stratakis <cstratak@redhat.com> |
||||
Date: Fri, 8 Jul 2016 20:24:10 +0200 |
||||
Subject: [PATCH] CVE-2016-5636 fix |
||||
|
||||
--- |
||||
Modules/zipimport.c | 9 +++++++++ |
||||
1 file changed, 9 insertions(+) |
||||
|
||||
diff --git a/Modules/zipimport.c b/Modules/zipimport.c |
||||
index 7240cb4..2e6a61f 100644 |
||||
--- a/Modules/zipimport.c |
||||
+++ b/Modules/zipimport.c |
||||
@@ -861,6 +861,10 @@ get_data(char *archive, PyObject *toc_entry) |
||||
&date, &crc)) { |
||||
return NULL; |
||||
} |
||||
+ if (data_size < 0) { |
||||
+ PyErr_Format(ZipImportError, "negative data size"); |
||||
+ return NULL; |
||||
+ } |
||||
|
||||
fp = fopen(archive, "rb"); |
||||
if (!fp) { |
||||
@@ -895,6 +899,11 @@ get_data(char *archive, PyObject *toc_entry) |
||||
PyMarshal_ReadShortFromFile(fp); /* local header size */ |
||||
file_offset += l; /* Start of file data */ |
||||
|
||||
+ if (data_size > LONG_MAX - 1) { |
||||
+ fclose(fp); |
||||
+ PyErr_NoMemory(); |
||||
+ return NULL; |
||||
+ } |
||||
raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ? |
||||
data_size : data_size + 1); |
||||
if (raw_data == NULL) { |
||||
-- |
||||
2.7.4 |
||||
|
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
From 3a184cc875709d4324d234a4b939d614a2c9bb0f Mon Sep 17 00:00:00 2001 |
||||
From: Charalampos Stratakis <cstratak@redhat.com> |
||||
Date: Mon, 1 Aug 2016 11:20:11 +0200 |
||||
Subject: [PATCH] =?UTF-8?q?Fix=20for=20CVE-2016-1000110=20http://bugs.pyth?= |
||||
=?UTF-8?q?on.org/issue27568=20Based=20on=20the=20patch=20by=20R=C3=A9mi?= |
||||
=?UTF-8?q?=20Rampin?= |
||||
MIME-Version: 1.0 |
||||
Content-Type: text/plain; charset=UTF-8 |
||||
Content-Transfer-Encoding: 8bit |
||||
|
||||
--- |
||||
Doc/howto/urllib2.rst | 5 +++++ |
||||
Doc/library/urllib.rst | 10 ++++++++++ |
||||
Doc/library/urllib2.rst | 4 ++++ |
||||
Lib/test/test_urllib.py | 12 ++++++++++++ |
||||
Lib/urllib.py | 9 +++++++++ |
||||
5 files changed, 40 insertions(+) |
||||
|
||||
diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst |
||||
index f84bf08..6542846 100644 |
||||
--- a/Doc/howto/urllib2.rst |
||||
+++ b/Doc/howto/urllib2.rst |
||||
@@ -523,6 +523,11 @@ setting up a `Basic Authentication`_ handler : :: |
||||
through a proxy. However, this can be enabled by extending urllib2 as |
||||
shown in the recipe [#]_. |
||||
|
||||
+.. note:: |
||||
+ |
||||
+ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; see |
||||
+ the documentation on :func:`~urllib.getproxies`. |
||||
+ |
||||
|
||||
Sockets and Layers |
||||
================== |
||||
diff --git a/Doc/library/urllib.rst b/Doc/library/urllib.rst |
||||
index c7d200d..3b9876e 100644 |
||||
--- a/Doc/library/urllib.rst |
||||
+++ b/Doc/library/urllib.rst |
||||
@@ -280,6 +280,16 @@ Utility functions |
||||
find it, looks for proxy information from Mac OSX System Configuration for |
||||
Mac OS X and Windows Systems Registry for Windows. |
||||
|
||||
+ .. note:: |
||||
+ |
||||
+ If the environment variable ``REQUEST_METHOD`` is set, which usually |
||||
+ indicates your script is running in a CGI environment, the environment |
||||
+ variable ``HTTP_PROXY`` (uppercase ``_PROXY``) will be ignored. This is |
||||
+ because that variable can be injected by a client using the "Proxy:" |
||||
+ HTTP header. If you need to use an HTTP proxy in a CGI environment, |
||||
+ either use ``ProxyHandler`` explicitly, or make sure the variable name |
||||
+ is in lowercase (or at least the ``_proxy`` suffix). |
||||
+ |
||||
.. note:: |
||||
urllib also exposes certain utility functions like splittype, splithost and |
||||
others parsing url into various components. But it is recommended to use |
||||
diff --git a/Doc/library/urllib2.rst b/Doc/library/urllib2.rst |
||||
index 24deeb4..46fce59 100644 |
||||
--- a/Doc/library/urllib2.rst |
||||
+++ b/Doc/library/urllib2.rst |
||||
@@ -224,6 +224,10 @@ The following classes are provided: |
||||
|
||||
To disable autodetected proxy pass an empty dictionary. |
||||
|
||||
+ .. note:: |
||||
+ |
||||
+ ``HTTP_PROXY`` will be ignored if a variable ``REQUEST_METHOD`` is set; |
||||
+ see the documentation on :func:`~urllib.getproxies`. |
||||
|
||||
.. class:: HTTPPasswordMgr() |
||||
|
||||
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py |
||||
index 3a273f8..3845012 100644 |
||||
--- a/Lib/test/test_urllib.py |
||||
+++ b/Lib/test/test_urllib.py |
||||
@@ -161,6 +161,18 @@ class ProxyTests(unittest.TestCase): |
||||
self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com') |
||||
self.assertTrue(urllib.proxy_bypass_environment('anotherdomain.com')) |
||||
|
||||
+ def test_proxy_cgi_ignore(self): |
||||
+ try: |
||||
+ self.env.set('HTTP_PROXY', 'http://somewhere:3128') |
||||
+ proxies = urllib.getproxies_environment() |
||||
+ self.assertEqual('http://somewhere:3128', proxies['http']) |
||||
+ self.env.set('REQUEST_METHOD', 'GET') |
||||
+ proxies = urllib.getproxies_environment() |
||||
+ self.assertNotIn('http', proxies) |
||||
+ finally: |
||||
+ self.env.unset('REQUEST_METHOD') |
||||
+ self.env.unset('HTTP_PROXY') |
||||
+ |
||||
|
||||
class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin): |
||||
"""Test urlopen() opening a fake http connection.""" |
||||
diff --git a/Lib/urllib.py b/Lib/urllib.py |
||||
index f9655f9..9b31df1 100644 |
||||
--- a/Lib/urllib.py |
||||
+++ b/Lib/urllib.py |
||||
@@ -1361,11 +1361,20 @@ def getproxies_environment(): |
||||
[Fancy]URLopener constructor. |
||||
|
||||
""" |
||||
+ # Get all variables |
||||
proxies = {} |
||||
for name, value in os.environ.items(): |
||||
name = name.lower() |
||||
if value and name[-6:] == '_proxy': |
||||
proxies[name[:-6]] = value |
||||
+ |
||||
+ # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY |
||||
+ # (non-all-lowercase) as it may be set from the web server by a "Proxy:" |
||||
+ # header from the client |
||||
+ # If "proxy" is lowercase, it will still be used thanks to the next block |
||||
+ if 'REQUEST_METHOD' in os.environ: |
||||
+ proxies.pop('http', None) |
||||
+ |
||||
return proxies |
||||
|
||||
def proxy_bypass_environment(host): |
||||
-- |
||||
2.7.4 |
||||
|
@ -0,0 +1,235 @@
@@ -0,0 +1,235 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Christian Heimes <christian@python.org> |
||||
# Date 1473197135 -7200 |
||||
# Node ID 74805fd9e7343649372d0b9c76b4490b2975a674 |
||||
# Parent 6f4f19217d9be12be7a9c86cf1e118b140564b4f |
||||
Issue #27691: Fix ssl module's parsing of GEN_RID subject alternative name fields in X.509 certs. |
||||
|
||||
diff --git a/Lib/test/allsans.pem b/Lib/test/allsans.pem |
||||
new file mode 100644 |
||||
--- /dev/null |
||||
+++ b/Lib/test/allsans.pem |
||||
@@ -0,0 +1,37 @@ |
||||
+-----BEGIN PRIVATE KEY----- |
||||
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE |
||||
+6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG |
||||
+Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm |
||||
+DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu |
||||
+A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az |
||||
+61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk |
||||
+elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb |
||||
+tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G |
||||
+kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l |
||||
+xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J |
||||
+b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/ |
||||
+EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa |
||||
+czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2 |
||||
+/CyWR2P3yLtOmA== |
||||
+-----END PRIVATE KEY----- |
||||
+-----BEGIN CERTIFICATE----- |
||||
+MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV |
||||
+BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u |
||||
+IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1 |
||||
+MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO |
||||
+Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0 |
||||
+aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB |
||||
+gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO |
||||
+ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA |
||||
+pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw |
||||
+ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp |
||||
+ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC |
||||
+AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu |
||||
+b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw |
||||
+IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly |
||||
+bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA |
||||
+AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT |
||||
+VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG |
||||
+iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f |
||||
+3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ== |
||||
+-----END CERTIFICATE----- |
||||
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py |
||||
--- a/Lib/test/make_ssl_certs.py |
||||
+++ b/Lib/test/make_ssl_certs.py |
||||
@@ -20,7 +20,28 @@ req_template = """ |
||||
CN = {hostname} |
||||
|
||||
[req_x509_extensions] |
||||
- subjectAltName = DNS:{hostname} |
||||
+ subjectAltName = @san |
||||
+ |
||||
+ [san] |
||||
+ DNS.1 = {hostname} |
||||
+ {extra_san} |
||||
+ |
||||
+ [dir_sect] |
||||
+ C = XY |
||||
+ L = Castle Anthrax |
||||
+ O = Python Software Foundation |
||||
+ CN = dirname example |
||||
+ |
||||
+ [princ_name] |
||||
+ realm = EXP:0, GeneralString:KERBEROS.REALM |
||||
+ principal_name = EXP:1, SEQUENCE:principal_seq |
||||
+ |
||||
+ [principal_seq] |
||||
+ name_type = EXP:0, INTEGER:1 |
||||
+ name_string = EXP:1, SEQUENCE:principals |
||||
+ |
||||
+ [principals] |
||||
+ princ1 = GeneralString:username |
||||
|
||||
[ ca ] |
||||
default_ca = CA_default |
||||
@@ -67,7 +88,7 @@ req_template = """ |
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__)) |
||||
|
||||
-def make_cert_key(hostname, sign=False): |
||||
+def make_cert_key(hostname, sign=False, extra_san=''): |
||||
print("creating cert for " + hostname) |
||||
tempnames = [] |
||||
for i in range(3): |
||||
@@ -75,8 +96,9 @@ def make_cert_key(hostname, sign=False): |
||||
tempnames.append(f.name) |
||||
req_file, cert_file, key_file = tempnames |
||||
try: |
||||
+ req = req_template.format(hostname=hostname, extra_san=extra_san) |
||||
with open(req_file, 'w') as f: |
||||
- f.write(req_template.format(hostname=hostname)) |
||||
+ f.write(req) |
||||
args = ['req', '-new', '-days', '3650', '-nodes', |
||||
'-newkey', 'rsa:1024', '-keyout', key_file, |
||||
'-config', req_file] |
||||
@@ -120,7 +142,7 @@ def make_ca(): |
||||
f.write('unique_subject = no') |
||||
|
||||
with tempfile.NamedTemporaryFile("w") as t: |
||||
- t.write(req_template.format(hostname='our-ca-server')) |
||||
+ t.write(req_template.format(hostname='our-ca-server', extra_san='')) |
||||
t.flush() |
||||
with tempfile.NamedTemporaryFile() as f: |
||||
args = ['req', '-new', '-days', '3650', '-extensions', 'v3_ca', '-nodes', |
||||
@@ -171,6 +193,25 @@ if __name__ == '__main__': |
||||
f.write(key) |
||||
f.write(cert) |
||||
|
||||
+ extra_san = [ |
||||
+ 'otherName.1 = 1.2.3.4;UTF8:some other identifier', |
||||
+ 'otherName.2 = 1.3.6.1.5.2.2;SEQUENCE:princ_name', |
||||
+ 'email.1 = user@example.org', |
||||
+ 'DNS.2 = www.example.org', |
||||
+ # GEN_X400 |
||||
+ 'dirName.1 = dir_sect', |
||||
+ # GEN_EDIPARTY |
||||
+ 'URI.1 = https://www.python.org/', |
||||
+ 'IP.1 = 127.0.0.1', |
||||
+ 'IP.2 = ::1', |
||||
+ 'RID.1 = 1.2.3.4.5', |
||||
+ ] |
||||
+ |
||||
+ cert, key = make_cert_key('allsans', extra_san='\n'.join(extra_san)) |
||||
+ with open('allsans.pem', 'w') as f: |
||||
+ f.write(key) |
||||
+ f.write(cert) |
||||
+ |
||||
unmake_ca() |
||||
print("\n\nPlease change the values in test_ssl.py, test_parse_cert function related to notAfter,notBefore and serialNumber") |
||||
check_call(['openssl','x509','-in','keycert.pem','-dates','-serial','-noout']) |
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py |
||||
index fa59641..9d5816b 100644 |
||||
--- a/Lib/test/test_ssl.py |
||||
+++ b/Lib/test/test_ssl.py |
||||
@@ -57,6 +57,8 @@ CRLFILE = data_file("revocation.crl") |
||||
SIGNED_CERTFILE = data_file("keycert3.pem") |
||||
SIGNED_CERTFILE2 = data_file("keycert4.pem") |
||||
SIGNING_CA = data_file("pycacert.pem") |
||||
+# cert with all kinds of subject alt names |
||||
+ALLSANFILE = data_file("allsans.pem") |
||||
|
||||
SVN_PYTHON_ORG_ROOT_CERT = data_file("https_svn_python_org_root.pem") |
||||
|
||||
@@ -236,6 +238,28 @@ class BasicSocketTests(unittest.TestCase): |
||||
('IP Address', '2001:DB8:0:0:0:0:0:1\n')) |
||||
) |
||||
|
||||
+ def test_parse_all_sans(self): |
||||
+ p = ssl._ssl._test_decode_cert(ALLSANFILE) |
||||
+ self.assertEqual(p['subjectAltName'], |
||||
+ ( |
||||
+ ('DNS', 'allsans'), |
||||
+ ('othername', '<unsupported>'), |
||||
+ ('othername', '<unsupported>'), |
||||
+ ('email', 'user@example.org'), |
||||
+ ('DNS', 'www.example.org'), |
||||
+ ('DirName', |
||||
+ ((('countryName', 'XY'),), |
||||
+ (('localityName', 'Castle Anthrax'),), |
||||
+ (('organizationName', 'Python Software Foundation'),), |
||||
+ (('commonName', 'dirname example'),))), |
||||
+ ('URI', 'https://www.python.org/'), |
||||
+ ('IP Address', '127.0.0.1'), |
||||
+ ('IP Address', '0:0:0:0:0:0:0:1\n'), |
||||
+ ('Registered ID', '1.2.3.4.5') |
||||
+ ) |
||||
+ ) |
||||
+ |
||||
+ |
||||
def test_DER_to_PEM(self): |
||||
with open(SVN_PYTHON_ORG_ROOT_CERT, 'r') as f: |
||||
pem = f.read() |
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -953,6 +953,35 @@ static PyObject * |
||||
PyTuple_SET_ITEM(t, 1, v); |
||||
break; |
||||
|
||||
+ case GEN_RID: |
||||
+ t = PyTuple_New(2); |
||||
+ if (t == NULL) |
||||
+ goto fail; |
||||
+ |
||||
+ v = PyUnicode_FromString("Registered ID"); |
||||
+ if (v == NULL) { |
||||
+ Py_DECREF(t); |
||||
+ goto fail; |
||||
+ } |
||||
+ PyTuple_SET_ITEM(t, 0, v); |
||||
+ |
||||
+ len = i2t_ASN1_OBJECT(buf, sizeof(buf)-1, name->d.rid); |
||||
+ if (len < 0) { |
||||
+ Py_DECREF(t); |
||||
+ _setSSLError(NULL, 0, __FILE__, __LINE__); |
||||
+ goto fail; |
||||
+ } else if (len >= (int)sizeof(buf)) { |
||||
+ v = PyUnicode_FromString("<INVALID>"); |
||||
+ } else { |
||||
+ v = PyUnicode_FromStringAndSize(buf, len); |
||||
+ } |
||||
+ if (v == NULL) { |
||||
+ Py_DECREF(t); |
||||
+ goto fail; |
||||
+ } |
||||
+ PyTuple_SET_ITEM(t, 1, v); |
||||
+ break; |
||||
+ |
||||
default: |
||||
/* for everything else, we use the OpenSSL print form */ |
||||
switch (gntype) { |
||||
@@ -978,8 +1007,12 @@ static PyObject * |
||||
goto fail; |
||||
} |
||||
vptr = strchr(buf, ':'); |
||||
- if (vptr == NULL) |
||||
+ if (vptr == NULL) { |
||||
+ PyErr_Format(PyExc_ValueError, |
||||
+ "Invalid value %.200s", |
||||
+ buf); |
||||
goto fail; |
||||
+ } |
||||
t = PyTuple_New(2); |
||||
if (t == NULL) |
||||
goto fail; |
||||
|
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
diff --git a/Lib/threading.py b/Lib/threading.py |
||||
index e4c7f35..91b3849 100644 |
||||
--- a/Lib/threading.py |
||||
+++ b/Lib/threading.py |
||||
@@ -351,13 +351,14 @@ class _Condition(_Verbose): |
||||
gotit = waiter.acquire(0) |
||||
if gotit: |
||||
break |
||||
- remaining = endtime - _time() |
||||
+ remaining = min(endtime - _time(), timeout) |
||||
if remaining <= 0: |
||||
break |
||||
if balancing: |
||||
delay = min(delay * 2, remaining, 0.05) |
||||
else: |
||||
delay = remaining |
||||
+ endtime = _time() + remaining |
||||
_sleep(delay) |
||||
if not gotit: |
||||
if __debug__: |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
index a3ea254..d0a3830 100644 |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -2564,7 +2564,9 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds) |
||||
} |
||||
SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); |
||||
SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); |
||||
+ Py_XDECREF(keyfile_bytes); |
||||
PyMem_Free(pw_info.password); |
||||
+ PyMem_Free(certfile_bytes); |
||||
Py_RETURN_NONE; |
||||
|
||||
error: |
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
diff --git a/Include/pythread.h b/Include/pythread.h |
||||
index dfd6157..f3e6259 100644 |
||||
--- a/Include/pythread.h |
||||
+++ b/Include/pythread.h |
||||
@@ -30,6 +30,8 @@ PyAPI_FUNC(void) PyThread_delete_key(int); |
||||
PyAPI_FUNC(int) PyThread_set_key_value(int, void *); |
||||
PyAPI_FUNC(void *) PyThread_get_key_value(int); |
||||
PyAPI_FUNC(void) PyThread_delete_key_value(int key); |
||||
+PyAPI_FUNC(int) _PyThread_AcquireKeyLock(void); |
||||
+PyAPI_FUNC(void) _PyThread_ReleaseKeyLock(void); |
||||
|
||||
/* Cleanup after a fork */ |
||||
PyAPI_FUNC(void) PyThread_ReInitTLS(void); |
||||
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c |
||||
index 022d7aa..8f6cbb2 100644 |
||||
--- a/Modules/posixmodule.c |
||||
+++ b/Modules/posixmodule.c |
||||
@@ -65,6 +65,10 @@ corresponding Unix manual entries for more information on calls."); |
||||
#include "osdefs.h" |
||||
#endif |
||||
|
||||
+#ifdef WITH_THREAD |
||||
+#include "pythread.h" |
||||
+#endif |
||||
+ |
||||
#ifdef HAVE_SYS_TYPES_H |
||||
#include <sys/types.h> |
||||
#endif /* HAVE_SYS_TYPES_H */ |
||||
@@ -3796,7 +3800,18 @@ posix_fork1(PyObject *self, PyObject *noargs) |
||||
pid_t pid; |
||||
int result = 0; |
||||
_PyImport_AcquireLock(); |
||||
+#ifdef WITH_THREAD |
||||
+ if (_PyThread_AcquireKeyLock() == 0) { |
||||
+ _PyImport_ReleaseLock(); |
||||
+ PyErr_SetString(PyExc_RuntimeError, |
||||
+ "could not acquire thread key lock"); |
||||
+ return NULL; |
||||
+ } |
||||
+#endif |
||||
pid = fork1(); |
||||
+#ifdef WITH_THREAD |
||||
+ _PyThread_ReleaseKeyLock(); |
||||
+#endif |
||||
if (pid == 0) { |
||||
/* child: this clobbers and resets the import lock. */ |
||||
PyOS_AfterFork(); |
||||
@@ -3829,7 +3844,18 @@ posix_fork(PyObject *self, PyObject *noargs) |
||||
pid_t pid; |
||||
int result = 0; |
||||
_PyImport_AcquireLock(); |
||||
+#ifdef WITH_THREAD |
||||
+ if (_PyThread_AcquireKeyLock() == 0) { |
||||
+ _PyImport_ReleaseLock(); |
||||
+ PyErr_SetString(PyExc_RuntimeError, |
||||
+ "could not acquire thread key lock"); |
||||
+ return NULL; |
||||
+ } |
||||
+#endif |
||||
pid = fork(); |
||||
+#ifdef WITH_THREAD |
||||
+ _PyThread_ReleaseKeyLock(); |
||||
+#endif |
||||
if (pid == 0) { |
||||
/* child: this clobbers and resets the import lock. */ |
||||
PyOS_AfterFork(); |
||||
@@ -3955,7 +3981,18 @@ posix_forkpty(PyObject *self, PyObject *noargs) |
||||
pid_t pid; |
||||
|
||||
_PyImport_AcquireLock(); |
||||
+#ifdef WITH_THREAD |
||||
+ if (_PyThread_AcquireKeyLock() == 0) { |
||||
+ _PyImport_ReleaseLock(); |
||||
+ PyErr_SetString(PyExc_RuntimeError, |
||||
+ "could not acquire thread key lock"); |
||||
+ return NULL; |
||||
+ } |
||||
+#endif |
||||
pid = forkpty(&master_fd, NULL, NULL, NULL); |
||||
+#ifdef WITH_THREAD |
||||
+ _PyThread_ReleaseKeyLock(); |
||||
+#endif |
||||
if (pid == 0) { |
||||
/* child: this clobbers and resets the import lock. */ |
||||
PyOS_AfterFork(); |
||||
diff --git a/Python/thread.c b/Python/thread.c |
||||
index dd333e8..957739e 100644 |
||||
--- a/Python/thread.c |
||||
+++ b/Python/thread.c |
||||
@@ -387,6 +387,24 @@ PyThread_delete_key_value(int key) |
||||
PyThread_release_lock(keymutex); |
||||
} |
||||
|
||||
+int |
||||
+_PyThread_AcquireKeyLock(void) |
||||
+{ |
||||
+ if (keymutex == NULL) { |
||||
+ keymutex = PyThread_allocate_lock(); |
||||
+ } |
||||
+ if (keymutex == NULL) { |
||||
+ return 0; |
||||
+ } |
||||
+ return PyThread_acquire_lock(keymutex, 1); |
||||
+} |
||||
+ |
||||
+void |
||||
+_PyThread_ReleaseKeyLock(void) |
||||
+{ |
||||
+ PyThread_release_lock(keymutex); |
||||
+} |
||||
+ |
||||
/* Forget everything not associated with the current thread id. |
||||
* This function is called from PyOS_AfterFork(). It is necessary |
||||
* because other thread ids which were in use at the time of the fork |
@ -0,0 +1,376 @@
@@ -0,0 +1,376 @@
|
||||
diff --git a/Lib/shutil.py b/Lib/shutil.py |
||||
index 420802f..d0ff2ef 100644 |
||||
--- a/Lib/shutil.py |
||||
+++ b/Lib/shutil.py |
||||
@@ -446,17 +446,24 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): |
||||
zip_filename, base_dir) |
||||
|
||||
if not dry_run: |
||||
- zip = zipfile.ZipFile(zip_filename, "w", |
||||
- compression=zipfile.ZIP_DEFLATED) |
||||
- |
||||
- for dirpath, dirnames, filenames in os.walk(base_dir): |
||||
- for name in filenames: |
||||
- path = os.path.normpath(os.path.join(dirpath, name)) |
||||
- if os.path.isfile(path): |
||||
- zip.write(path, path) |
||||
+ with zipfile.ZipFile(zip_filename, "w", |
||||
+ compression=zipfile.ZIP_DEFLATED) as zf: |
||||
+ path = os.path.normpath(base_dir) |
||||
+ zf.write(path, path) |
||||
+ if logger is not None: |
||||
+ logger.info("adding '%s'", path) |
||||
+ for dirpath, dirnames, filenames in os.walk(base_dir): |
||||
+ for name in sorted(dirnames): |
||||
+ path = os.path.normpath(os.path.join(dirpath, name)) |
||||
+ zf.write(path, path) |
||||
if logger is not None: |
||||
logger.info("adding '%s'", path) |
||||
- zip.close() |
||||
+ for name in filenames: |
||||
+ path = os.path.normpath(os.path.join(dirpath, name)) |
||||
+ if os.path.isfile(path): |
||||
+ zf.write(path, path) |
||||
+ if logger is not None: |
||||
+ logger.info("adding '%s'", path) |
||||
|
||||
return zip_filename |
||||
|
||||
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py |
||||
index 9bdb724..9238489 100644 |
||||
--- a/Lib/test/test_shutil.py |
||||
+++ b/Lib/test/test_shutil.py |
||||
@@ -10,13 +10,13 @@ import os.path |
||||
import errno |
||||
from os.path import splitdrive |
||||
from distutils.spawn import find_executable, spawn |
||||
-from shutil import (_make_tarball, _make_zipfile, make_archive, |
||||
+from shutil import (make_archive, |
||||
register_archive_format, unregister_archive_format, |
||||
get_archive_formats) |
||||
import tarfile |
||||
import warnings |
||||
|
||||
-from test import test_support |
||||
+from test import test_support as support |
||||
from test.test_support import TESTFN, check_warnings, captured_stdout |
||||
|
||||
TESTFN2 = TESTFN + "2" |
||||
@@ -372,139 +372,135 @@ class TestShutil(unittest.TestCase): |
||||
@unittest.skipUnless(zlib, "requires zlib") |
||||
def test_make_tarball(self): |
||||
# creating something to tar |
||||
- tmpdir = self.mkdtemp() |
||||
- self.write_file([tmpdir, 'file1'], 'xxx') |
||||
- self.write_file([tmpdir, 'file2'], 'xxx') |
||||
- os.mkdir(os.path.join(tmpdir, 'sub')) |
||||
- self.write_file([tmpdir, 'sub', 'file3'], 'xxx') |
||||
+ root_dir, base_dir = self._create_files('') |
||||
|
||||
tmpdir2 = self.mkdtemp() |
||||
# force shutil to create the directory |
||||
os.rmdir(tmpdir2) |
||||
- unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], |
||||
+ unittest.skipUnless(splitdrive(root_dir)[0] == splitdrive(tmpdir2)[0], |
||||
"source and target should be on same drive") |
||||
|
||||
base_name = os.path.join(tmpdir2, 'archive') |
||||
|
||||
# working with relative paths to avoid tar warnings |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- _make_tarball(splitdrive(base_name)[1], '.') |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ make_archive(splitdrive(base_name)[1], 'gztar', root_dir, '.') |
||||
|
||||
# check if the compressed tarball was created |
||||
tarball = base_name + '.tar.gz' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertTrue(os.path.isfile(tarball)) |
||||
+ self.assertTrue(tarfile.is_tarfile(tarball)) |
||||
+ with tarfile.open(tarball, 'r:gz') as tf: |
||||
+ self.assertEqual(sorted(tf.getnames()), |
||||
+ ['.', './file1', './file2', |
||||
+ './sub', './sub/file3', './sub2']) |
||||
|
||||
# trying an uncompressed one |
||||
base_name = os.path.join(tmpdir2, 'archive') |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- _make_tarball(splitdrive(base_name)[1], '.', compress=None) |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ make_archive(splitdrive(base_name)[1], 'tar', root_dir, '.') |
||||
tarball = base_name + '.tar' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertTrue(os.path.isfile(tarball)) |
||||
+ self.assertTrue(tarfile.is_tarfile(tarball)) |
||||
+ with tarfile.open(tarball, 'r') as tf: |
||||
+ self.assertEqual(sorted(tf.getnames()), |
||||
+ ['.', './file1', './file2', |
||||
+ './sub', './sub/file3', './sub2']) |
||||
|
||||
def _tarinfo(self, path): |
||||
- tar = tarfile.open(path) |
||||
- try: |
||||
+ with tarfile.open(path) as tar: |
||||
names = tar.getnames() |
||||
names.sort() |
||||
return tuple(names) |
||||
- finally: |
||||
- tar.close() |
||||
|
||||
- def _create_files(self): |
||||
+ def _create_files(self, base_dir='dist'): |
||||
# creating something to tar |
||||
- tmpdir = self.mkdtemp() |
||||
- dist = os.path.join(tmpdir, 'dist') |
||||
- os.mkdir(dist) |
||||
- self.write_file([dist, 'file1'], 'xxx') |
||||
- self.write_file([dist, 'file2'], 'xxx') |
||||
+ root_dir = self.mkdtemp() |
||||
+ dist = os.path.join(root_dir, base_dir) |
||||
+ if not os.path.isdir(dist): |
||||
+ os.makedirs(dist) |
||||
+ self.write_file((dist, 'file1'), 'xxx') |
||||
+ self.write_file((dist, 'file2'), 'xxx') |
||||
os.mkdir(os.path.join(dist, 'sub')) |
||||
- self.write_file([dist, 'sub', 'file3'], 'xxx') |
||||
+ self.write_file((dist, 'sub', 'file3'), 'xxx') |
||||
os.mkdir(os.path.join(dist, 'sub2')) |
||||
- tmpdir2 = self.mkdtemp() |
||||
- base_name = os.path.join(tmpdir2, 'archive') |
||||
- return tmpdir, tmpdir2, base_name |
||||
+ if base_dir: |
||||
+ self.write_file((root_dir, 'outer'), 'xxx') |
||||
+ return root_dir, base_dir |
||||
|
||||
@unittest.skipUnless(zlib, "Requires zlib") |
||||
- @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), |
||||
+ @unittest.skipUnless(find_executable('tar'), |
||||
'Need the tar command to run') |
||||
def test_tarfile_vs_tar(self): |
||||
- tmpdir, tmpdir2, base_name = self._create_files() |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- _make_tarball(base_name, 'dist') |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ root_dir, base_dir = self._create_files() |
||||
+ base_name = os.path.join(self.mkdtemp(), 'archive') |
||||
+ make_archive(base_name, 'gztar', root_dir, base_dir) |
||||
|
||||
# check if the compressed tarball was created |
||||
tarball = base_name + '.tar.gz' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertTrue(os.path.isfile(tarball)) |
||||
|
||||
# now create another tarball using `tar` |
||||
- tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') |
||||
- tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] |
||||
- gzip_cmd = ['gzip', '-f9', 'archive2.tar'] |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- with captured_stdout() as s: |
||||
- spawn(tar_cmd) |
||||
- spawn(gzip_cmd) |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ tarball2 = os.path.join(root_dir, 'archive2.tar') |
||||
+ tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir] |
||||
+ with support.change_cwd(root_dir), captured_stdout(): |
||||
+ spawn(tar_cmd) |
||||
|
||||
- self.assertTrue(os.path.exists(tarball2)) |
||||
+ self.assertTrue(os.path.isfile(tarball2)) |
||||
# let's compare both tarballs |
||||
self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2)) |
||||
|
||||
# trying an uncompressed one |
||||
- base_name = os.path.join(tmpdir2, 'archive') |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- _make_tarball(base_name, 'dist', compress=None) |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ make_archive(base_name, 'tar', root_dir, base_dir) |
||||
tarball = base_name + '.tar' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertTrue(os.path.isfile(tarball)) |
||||
|
||||
# now for a dry_run |
||||
- base_name = os.path.join(tmpdir2, 'archive') |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
- try: |
||||
- _make_tarball(base_name, 'dist', compress=None, dry_run=True) |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ make_archive(base_name, 'tar', root_dir, base_dir, dry_run=True) |
||||
tarball = base_name + '.tar' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertTrue(os.path.isfile(tarball)) |
||||
|
||||
@unittest.skipUnless(zlib, "Requires zlib") |
||||
@unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') |
||||
def test_make_zipfile(self): |
||||
- # creating something to tar |
||||
- tmpdir = self.mkdtemp() |
||||
- self.write_file([tmpdir, 'file1'], 'xxx') |
||||
- self.write_file([tmpdir, 'file2'], 'xxx') |
||||
+ # creating something to zip |
||||
+ root_dir, base_dir = self._create_files() |
||||
+ base_name = os.path.join(self.mkdtemp(), 'archive') |
||||
|
||||
- tmpdir2 = self.mkdtemp() |
||||
- # force shutil to create the directory |
||||
- os.rmdir(tmpdir2) |
||||
- base_name = os.path.join(tmpdir2, 'archive') |
||||
- _make_zipfile(base_name, tmpdir) |
||||
+ res = make_archive(base_name, 'zip', root_dir, base_dir) |
||||
|
||||
- # check if the compressed tarball was created |
||||
- tarball = base_name + '.zip' |
||||
- self.assertTrue(os.path.exists(tarball)) |
||||
+ self.assertEqual(res, base_name + '.zip') |
||||
+ self.assertTrue(os.path.isfile(res)) |
||||
+ self.assertTrue(zipfile.is_zipfile(res)) |
||||
+ with zipfile.ZipFile(res) as zf: |
||||
+ self.assertEqual(sorted(zf.namelist()), |
||||
+ ['dist/', 'dist/file1', 'dist/file2', |
||||
+ 'dist/sub/', 'dist/sub/file3', 'dist/sub2/']) |
||||
|
||||
+ @unittest.skipUnless(zlib, "Requires zlib") |
||||
+ @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') |
||||
+ @unittest.skipUnless(find_executable('zip'), |
||||
+ 'Need the zip command to run') |
||||
+ def test_zipfile_vs_zip(self): |
||||
+ root_dir, base_dir = self._create_files() |
||||
+ base_name = os.path.join(self.mkdtemp(), 'archive') |
||||
+ archive = make_archive(base_name, 'zip', root_dir, base_dir) |
||||
+ |
||||
+ # check if ZIP file was created |
||||
+ self.assertEqual(archive, base_name + '.zip') |
||||
+ self.assertTrue(os.path.isfile(archive)) |
||||
+ |
||||
+ # now create another ZIP file using `zip` |
||||
+ archive2 = os.path.join(root_dir, 'archive2.zip') |
||||
+ zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir] |
||||
+ with support.change_cwd(root_dir): |
||||
+ spawn(zip_cmd) |
||||
+ |
||||
+ self.assertTrue(os.path.isfile(archive2)) |
||||
+ # let's compare both ZIP files |
||||
+ with zipfile.ZipFile(archive) as zf: |
||||
+ names = zf.namelist() |
||||
+ with zipfile.ZipFile(archive2) as zf: |
||||
+ names2 = zf.namelist() |
||||
+ self.assertEqual(sorted(names), sorted(names2)) |
||||
|
||||
def test_make_archive(self): |
||||
tmpdir = self.mkdtemp() |
||||
@@ -521,39 +517,36 @@ class TestShutil(unittest.TestCase): |
||||
else: |
||||
group = owner = 'root' |
||||
|
||||
- base_dir, root_dir, base_name = self._create_files() |
||||
- base_name = os.path.join(self.mkdtemp() , 'archive') |
||||
+ root_dir, base_dir = self._create_files() |
||||
+ base_name = os.path.join(self.mkdtemp(), 'archive') |
||||
res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, |
||||
group=group) |
||||
- self.assertTrue(os.path.exists(res)) |
||||
+ self.assertTrue(os.path.isfile(res)) |
||||
|
||||
res = make_archive(base_name, 'zip', root_dir, base_dir) |
||||
- self.assertTrue(os.path.exists(res)) |
||||
+ self.assertTrue(os.path.isfile(res)) |
||||
|
||||
res = make_archive(base_name, 'tar', root_dir, base_dir, |
||||
owner=owner, group=group) |
||||
- self.assertTrue(os.path.exists(res)) |
||||
+ self.assertTrue(os.path.isfile(res)) |
||||
|
||||
res = make_archive(base_name, 'tar', root_dir, base_dir, |
||||
owner='kjhkjhkjg', group='oihohoh') |
||||
- self.assertTrue(os.path.exists(res)) |
||||
+ self.assertTrue(os.path.isfile(res)) |
||||
|
||||
@unittest.skipUnless(zlib, "Requires zlib") |
||||
@unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") |
||||
def test_tarfile_root_owner(self): |
||||
- tmpdir, tmpdir2, base_name = self._create_files() |
||||
- old_dir = os.getcwd() |
||||
- os.chdir(tmpdir) |
||||
+ root_dir, base_dir = self._create_files() |
||||
+ base_name = os.path.join(self.mkdtemp(), 'archive') |
||||
group = grp.getgrgid(0)[0] |
||||
owner = pwd.getpwuid(0)[0] |
||||
- try: |
||||
- archive_name = _make_tarball(base_name, 'dist', compress=None, |
||||
- owner=owner, group=group) |
||||
- finally: |
||||
- os.chdir(old_dir) |
||||
+ with support.change_cwd(root_dir): |
||||
+ archive_name = make_archive(base_name, 'gztar', root_dir, 'dist', |
||||
+ owner=owner, group=group) |
||||
|
||||
# check if the compressed tarball was created |
||||
- self.assertTrue(os.path.exists(archive_name)) |
||||
+ self.assertTrue(os.path.isfile(archive_name)) |
||||
|
||||
# now checks the rights |
||||
archive = tarfile.open(archive_name) |
||||
@@ -859,7 +852,7 @@ class TestCopyFile(unittest.TestCase): |
||||
|
||||
|
||||
def test_main(): |
||||
- test_support.run_unittest(TestShutil, TestMove, TestCopyFile) |
||||
+ support.run_unittest(TestShutil, TestMove, TestCopyFile) |
||||
|
||||
if __name__ == '__main__': |
||||
test_main() |
||||
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py |
||||
index 42c1b4d..98a9275 100644 |
||||
--- a/Lib/test/test_support.py |
||||
+++ b/Lib/test/test_support.py |
||||
@@ -491,6 +491,33 @@ TESTFN = "{}_{}_tmp".format(TESTFN, os.getpid()) |
||||
SAVEDCWD = os.getcwd() |
||||
|
||||
@contextlib.contextmanager |
||||
+def change_cwd(path, quiet=False): |
||||
+ """Return a context manager that changes the current working directory. |
||||
+ |
||||
+ Arguments: |
||||
+ |
||||
+ path: the directory to use as the temporary current working directory. |
||||
+ |
||||
+ quiet: if False (the default), the context manager raises an exception |
||||
+ on error. Otherwise, it issues only a warning and keeps the current |
||||
+ working directory the same. |
||||
+ |
||||
+ """ |
||||
+ saved_dir = os.getcwd() |
||||
+ try: |
||||
+ os.chdir(path) |
||||
+ except OSError: |
||||
+ if not quiet: |
||||
+ raise |
||||
+ warnings.warn('tests may fail, unable to change CWD to: ' + path, |
||||
+ RuntimeWarning, stacklevel=3) |
||||
+ try: |
||||
+ yield os.getcwd() |
||||
+ finally: |
||||
+ os.chdir(saved_dir) |
||||
+ |
||||
+ |
||||
+@contextlib.contextmanager |
||||
def temp_cwd(name='tempcwd', quiet=False): |
||||
""" |
||||
Context manager that creates a temporary directory and set it as CWD. |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Vinay Sajip <vinay_sajip@yahoo.co.uk> |
||||
# Date 1402737594 -3600 |
||||
# Node ID bb8b0c7fefd0c5ed99b3f336178a4f9554a1d0ef |
||||
# Parent 31adcc4c43916f7448c9dd8048ad5be7e5bb6456 |
||||
Issue #21742: Set stream to None after closing. |
||||
|
||||
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py |
||||
--- a/Lib/logging/handlers.py |
||||
+++ b/Lib/logging/handlers.py |
||||
@@ -423,6 +423,7 @@ class WatchedFileHandler(logging.FileHan |
||||
# we have an open file handle, clean it up |
||||
self.stream.flush() |
||||
self.stream.close() |
||||
+ self.stream = None # See Issue #21742: _open () might fail. |
||||
# open a new file handle and get new stat info from that fd |
||||
self.stream = self._open() |
||||
self._statstream() |
||||
|
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c |
||||
index 997867a..2bd2f55 100644 |
||||
--- a/Modules/fcntlmodule.c |
||||
+++ b/Modules/fcntlmodule.c |
||||
@@ -34,7 +34,7 @@ fcntl_fcntl(PyObject *self, PyObject *args) |
||||
{ |
||||
int fd; |
||||
int code; |
||||
- long arg; |
||||
+ int arg; |
||||
int ret; |
||||
char *str; |
||||
Py_ssize_t len; |
||||
@@ -61,7 +61,7 @@ fcntl_fcntl(PyObject *self, PyObject *args) |
||||
PyErr_Clear(); |
||||
arg = 0; |
||||
if (!PyArg_ParseTuple(args, |
||||
- "O&i|l;fcntl requires a file or file descriptor," |
||||
+ "O&i|I;fcntl requires a file or file descriptor," |
||||
" an integer and optionally a third integer or a string", |
||||
conv_descriptor, &fd, &code, &arg)) { |
||||
return NULL; |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
diff --git a/Lib/imaplib.py b/Lib/imaplib.py |
||||
index 4586fb3..d8243e5 100644 |
||||
--- a/Lib/imaplib.py |
||||
+++ b/Lib/imaplib.py |
||||
@@ -37,11 +37,12 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first |
||||
|
||||
# Maximal line length when calling readline(). This is to prevent |
||||
# reading arbitrary length lines. RFC 3501 and 2060 (IMAP 4rev1) |
||||
-# don't specify a line length. RFC 2683 however suggests limiting client |
||||
-# command lines to 1000 octets and server command lines to 8000 octets. |
||||
-# We have selected 10000 for some extra margin and since that is supposedly |
||||
-# also what UW and Panda IMAP does. |
||||
-_MAXLINE = 10000 |
||||
+# don't specify a line length. RFC 2683 suggests limiting client |
||||
+# command lines to 1000 octets and that servers should be prepared |
||||
+# to accept command lines up to 8000 octets, so we used to use 10K here. |
||||
+# In the modern world (eg: gmail) the response to, for example, a |
||||
+# search command can be quite large, so we now use 1M. |
||||
+_MAXLINE = 1000000 |
||||
|
||||
|
||||
# Commands |
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Benjamin Peterson <benjamin@python.org> |
||||
# Date 1417319735 18000 |
||||
# Node ID 62bd574e95d5ec4b37ca8f72ae6523ea7d6c11cd |
||||
# Parent 1ac5aec658f6972c3372f139ce69ee6799dc0b2e |
||||
add context parameter to xmlrpclib.ServerProxy (#22960) |
||||
|
||||
Patch from Alex Gaynor. |
||||
|
||||
diff --git a/Doc/library/xmlrpclib.rst b/Doc/library/xmlrpclib.rst |
||||
--- a/Doc/library/xmlrpclib.rst |
||||
+++ b/Doc/library/xmlrpclib.rst |
||||
@@ -39,7 +39,7 @@ between conformable Python objects and X |
||||
For https URIs, :mod:`xmlrpclib` now performs all the necessary certificate |
||||
and hostname checks by default |
||||
|
||||
-.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]]) |
||||
+.. class:: ServerProxy(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime[, context]]]]]]) |
||||
|
||||
A :class:`ServerProxy` instance is an object that manages communication with a |
||||
remote XML-RPC server. The required first argument is a URI (Uniform Resource |
||||
@@ -57,11 +57,13 @@ between conformable Python objects and X |
||||
:class:`datetime.datetime` objects may be passed to calls. |
||||
|
||||
Both the HTTP and HTTPS transports support the URL syntax extension for HTTP |
||||
- Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass`` |
||||
+ Basic Authentication: ``http://user:pass@host:port/path``. The ``user:pass`` |
||||
portion will be base64-encoded as an HTTP 'Authorization' header, and sent to |
||||
the remote server as part of the connection process when invoking an XML-RPC |
||||
method. You only need to use this if the remote server requires a Basic |
||||
- Authentication user and password. |
||||
+ Authentication user and password. If an HTTPS url is provided, *context* may |
||||
+ be :class:`ssl.SSLContext` and configures the SSL settings of the underlying |
||||
+ HTTPS connection. |
||||
|
||||
The returned instance is a proxy object with methods that can be used to invoke |
||||
corresponding RPC calls on the remote server. If the remote server supports the |
||||
@@ -131,6 +133,9 @@ between conformable Python objects and X |
||||
*__dict__* attribute and don't have a base class that is marshalled in a |
||||
special way. |
||||
|
||||
+ .. versionchanged:: 2.7.9 |
||||
+ Added the *context* argument. |
||||
+ |
||||
|
||||
.. seealso:: |
||||
|
||||
diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py |
||||
--- a/Lib/xmlrpclib.py |
||||
+++ b/Lib/xmlrpclib.py |
||||
@@ -1478,6 +1478,10 @@ class Transport: |
||||
class SafeTransport(Transport): |
||||
"""Handles an HTTPS transaction to an XML-RPC server.""" |
||||
|
||||
+ def __init__(self, use_datetime=0, context=None): |
||||
+ Transport.__init__(self, use_datetime=use_datetime) |
||||
+ self.context = context |
||||
+ |
||||
# FIXME: mostly untested |
||||
|
||||
def make_connection(self, host): |
||||
@@ -1493,7 +1497,7 @@ class SafeTransport(Transport): |
||||
) |
||||
else: |
||||
chost, self._extra_headers, x509 = self.get_host_info(host) |
||||
- self._connection = host, HTTPS(chost, None, **(x509 or {})) |
||||
+ self._connection = host, HTTPS(chost, None, context=self.context, **(x509 or {})) |
||||
return self._connection[1] |
||||
|
||||
## |
||||
@@ -1536,7 +1540,7 @@ class ServerProxy: |
||||
""" |
||||
|
||||
def __init__(self, uri, transport=None, encoding=None, verbose=0, |
||||
- allow_none=0, use_datetime=0): |
||||
+ allow_none=0, use_datetime=0, context=None): |
||||
# establish a "logical" server connection |
||||
|
||||
if isinstance(uri, unicode): |
||||
@@ -1553,7 +1557,7 @@ class ServerProxy: |
||||
|
||||
if transport is None: |
||||
if type == "https": |
||||
- transport = SafeTransport(use_datetime=use_datetime) |
||||
+ transport = SafeTransport(use_datetime=use_datetime, context=context) |
||||
else: |
||||
transport = Transport(use_datetime=use_datetime) |
||||
self.__transport = transport |
||||
|
||||
|
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
Make it more likely for the system allocator to release free()d memory arenas on glibc-based systems. |
||||
Patch by Charles-François Natali. |
||||
https://bugs.python.org/issue20494 |
||||
|
||||
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c |
||||
--- a/Objects/obmalloc.c |
||||
+++ b/Objects/obmalloc.c |
||||
@@ -2,6 +2,13 @@ |
||||
|
||||
#ifdef WITH_PYMALLOC |
||||
|
||||
+#ifdef HAVE_MMAP |
||||
+ #include <sys/mman.h> |
||||
+ #ifdef MAP_ANONYMOUS |
||||
+ #define ARENAS_USE_MMAP |
||||
+ #endif |
||||
+#endif |
||||
+ |
||||
#ifdef WITH_VALGRIND |
||||
#include <valgrind/valgrind.h> |
||||
|
||||
@@ -75,7 +82,8 @@ static int running_on_valgrind = -1; |
||||
* Allocation strategy abstract: |
||||
* |
||||
* For small requests, the allocator sub-allocates <Big> blocks of memory. |
||||
- * Requests greater than 256 bytes are routed to the system's allocator. |
||||
+ * Requests greater than SMALL_REQUEST_THRESHOLD bytes are routed to the |
||||
+ * system's allocator. |
||||
* |
||||
* Small requests are grouped in size classes spaced 8 bytes apart, due |
||||
* to the required valid alignment of the returned address. Requests of |
||||
@@ -107,10 +115,11 @@ static int running_on_valgrind = -1; |
||||
* 57-64 64 7 |
||||
* 65-72 72 8 |
||||
* ... ... ... |
||||
- * 241-248 248 30 |
||||
- * 249-256 256 31 |
||||
+ * 497-504 504 62 |
||||
+ * 505-512 512 63 |
||||
* |
||||
- * 0, 257 and up: routed to the underlying allocator. |
||||
+ * 0, SMALL_REQUEST_THRESHOLD + 1 and up: routed to the underlying |
||||
+ * allocator. |
||||
*/ |
||||
|
||||
/*==========================================================================*/ |
||||
@@ -143,10 +152,13 @@ static int running_on_valgrind = -1; |
||||
* 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256 |
||||
* 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT |
||||
* |
||||
+ * Note: a size threshold of 512 guarantees that newly created dictionaries |
||||
+ * will be allocated from preallocated memory pools on 64-bit. |
||||
+ * |
||||
* Although not required, for better performance and space efficiency, |
||||
* it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2. |
||||
*/ |
||||
-#define SMALL_REQUEST_THRESHOLD 256 |
||||
+#define SMALL_REQUEST_THRESHOLD 512 |
||||
#define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT) |
||||
|
||||
/* |
||||
@@ -174,15 +186,15 @@ static int running_on_valgrind = -1; |
||||
/* |
||||
* The allocator sub-allocates <Big> blocks of memory (called arenas) aligned |
||||
* on a page boundary. This is a reserved virtual address space for the |
||||
- * current process (obtained through a malloc call). In no way this means |
||||
- * that the memory arenas will be used entirely. A malloc(<Big>) is usually |
||||
- * an address range reservation for <Big> bytes, unless all pages within this |
||||
- * space are referenced subsequently. So malloc'ing big blocks and not using |
||||
- * them does not mean "wasting memory". It's an addressable range wastage... |
||||
+ * current process (obtained through a malloc()/mmap() call). In no way this |
||||
+ * means that the memory arenas will be used entirely. A malloc(<Big>) is |
||||
+ * usually an address range reservation for <Big> bytes, unless all pages within |
||||
+ * this space are referenced subsequently. So malloc'ing big blocks and not |
||||
+ * using them does not mean "wasting memory". It's an addressable range |
||||
+ * wastage... |
||||
* |
||||
- * Therefore, allocating arenas with malloc is not optimal, because there is |
||||
- * some address space wastage, but this is the most portable way to request |
||||
- * memory from the system across various platforms. |
||||
+ * Arenas are allocated with mmap() on systems supporting anonymous memory |
||||
+ * mappings to reduce heap fragmentation. |
||||
*/ |
||||
#define ARENA_SIZE (256 << 10) /* 256KB */ |
||||
|
||||
@@ -440,6 +452,9 @@ static poolp usedpools[2 * ((NB_SMALL_SI |
||||
, PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55) |
||||
#if NB_SMALL_SIZE_CLASSES > 56 |
||||
, PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63) |
||||
+#if NB_SMALL_SIZE_CLASSES > 64 |
||||
+#error "NB_SMALL_SIZE_CLASSES should be less than 64" |
||||
+#endif /* NB_SMALL_SIZE_CLASSES > 64 */ |
||||
#endif /* NB_SMALL_SIZE_CLASSES > 56 */ |
||||
#endif /* NB_SMALL_SIZE_CLASSES > 48 */ |
||||
#endif /* NB_SMALL_SIZE_CLASSES > 40 */ |
||||
@@ -577,7 +592,12 @@ new_arena(void) |
||||
arenaobj = unused_arena_objects; |
||||
unused_arena_objects = arenaobj->nextarena; |
||||
assert(arenaobj->address == 0); |
||||
+#ifdef ARENAS_USE_MMAP |
||||
+ arenaobj->address = (uptr)mmap(NULL, ARENA_SIZE, PROT_READ|PROT_WRITE, |
||||
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
||||
+#else |
||||
arenaobj->address = (uptr)malloc(ARENA_SIZE); |
||||
+#endif |
||||
if (arenaobj->address == 0) { |
||||
/* The allocation failed: return NULL after putting the |
||||
* arenaobj back. |
||||
@@ -1054,7 +1074,11 @@ PyObject_Free(void *p) |
||||
unused_arena_objects = ao; |
||||
|
||||
/* Free the entire arena. */ |
||||
+#ifdef ARENAS_USE_MMAP |
||||
+ munmap((void *)ao->address, ARENA_SIZE); |
||||
+#else |
||||
free((void *)ao->address); |
||||
+#endif |
||||
ao->address = 0; /* mark unassociated */ |
||||
--narenas_currently_allocated; |
||||
|
||||
diff --git a/configure b/configure |
||||
--- a/configure |
||||
+++ b/configure |
||||
@@ -10164,7 +10164,7 @@ for ac_func in alarm setitimer getitimer |
||||
clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \ |
||||
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ |
||||
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ |
||||
- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \ |
||||
+ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \ |
||||
mremap nice pathconf pause plock poll pthread_init \ |
||||
putenv readlink realpath \ |
||||
select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ |
||||
diff --git a/configure.ac b/configure.ac |
||||
--- a/configure.ac |
||||
+++ b/configure.ac |
||||
@@ -2905,7 +2905,7 @@ AC_CHECK_FUNCS(alarm setitimer getitimer |
||||
clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \ |
||||
gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \ |
||||
getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \ |
||||
- initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime \ |
||||
+ initgroups kill killpg lchmod lchown lstat mkfifo mknod mktime mmap \ |
||||
mremap nice pathconf pause plock poll pthread_init \ |
||||
putenv readlink realpath \ |
||||
select sem_open sem_timedwait sem_getvalue sem_unlink setegid seteuid \ |
||||
diff --git a/pyconfig.h.in b/pyconfig.h.in |
||||
--- a/pyconfig.h.in |
||||
+++ b/pyconfig.h.in |
||||
@@ -475,6 +475,9 @@ |
||||
/* Define to 1 if you have the `mktime' function. */ |
||||
#undef HAVE_MKTIME |
||||
|
||||
+/* Define to 1 if you have the `mmap' function. */ |
||||
+#undef HAVE_MMAP |
||||
+ |
||||
/* Define to 1 if you have the `mremap' function. */ |
||||
#undef HAVE_MREMAP |
||||
|
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py |
||||
index bec38c45456..f623aa09620 100644 |
||||
--- a/Lib/test/test_pty.py |
||||
+++ b/Lib/test/test_pty.py |
||||
@@ -11,6 +11,7 @@ |
||||
import select |
||||
import signal |
||||
import socket |
||||
+import io # readline |
||||
import unittest |
||||
|
||||
TEST_STRING_1 = "I wish to buy a fish license.\n" |
||||
@@ -24,6 +25,16 @@ def debug(msg): |
||||
pass |
||||
|
||||
|
||||
+# Note that os.read() is nondeterministic so we need to be very careful |
||||
+# to make the test suite deterministic. A normal call to os.read() may |
||||
+# give us less than expected. |
||||
+# |
||||
+# Beware, on my Linux system, if I put 'foo\n' into a terminal fd, I get |
||||
+# back 'foo\r\n' at the other end. The behavior depends on the termios |
||||
+# setting. The newline translation may be OS-specific. To make the |
||||
+# test suite deterministic and OS-independent, the functions _readline |
||||
+# and normalize_output can be used. |
||||
+ |
||||
def normalize_output(data): |
||||
# Some operating systems do conversions on newline. We could possibly |
||||
# fix that by doing the appropriate termios.tcsetattr()s. I couldn't |
||||
@@ -45,6 +56,12 @@ def normalize_output(data): |
||||
|
||||
return data |
||||
|
||||
+def _readline(fd): |
||||
+ """Read one line. May block forever if no newline is read.""" |
||||
+ reader = io.FileIO(fd, mode='rb', closefd=False) |
||||
+ return reader.readline() |
||||
+ |
||||
+ |
||||
|
||||
# Marginal testing of pty suite. Cannot do extensive 'do or fail' testing |
||||
# because pty code is not too portable. |
||||
@@ -97,14 +114,14 @@ def test_basic(self): |
||||
|
||||
debug("Writing to slave_fd") |
||||
os.write(slave_fd, TEST_STRING_1) |
||||
- s1 = os.read(master_fd, 1024) |
||||
+ s1 = _readline(master_fd) |
||||
self.assertEqual('I wish to buy a fish license.\n', |
||||
normalize_output(s1)) |
||||
|
||||
debug("Writing chunked output") |
||||
os.write(slave_fd, TEST_STRING_2[:5]) |
||||
os.write(slave_fd, TEST_STRING_2[5:]) |
||||
- s2 = os.read(master_fd, 1024) |
||||
+ s2 = _readline(master_fd) |
||||
self.assertEqual('For my pet fish, Eric.\n', normalize_output(s2)) |
||||
|
||||
os.close(slave_fd) |
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c |
||||
index 4a71a57ec0d..2b40ada195a 100644 |
||||
--- a/Modules/_io/fileio.c |
||||
+++ b/Modules/_io/fileio.c |
||||
@@ -146,9 +146,15 @@ dircheck(fileio* self, PyObject *nameobj) |
||||
{ |
||||
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) |
||||
struct stat buf; |
||||
+ int res; |
||||
if (self->fd < 0) |
||||
return 0; |
||||
- if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ res = fstat(self->fd, &buf); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (res == 0 && S_ISDIR(buf.st_mode)) { |
||||
errno = EISDIR; |
||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); |
||||
return -1; |
||||
@@ -162,17 +168,34 @@ check_fd(int fd) |
||||
{ |
||||
#if defined(HAVE_FSTAT) |
||||
struct stat buf; |
||||
- if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { |
||||
- PyObject *exc; |
||||
- char *msg = strerror(EBADF); |
||||
- exc = PyObject_CallFunction(PyExc_OSError, "(is)", |
||||
- EBADF, msg); |
||||
- PyErr_SetObject(PyExc_OSError, exc); |
||||
- Py_XDECREF(exc); |
||||
- return -1; |
||||
+ int res; |
||||
+ PyObject *exc; |
||||
+ char *msg; |
||||
+ |
||||
+ if (!_PyVerify_fd(fd)) { |
||||
+ goto badfd; |
||||
} |
||||
-#endif |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ res = fstat(fd, &buf); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (res < 0 && errno == EBADF) { |
||||
+ goto badfd; |
||||
+ } |
||||
+ |
||||
return 0; |
||||
+ |
||||
+badfd: |
||||
+ msg = strerror(EBADF); |
||||
+ exc = PyObject_CallFunction(PyExc_OSError, "(is)", |
||||
+ EBADF, msg); |
||||
+ PyErr_SetObject(PyExc_OSError, exc); |
||||
+ Py_XDECREF(exc); |
||||
+ return -1; |
||||
+#else |
||||
+ return 0; |
||||
+#endif |
||||
} |
||||
|
||||
|
||||
@@ -519,9 +542,19 @@ new_buffersize(fileio *self, size_t currentsize) |
||||
#ifdef HAVE_FSTAT |
||||
off_t pos, end; |
||||
struct stat st; |
||||
- if (fstat(self->fd, &st) == 0) { |
||||
+ int res; |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ res = fstat(self->fd, &st); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (res == 0) { |
||||
end = st.st_size; |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
pos = lseek(self->fd, 0L, SEEK_CUR); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
/* Files claiming a size smaller than SMALLCHUNK may |
||||
actually be streaming pseudo-files. In this case, we |
||||
apply the more aggressive algorithm below. |
||||
diff --git a/Objects/fileobject.c b/Objects/fileobject.c |
||||
index 2f63c374d1e..8d1c5812f0d 100644 |
||||
--- a/Objects/fileobject.c |
||||
+++ b/Objects/fileobject.c |
||||
@@ -121,10 +121,15 @@ dircheck(PyFileObject* f) |
||||
{ |
||||
#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) |
||||
struct stat buf; |
||||
+ int res; |
||||
if (f->f_fp == NULL) |
||||
return f; |
||||
- if (fstat(fileno(f->f_fp), &buf) == 0 && |
||||
- S_ISDIR(buf.st_mode)) { |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ res = fstat(fileno(f->f_fp), &buf); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (res == 0 && S_ISDIR(buf.st_mode)) { |
||||
char *msg = strerror(EISDIR); |
||||
PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(isO)", |
||||
EISDIR, msg, f->f_name); |
||||
@@ -1010,7 +1015,13 @@ new_buffersize(PyFileObject *f, size_t currentsize) |
||||
#ifdef HAVE_FSTAT |
||||
off_t pos, end; |
||||
struct stat st; |
||||
- if (fstat(fileno(f->f_fp), &st) == 0) { |
||||
+ int res; |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
+ res = fstat(fileno(f->f_fp), &st); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
+ if (res == 0) { |
||||
end = st.st_size; |
||||
/* The following is not a bug: we really need to call lseek() |
||||
*and* ftell(). The reason is that some stdio libraries |
||||
@@ -1021,7 +1032,11 @@ new_buffersize(PyFileObject *f, size_t currentsize) |
||||
works. We can't use the lseek() value either, because we |
||||
need to take the amount of buffered data into account. |
||||
(Yet another reason why stdio stinks. :-) */ |
||||
+ |
||||
+ Py_BEGIN_ALLOW_THREADS |
||||
pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR); |
||||
+ Py_END_ALLOW_THREADS |
||||
+ |
||||
if (pos >= 0) { |
||||
pos = ftell(f->f_fp); |
||||
} |
@ -0,0 +1,250 @@
@@ -0,0 +1,250 @@
|
||||
diff --git a/Lib/httplib.py b/Lib/httplib.py |
||||
index 592ee57..b69145b 100644 |
||||
--- a/Lib/httplib.py |
||||
+++ b/Lib/httplib.py |
||||
@@ -735,25 +735,40 @@ class HTTPConnection: |
||||
self._tunnel_host = None |
||||
self._tunnel_port = None |
||||
self._tunnel_headers = {} |
||||
- |
||||
- self._set_hostport(host, port) |
||||
if strict is not None: |
||||
self.strict = strict |
||||
|
||||
+ (self.host, self.port) = self._get_hostport(host, port) |
||||
+ |
||||
+ # This is stored as an instance variable to allow unittests |
||||
+ # to replace with a suitable mock |
||||
+ self._create_connection = socket.create_connection |
||||
+ |
||||
def set_tunnel(self, host, port=None, headers=None): |
||||
- """ Sets up the host and the port for the HTTP CONNECT Tunnelling. |
||||
+ """ Set up host and port for HTTP CONNECT tunnelling. |
||||
+ |
||||
+ In a connection that uses HTTP Connect tunneling, the host passed to the |
||||
+ constructor is used as proxy server that relays all communication to the |
||||
+ endpoint passed to set_tunnel. This is done by sending a HTTP CONNECT |
||||
+ request to the proxy server when the connection is established. |
||||
+ |
||||
+ This method must be called before the HTTP connection has been |
||||
+ established. |
||||
|
||||
The headers argument should be a mapping of extra HTTP headers |
||||
to send with the CONNECT request. |
||||
""" |
||||
- self._tunnel_host = host |
||||
- self._tunnel_port = port |
||||
+ # Verify if this is required. |
||||
+ if self.sock: |
||||
+ raise RuntimeError("Can't setup tunnel for established connection.") |
||||
+ |
||||
+ self._tunnel_host, self._tunnel_port = self._get_hostport(host, port) |
||||
if headers: |
||||
self._tunnel_headers = headers |
||||
else: |
||||
self._tunnel_headers.clear() |
||||
|
||||
- def _set_hostport(self, host, port): |
||||
+ def _get_hostport(self, host, port): |
||||
if port is None: |
||||
i = host.rfind(':') |
||||
j = host.rfind(']') # ipv6 addresses have [...] |
||||
@@ -770,15 +785,14 @@ class HTTPConnection: |
||||
port = self.default_port |
||||
if host and host[0] == '[' and host[-1] == ']': |
||||
host = host[1:-1] |
||||
- self.host = host |
||||
- self.port = port |
||||
+ return (host, port) |
||||
|
||||
def set_debuglevel(self, level): |
||||
self.debuglevel = level |
||||
|
||||
def _tunnel(self): |
||||
- self._set_hostport(self._tunnel_host, self._tunnel_port) |
||||
- self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port)) |
||||
+ self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self._tunnel_host, |
||||
+ self._tunnel_port)) |
||||
for header, value in self._tunnel_headers.iteritems(): |
||||
self.send("%s: %s\r\n" % (header, value)) |
||||
self.send("\r\n") |
||||
@@ -803,8 +817,8 @@ class HTTPConnection: |
||||
|
||||
def connect(self): |
||||
"""Connect to the host and port specified in __init__.""" |
||||
- self.sock = socket.create_connection((self.host,self.port), |
||||
- self.timeout, self.source_address) |
||||
+ self.sock = self._create_connection((self.host,self.port), |
||||
+ self.timeout, self.source_address) |
||||
|
||||
if self._tunnel_host: |
||||
self._tunnel() |
||||
@@ -942,17 +956,24 @@ class HTTPConnection: |
||||
netloc_enc = netloc.encode("idna") |
||||
self.putheader('Host', netloc_enc) |
||||
else: |
||||
+ if self._tunnel_host: |
||||
+ host = self._tunnel_host |
||||
+ port = self._tunnel_port |
||||
+ else: |
||||
+ host = self.host |
||||
+ port = self.port |
||||
+ |
||||
try: |
||||
- host_enc = self.host.encode("ascii") |
||||
+ host_enc = host.encode("ascii") |
||||
except UnicodeEncodeError: |
||||
- host_enc = self.host.encode("idna") |
||||
+ host_enc = host.encode("idna") |
||||
# Wrap the IPv6 Host Header with [] (RFC 2732) |
||||
if host_enc.find(':') >= 0: |
||||
host_enc = "[" + host_enc + "]" |
||||
- if self.port == self.default_port: |
||||
+ if port == self.default_port: |
||||
self.putheader('Host', host_enc) |
||||
else: |
||||
- self.putheader('Host', "%s:%s" % (host_enc, self.port)) |
||||
+ self.putheader('Host', "%s:%s" % (host_enc, port)) |
||||
|
||||
# note: we are assuming that clients will not attempt to set these |
||||
# headers since *this* library must deal with the |
||||
@@ -1141,7 +1162,7 @@ class HTTP: |
||||
"Accept arguments to set the host/port, since the superclass doesn't." |
||||
|
||||
if host is not None: |
||||
- self._conn._set_hostport(host, port) |
||||
+ (self._conn.host, self._conn.port) = self._conn._get_hostport(host, port) |
||||
self._conn.connect() |
||||
|
||||
def getfile(self): |
||||
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py |
||||
index 29af589..9db30cc 100644 |
||||
--- a/Lib/test/test_httplib.py |
||||
+++ b/Lib/test/test_httplib.py |
||||
@@ -21,10 +21,12 @@ CERT_selfsigned_pythontestdotnet = os.path.join(here, 'selfsigned_pythontestdotn |
||||
HOST = test_support.HOST |
||||
|
||||
class FakeSocket: |
||||
- def __init__(self, text, fileclass=StringIO.StringIO): |
||||
+ def __init__(self, text, fileclass=StringIO.StringIO, host=None, port=None): |
||||
self.text = text |
||||
self.fileclass = fileclass |
||||
self.data = '' |
||||
+ self.host = host |
||||
+ self.port = port |
||||
|
||||
def sendall(self, data): |
||||
self.data += ''.join(data) |
||||
@@ -34,6 +36,9 @@ class FakeSocket: |
||||
raise httplib.UnimplementedFileMode() |
||||
return self.fileclass(self.text) |
||||
|
||||
+ def close(self): |
||||
+ pass |
||||
+ |
||||
class EPipeSocket(FakeSocket): |
||||
|
||||
def __init__(self, text, pipe_trigger): |
||||
@@ -487,7 +492,11 @@ class OfflineTest(TestCase): |
||||
self.assertEqual(httplib.responses[httplib.NOT_FOUND], "Not Found") |
||||
|
||||
|
||||
-class SourceAddressTest(TestCase): |
||||
+class TestServerMixin: |
||||
+ """A limited socket server mixin. |
||||
+ |
||||
+ This is used by test cases for testing http connection end points. |
||||
+ """ |
||||
def setUp(self): |
||||
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
self.port = test_support.bind_port(self.serv) |
||||
@@ -502,6 +511,7 @@ class SourceAddressTest(TestCase): |
||||
self.serv.close() |
||||
self.serv = None |
||||
|
||||
+class SourceAddressTest(TestServerMixin, TestCase): |
||||
def testHTTPConnectionSourceAddress(self): |
||||
self.conn = httplib.HTTPConnection(HOST, self.port, |
||||
source_address=('', self.source_port)) |
||||
@@ -518,6 +528,24 @@ class SourceAddressTest(TestCase): |
||||
# for an ssl_wrapped connect() to actually return from. |
||||
|
||||
|
||||
+class HTTPTest(TestServerMixin, TestCase): |
||||
+ def testHTTPConnection(self): |
||||
+ self.conn = httplib.HTTP(host=HOST, port=self.port, strict=None) |
||||
+ self.conn.connect() |
||||
+ self.assertEqual(self.conn._conn.host, HOST) |
||||
+ self.assertEqual(self.conn._conn.port, self.port) |
||||
+ |
||||
+ def testHTTPWithConnectHostPort(self): |
||||
+ testhost = 'unreachable.test.domain' |
||||
+ testport = '80' |
||||
+ self.conn = httplib.HTTP(host=testhost, port=testport) |
||||
+ self.conn.connect(host=HOST, port=self.port) |
||||
+ self.assertNotEqual(self.conn._conn.host, testhost) |
||||
+ self.assertNotEqual(self.conn._conn.port, testport) |
||||
+ self.assertEqual(self.conn._conn.host, HOST) |
||||
+ self.assertEqual(self.conn._conn.port, self.port) |
||||
+ |
||||
+ |
||||
class TimeoutTest(TestCase): |
||||
PORT = None |
||||
|
||||
@@ -716,13 +744,54 @@ class HTTPSTest(TestCase): |
||||
c = httplib.HTTPSConnection(hp, context=context) |
||||
self.assertEqual(h, c.host) |
||||
self.assertEqual(p, c.port) |
||||
- |
||||
+ |
||||
+class TunnelTests(TestCase): |
||||
+ def test_connect(self): |
||||
+ response_text = ( |
||||
+ 'HTTP/1.0 200 OK\r\n\r\n' # Reply to CONNECT |
||||
+ 'HTTP/1.1 200 OK\r\n' # Reply to HEAD |
||||
+ 'Content-Length: 42\r\n\r\n' |
||||
+ ) |
||||
+ |
||||
+ def create_connection(address, timeout=None, source_address=None): |
||||
+ return FakeSocket(response_text, host=address[0], port=address[1]) |
||||
+ |
||||
+ conn = httplib.HTTPConnection('proxy.com') |
||||
+ conn._create_connection = create_connection |
||||
+ |
||||
+ # Once connected, we should not be able to tunnel anymore |
||||
+ conn.connect() |
||||
+ self.assertRaises(RuntimeError, conn.set_tunnel, 'destination.com') |
||||
+ |
||||
+ # But if close the connection, we are good. |
||||
+ conn.close() |
||||
+ conn.set_tunnel('destination.com') |
||||
+ conn.request('HEAD', '/', '') |
||||
+ |
||||
+ self.assertEqual(conn.sock.host, 'proxy.com') |
||||
+ self.assertEqual(conn.sock.port, 80) |
||||
+ self.assertIn('CONNECT destination.com', conn.sock.data) |
||||
+ # issue22095 |
||||
+ self.assertNotIn('Host: destination.com:None', conn.sock.data) |
||||
+ # issue22095 |
||||
+ |
||||
+ self.assertNotIn('Host: proxy.com', conn.sock.data) |
||||
+ |
||||
+ conn.close() |
||||
+ |
||||
+ conn.request('PUT', '/', '') |
||||
+ self.assertEqual(conn.sock.host, 'proxy.com') |
||||
+ self.assertEqual(conn.sock.port, 80) |
||||
+ self.assertTrue('CONNECT destination.com' in conn.sock.data) |
||||
+ self.assertTrue('Host: destination.com' in conn.sock.data) |
||||
+ |
||||
|
||||
|
||||
@test_support.reap_threads |
||||
def test_main(verbose=None): |
||||
test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest, |
||||
- HTTPSTest, SourceAddressTest) |
||||
+ HTTPTest, HTTPSTest, SourceAddressTest, |
||||
+ TunnelTests) |
||||
|
||||
if __name__ == '__main__': |
||||
test_main() |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
From 8a91bb4ea0a7f50d024fe55014c2e86e36e67751 Mon Sep 17 00:00:00 2001 |
||||
From: Tomas Orsava <torsava@redhat.com> |
||||
Date: Mon, 19 Feb 2018 14:42:13 +0100 |
||||
Subject: [PATCH] Readd the private `_set_hostport` api to httplib |
||||
|
||||
--- |
||||
Lib/httplib.py | 3 +++ |
||||
1 file changed, 3 insertions(+) |
||||
|
||||
diff --git a/Lib/httplib.py b/Lib/httplib.py |
||||
index b69145b..da2f346 100644 |
||||
--- a/Lib/httplib.py |
||||
+++ b/Lib/httplib.py |
||||
@@ -787,6 +787,9 @@ class HTTPConnection: |
||||
host = host[1:-1] |
||||
return (host, port) |
||||
|
||||
+ def _set_hostport(self, host, port): |
||||
+ (self.host, self.port) = self._get_hostport(host, port) |
||||
+ |
||||
def set_debuglevel(self, level): |
||||
self.debuglevel = level |
||||
|
||||
-- |
||||
2.13.6 |
||||
|
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
index d0a3830..51b192c 100644 |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -50,6 +50,11 @@ |
||||
#include <sys/poll.h> |
||||
#endif |
||||
|
||||
+#ifndef MS_WINDOWS |
||||
+/* inet_pton */ |
||||
+#include <arpa/inet.h> |
||||
+#endif |
||||
+ |
||||
/* Include OpenSSL header files */ |
||||
#include "openssl/rsa.h" |
||||
#include "openssl/crypto.h" |
||||
@@ -493,8 +498,41 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, |
||||
SSL_set_mode(self->ssl, mode); |
||||
|
||||
#if HAVE_SNI |
||||
- if (server_hostname != NULL) |
||||
- SSL_set_tlsext_host_name(self->ssl, server_hostname); |
||||
+ if (server_hostname != NULL) { |
||||
+/* Don't send SNI for IP addresses. We cannot simply use inet_aton() and |
||||
+ * inet_pton() here. inet_aton() may be linked weakly and inet_pton() isn't |
||||
+ * available on all platforms. Use OpenSSL's IP address parser. It's |
||||
+ * available since 1.0.2 and LibreSSL since at least 2.3.0. */ |
||||
+ int send_sni = 1; |
||||
+#if OPENSSL_VERSION_NUMBER >= 0x10200000L |
||||
+ ASN1_OCTET_STRING *ip = a2i_IPADDRESS(server_hostname); |
||||
+ if (ip == NULL) { |
||||
+ send_sni = 1; |
||||
+ ERR_clear_error(); |
||||
+ } else { |
||||
+ send_sni = 0; |
||||
+ ASN1_OCTET_STRING_free(ip); |
||||
+ } |
||||
+#elif defined(HAVE_INET_PTON) |
||||
+#ifdef ENABLE_IPV6 |
||||
+ char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; |
||||
+#else |
||||
+ char packed[sizeof(struct in_addr)]; |
||||
+#endif /* ENABLE_IPV6 */ |
||||
+ if (inet_pton(AF_INET, server_hostname, packed)) { |
||||
+ send_sni = 0; |
||||
+#ifdef ENABLE_IPV6 |
||||
+ } else if(inet_pton(AF_INET6, server_hostname, packed)) { |
||||
+ send_sni = 0; |
||||
+#endif /* ENABLE_IPV6 */ |
||||
+ } else { |
||||
+ send_sni = 1; |
||||
+ } |
||||
+#endif /* HAVE_INET_PTON */ |
||||
+ if (send_sni) { |
||||
+ SSL_set_tlsext_host_name(self->ssl, server_hostname); |
||||
+ } |
||||
+ } |
||||
#endif |
||||
|
||||
/* If the socket is in non-blocking mode or timeout mode, set the BIO |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
From 439956a149f8a3eb44646498c63b2ef3337d5f3d Mon Sep 17 00:00:00 2001 |
||||
From: Christian Heimes <christian@python.org> |
||||
Date: Sun, 25 Feb 2018 13:08:05 +0100 |
||||
Subject: [PATCH] Fix ssl module, Python 2.7 doesn't have Py_MAX (#5878) |
||||
|
||||
Signed-off-by: Christian Heimes <christian@python.org> |
||||
--- |
||||
Modules/_ssl.c | 3 ++- |
||||
1 file changed, 2 insertions(+), 1 deletion(-) |
||||
|
||||
diff --git a/Modules/_ssl.c b/Modules/_ssl.c |
||||
index af66a581e15a..f9ed94dee1e1 100644 |
||||
--- a/Modules/_ssl.c |
||||
+++ b/Modules/_ssl.c |
||||
@@ -610,7 +610,8 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, |
||||
} |
||||
#elif defined(HAVE_INET_PTON) |
||||
#ifdef ENABLE_IPV6 |
||||
- char packed[Py_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; |
||||
+ #define PySSL_MAX(x, y) (((x) > (y)) ? (x) : (y)) |
||||
+ char packed[PySSL_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; |
||||
#else |
||||
char packed[sizeof(struct in_addr)]; |
||||
#endif /* ENABLE_IPV6 */ |
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
diff --git a/Lib/difflib.py b/Lib/difflib.py |
||||
index 1c6fbdbedcb7..788a92df3f89 100644 |
||||
--- a/Lib/difflib.py |
||||
+++ b/Lib/difflib.py |
||||
@@ -1103,7 +1103,7 @@ def _qformat(self, aline, bline, atags, btags): |
||||
|
||||
import re |
||||
|
||||
-def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match): |
||||
+def IS_LINE_JUNK(line, pat=re.compile(r"\s*(?:#\s*)?$").match): |
||||
r""" |
||||
Return 1 for ignorable line: iff `line` is blank or contains a single '#'. |
||||
|
||||
diff --git a/Lib/poplib.py b/Lib/poplib.py |
||||
index b91e5f72d2ca..a238510b38fc 100644 |
||||
--- a/Lib/poplib.py |
||||
+++ b/Lib/poplib.py |
||||
@@ -274,7 +274,7 @@ def rpop(self, user): |
||||
return self._shortcmd('RPOP %s' % user) |
||||
|
||||
|
||||
- timestamp = re.compile(r'\+OK.*(<[^>]+>)') |
||||
+ timestamp = re.compile(br'\+OK.[^<]*(<.*>)') |
||||
|
||||
def apop(self, user, secret): |
||||
"""Authorisation |
||||
diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py |
||||
index 35f2c36ca70a..d8277b79b880 100644 |
||||
--- a/Lib/test/test_difflib.py |
||||
+++ b/Lib/test/test_difflib.py |
||||
@@ -269,13 +269,33 @@ def test_range_format_context(self): |
||||
self.assertEqual(fmt(3,6), '4,6') |
||||
self.assertEqual(fmt(0,0), '0') |
||||
|
||||
+class TestJunkAPIs(unittest.TestCase): |
||||
+ def test_is_line_junk_true(self): |
||||
+ for line in ['#', ' ', ' #', '# ', ' # ', '']: |
||||
+ self.assertTrue(difflib.IS_LINE_JUNK(line), repr(line)) |
||||
+ |
||||
+ def test_is_line_junk_false(self): |
||||
+ for line in ['##', ' ##', '## ', 'abc ', 'abc #', 'Mr. Moose is up!']: |
||||
+ self.assertFalse(difflib.IS_LINE_JUNK(line), repr(line)) |
||||
+ |
||||
+ def test_is_line_junk_REDOS(self): |
||||
+ evil_input = ('\t' * 1000000) + '##' |
||||
+ self.assertFalse(difflib.IS_LINE_JUNK(evil_input)) |
||||
+ |
||||
+ def test_is_character_junk_true(self): |
||||
+ for char in [' ', '\t']: |
||||
+ self.assertTrue(difflib.IS_CHARACTER_JUNK(char), repr(char)) |
||||
+ |
||||
+ def test_is_character_junk_false(self): |
||||
+ for char in ['a', '#', '\n', '\f', '\r', '\v']: |
||||
+ self.assertFalse(difflib.IS_CHARACTER_JUNK(char), repr(char)) |
||||
|
||||
def test_main(): |
||||
difflib.HtmlDiff._default_prefix = 0 |
||||
Doctests = doctest.DocTestSuite(difflib) |
||||
run_unittest( |
||||
TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs, |
||||
- TestOutputFormat, Doctests) |
||||
+ TestOutputFormat, TestJunkAPIs) |
||||
|
||||
if __name__ == '__main__': |
||||
test_main() |
||||
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py |
||||
index 23d688724b95..d2143759ba66 100644 |
||||
--- a/Lib/test/test_poplib.py |
||||
+++ b/Lib/test/test_poplib.py |
||||
@@ -211,6 +211,16 @@ def test_noop(self): |
||||
def test_rpop(self): |
||||
self.assertOK(self.client.rpop('foo')) |
||||
|
||||
+ def test_apop_REDOS(self): |
||||
+ # Replace welcome with very long evil welcome. |
||||
+ # NB The upper bound on welcome length is currently 2048. |
||||
+ # At this length, evil input makes each apop call take |
||||
+ # on the order of milliseconds instead of microseconds. |
||||
+ evil_welcome = b'+OK' + (b'<' * 1000000) |
||||
+ with test_support.swap_attr(self.client, 'welcome', evil_welcome): |
||||
+ # The evil welcome is invalid, so apop should throw. |
||||
+ self.assertRaises(poplib.error_proto, self.client.apop, 'a', 'kb') |
||||
+ |
||||
def test_top(self): |
||||
expected = ('+OK 116 bytes', |
||||
['From: postmaster@python.org', 'Content-Type: text/plain', |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
diff --git a/Lib/ssl.py b/Lib/ssl.py |
||||
index 038daa4..5311321 100644 |
||||
--- a/Lib/ssl.py |
||||
+++ b/Lib/ssl.py |
||||
@@ -143,38 +143,36 @@ if _ssl.HAS_TLS_UNIQUE: |
||||
else: |
||||
CHANNEL_BINDING_TYPES = [] |
||||
|
||||
+ |
||||
# Disable weak or insecure ciphers by default |
||||
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL') |
||||
# Enable a better set of ciphers by default |
||||
# This list has been explicitly chosen to: |
||||
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) |
||||
# * Prefer ECDHE over DHE for better performance |
||||
-# * Prefer any AES-GCM over any AES-CBC for better performance and security |
||||
+# * Prefer AEAD over CBC for better performance and security |
||||
# * Then Use HIGH cipher suites as a fallback |
||||
-# * Then Use 3DES as fallback which is secure but slow |
||||
# * Finally use RC4 as a fallback which is problematic but needed for |
||||
# compatibility some times. |
||||
-# * Disable NULL authentication, NULL encryption, and MD5 MACs for security |
||||
-# reasons |
||||
+# * Disable NULL authentication, NULL encryption, 3DES and MD5 MACs |
||||
+# for security reasons |
||||
_DEFAULT_CIPHERS = ( |
||||
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' |
||||
- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:' |
||||
- 'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5' |
||||
+ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:ECDH+RC4:DH+RC4:RSA+RC4:!aNULL:!eNULL:' |
||||
+ '!MD5:!3DES' |
||||
) |
||||
|
||||
# Restricted and more secure ciphers for the server side |
||||
# This list has been explicitly chosen to: |
||||
# * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE) |
||||
# * Prefer ECDHE over DHE for better performance |
||||
-# * Prefer any AES-GCM over any AES-CBC for better performance and security |
||||
+# * Prefer AEAD over CBC for better performance and security |
||||
# * Then Use HIGH cipher suites as a fallback |
||||
-# * Then Use 3DES as fallback which is secure but slow |
||||
-# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, and RC4 for |
||||
-# security reasons |
||||
+# * Disable NULL authentication, NULL encryption, MD5 MACs, DSS, RC4, and |
||||
+# 3DES for security reasons |
||||
_RESTRICTED_SERVER_CIPHERS = ( |
||||
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:' |
||||
- 'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:' |
||||
- '!eNULL:!MD5:!DSS:!RC4' |
||||
+ 'DH+HIGH:RSA+AESGCM:RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!DSS:!RC4:!3DES' |
||||
) |
||||
|
||||
|
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
|
||||
# HG changeset patch |
||||
# User Charles-François Natali <cf.natali@gmail.com> |
||||
# Date 1455316761 0 |
||||
# Node ID d3662c088db8fb2c89f754031f18b1543419fed9 |
||||
# Parent 5715a6d9ff12053e81f7ad75268ac059b079b351 |
||||
Issue #24303: Fix random EEXIST upon multiprocessing semaphores creation with |
||||
Linux PID namespaces enabled. |
||||
|
||||
diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c |
||||
--- a/Modules/_multiprocessing/semaphore.c |
||||
+++ b/Modules/_multiprocessing/semaphore.c |
||||
@@ -429,7 +429,7 @@ semlock_new(PyTypeObject *type, PyObject |
||||
int kind, maxvalue, value; |
||||
PyObject *result; |
||||
static char *kwlist[] = {"kind", "value", "maxvalue", NULL}; |
||||
- static int counter = 0; |
||||
+ int try = 0; |
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist, |
||||
&kind, &value, &maxvalue)) |
||||
@@ -440,10 +440,18 @@ semlock_new(PyTypeObject *type, PyObject |
||||
return NULL; |
||||
} |
||||
|
||||
- PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++); |
||||
+ /* Create a semaphore with a unique name. The bytes returned by |
||||
+ * _PyOS_URandom() are treated as unsigned long to ensure that the filename |
||||
+ * is valid (no special characters). */ |
||||
+ do { |
||||
+ unsigned long suffix; |
||||
+ _PyOS_URandom((char *)&suffix, sizeof(suffix)); |
||||
+ PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%lu", (long)getpid(), |
||||
+ suffix); |
||||
+ SEM_CLEAR_ERROR(); |
||||
+ handle = SEM_CREATE(buffer, value, maxvalue); |
||||
+ } while ((handle == SEM_FAILED) && (errno == EEXIST) && (++try < 100)); |
||||
|
||||
- SEM_CLEAR_ERROR(); |
||||
- handle = SEM_CREATE(buffer, value, maxvalue); |
||||
/* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ |
||||
if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) |
||||
goto failure; |
||||
|
@ -0,0 +1,216 @@
@@ -0,0 +1,216 @@
|
||||
diff -up ./configure.autotool-intermediates ./configure |
||||
--- ./configure.autotool-intermediates 2013-04-09 11:24:01.024185796 +0200 |
||||
+++ ./configure 2013-04-09 11:24:01.780183954 +0200 |
||||
@@ -639,6 +639,8 @@ TRUE |
||||
MACHDEP_OBJS |
||||
DYNLOADFILE |
||||
DLINCLDIR |
||||
+DTRACEHDRS |
||||
+DTRACEOBJS |
||||
THREADOBJ |
||||
LDLAST |
||||
USE_THREAD_MODULE |
||||
@@ -659,6 +661,8 @@ OTHER_LIBTOOL_OPT |
||||
UNIVERSAL_ARCH_FLAGS |
||||
BASECFLAGS |
||||
OPT |
||||
+DEBUG_SUFFIX |
||||
+DEBUG_EXT |
||||
LN |
||||
MKDIR_P |
||||
INSTALL_DATA |
||||
@@ -795,8 +799,11 @@ with_pth |
||||
enable_ipv6 |
||||
with_doc_strings |
||||
with_tsc |
||||
+with_count_allocs |
||||
+with_call_profile |
||||
with_pymalloc |
||||
with_valgrind |
||||
+with_dtrace |
||||
with_wctype_functions |
||||
with_fpectl |
||||
with_libm |
||||
@@ -1472,8 +1479,11 @@ Optional Packages: |
||||
--with-pth use GNU pth threading libraries |
||||
--with(out)-doc-strings disable/enable documentation strings |
||||
--with(out)-tsc enable/disable timestamp counter profile |
||||
+ --with(out)count-allocs enable/disable per-type instance accounting |
||||
+ --with(out)-call-profile enable/disable statistics on function call invocation |
||||
--with(out)-pymalloc disable/enable specialized mallocs |
||||
--with-valgrind Enable Valgrind support |
||||
+ --with(out)-dtrace disable/enable dtrace support |
||||
--with-wctype-functions use wctype.h functions |
||||
--with-fpectl enable SIGFPE catching |
||||
--with-libm=STRING math library |
||||
@@ -5171,7 +5181,7 @@ esac |
||||
$as_echo_n "checking LIBRARY... " >&6; } |
||||
if test -z "$LIBRARY" |
||||
then |
||||
- LIBRARY='libpython$(VERSION).a' |
||||
+ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a' |
||||
fi |
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBRARY" >&5 |
||||
$as_echo "$LIBRARY" >&6; } |
||||
@@ -5343,8 +5353,8 @@ $as_echo "#define Py_ENABLE_SHARED 1" >> |
||||
INSTSONAME="$LDLIBRARY".$SOVERSION |
||||
;; |
||||
Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*) |
||||
- LDLIBRARY='libpython$(VERSION).so' |
||||
- BLDLIBRARY='-L. -lpython$(VERSION)' |
||||
+ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so' |
||||
+ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)' |
||||
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} |
||||
case $ac_sys_system in |
||||
FreeBSD*) |
||||
@@ -5367,7 +5377,7 @@ $as_echo "#define Py_ENABLE_SHARED 1" >> |
||||
;; |
||||
OSF*) |
||||
LDLIBRARY='libpython$(VERSION).so' |
||||
- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)' |
||||
+ BLDLIBRARY='-L. -lpython$(VERSION)' |
||||
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} |
||||
;; |
||||
atheos*) |
||||
@@ -5894,6 +5904,14 @@ $as_echo "no" >&6; } |
||||
fi |
||||
|
||||
|
||||
+if test "$Py_DEBUG" = 'true' |
||||
+then |
||||
+ DEBUG_EXT=_d |
||||
+ DEBUG_SUFFIX=-debug |
||||
+fi |
||||
+ |
||||
+ |
||||
+ |
||||
# XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be |
||||
# merged with this chunk of code? |
||||
|
||||
@@ -9958,6 +9976,50 @@ $as_echo "no" >&6; } |
||||
fi |
||||
|
||||
|
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-count-allocs" >&5 |
||||
+$as_echo_n "checking for --with-count-allocs... " >&6; } |
||||
+ |
||||
+# Check whether --with-count-allocs was given. |
||||
+if test "${with_count_allocs+set}" = set; then : |
||||
+ withval=$with_count_allocs; |
||||
+if test "$withval" != no |
||||
+then |
||||
+ |
||||
+$as_echo "#define COUNT_ALLOCS 1" >>confdefs.h |
||||
+ |
||||
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 |
||||
+$as_echo "yes" >&6; } |
||||
+else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
||||
+$as_echo "no" >&6; } |
||||
+fi |
||||
+else |
||||
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
||||
+$as_echo "no" >&6; } |
||||
+fi |
||||
+ |
||||
+ |
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-call-profile" >&5 |
||||
+$as_echo_n "checking for --with-call-profile... " >&6; } |
||||
+ |
||||
+# Check whether --with-call-profile was given. |
||||
+if test "${with_call_profile+set}" = set; then : |
||||
+ withval=$with_call_profile; |
||||
+if test "$withval" != no |
||||
+then |
||||
+ |
||||
+$as_echo "#define CALL_PROFILE 1" >>confdefs.h |
||||
+ |
||||
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 |
||||
+$as_echo "yes" >&6; } |
||||
+else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
||||
+$as_echo "no" >&6; } |
||||
+fi |
||||
+else |
||||
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
||||
+$as_echo "no" >&6; } |
||||
+fi |
||||
+ |
||||
+ |
||||
# Check for Python-specific malloc support |
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc" >&5 |
||||
$as_echo_n "checking for --with-pymalloc... " >&6; } |
||||
@@ -10007,6 +10069,46 @@ fi |
||||
|
||||
fi |
||||
|
||||
+# Check for dtrace support |
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-dtrace" >&5 |
||||
+$as_echo_n "checking for --with-dtrace... " >&6; } |
||||
+ |
||||
+# Check whether --with-dtrace was given. |
||||
+if test "${with_dtrace+set}" = set; then : |
||||
+ withval=$with_dtrace; |
||||
+fi |
||||
+ |
||||
+ |
||||
+if test ! -z "$with_dtrace" |
||||
+then |
||||
+ if dtrace -G -o /dev/null -s $srcdir/Include/pydtrace.d 2>/dev/null |
||||
+ then |
||||
+ |
||||
+$as_echo "#define WITH_DTRACE 1" >>confdefs.h |
||||
+ |
||||
+ with_dtrace="Sun" |
||||
+ DTRACEOBJS="Python/dtrace.o" |
||||
+ DTRADEHDRS="" |
||||
+ elif dtrace -h -o /dev/null -s $srcdir/Include/pydtrace.d |
||||
+ then |
||||
+ |
||||
+$as_echo "#define WITH_DTRACE 1" >>confdefs.h |
||||
+ |
||||
+ with_dtrace="Apple" |
||||
+ DTRACEOBJS="" |
||||
+ DTRADEHDRS="pydtrace.h" |
||||
+ else |
||||
+ with_dtrace="no" |
||||
+ fi |
||||
+else |
||||
+ with_dtrace="no" |
||||
+fi |
||||
+ |
||||
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_dtrace" >&5 |
||||
+$as_echo "$with_dtrace" >&6; } |
||||
+ |
||||
+ |
||||
+ |
||||
# Check for --with-wctype-functions |
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-wctype-functions" >&5 |
||||
$as_echo_n "checking for --with-wctype-functions... " >&6; } |
||||
diff -up ./pyconfig.h.in.autotool-intermediates ./pyconfig.h.in |
||||
--- ./pyconfig.h.in.autotool-intermediates 2013-04-09 11:24:01.020185806 +0200 |
||||
+++ ./pyconfig.h.in 2013-04-09 11:24:02.088183204 +0200 |
||||
@@ -18,6 +18,12 @@ |
||||
/* Define this if you have BeOS threads. */ |
||||
#undef BEOS_THREADS |
||||
|
||||
+/* Define to keep records on function call invocation */ |
||||
+#undef CALL_PROFILE |
||||
+ |
||||
+/* Define to keep records of the number of instances of each type */ |
||||
+#undef COUNT_ALLOCS |
||||
+ |
||||
/* Define if you have the Mach cthreads package */ |
||||
#undef C_THREADS |
||||
|
||||
@@ -1119,12 +1125,6 @@ |
||||
/* Define to profile with the Pentium timestamp counter */ |
||||
#undef WITH_TSC |
||||
|
||||
-/* Define to keep records of the number of instances of each type */ |
||||
-#undef COUNT_ALLOCS |
||||
- |
||||
-/* Define to keep records on function call invocation */ |
||||
-#undef CALL_PROFILE |
||||
- |
||||
/* Define if you want pymalloc to be disabled when running under valgrind */ |
||||
#undef WITH_VALGRIND |
||||
|
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
# Possible values are: |
||||
# 'enable' to ensure HTTPS certificate verification is enabled by default |
||||
# 'disable' to ensure HTTPS certificate verification is disabled by default |
||||
# 'platform_default' to delegate the decision to the redistributor providing this particular Python version |
||||
|
||||
# For more info refer to https://www.python.org/dev/peps/pep-0493/ |
||||
[https] |
||||
verify=platform_default |
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
%py_setup setup.py |
||||
%py_shbang_opts -s |
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as |
||||
# the macro |
||||
%py_build() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py_shbang_opts}" %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py_build_egg() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_egg %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py_build_wheel() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} bdist_wheel %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py_install() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*} |
||||
} |
||||
|
||||
%py_install_egg() %{expand:\\\ |
||||
mkdir -p %{buildroot}%{python_sitelib} |
||||
easy_install -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python_version}.egg %{?*} |
||||
} |
||||
|
||||
%py_install_wheel() %{expand:\\\ |
||||
pip install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps |
||||
} |
||||
|
||||
%python_provide() %{lua: |
||||
function string.starts(String,Start) |
||||
return string.sub(String,1,string.len(Start))==Start |
||||
end |
||||
package = rpm.expand("%{?1}") |
||||
vr = rpm.expand("%{?epoch:%{epoch}:}%{version}-%{release}") |
||||
if (string.starts(package, "python2-")) then |
||||
if (rpm.expand("%{?buildarch}") ~= "noarch") then |
||||
str = "Provides: python-" .. string.sub(package,9,string.len(package)) .. "%{?_isa} = " .. vr |
||||
print(rpm.expand(str)) |
||||
end |
||||
print("\\nProvides: python-") |
||||
print(string.sub(package,9,string.len(package))) |
||||
print(" = ") |
||||
print(vr) |
||||
--Obsoleting the previous default python package |
||||
print("\\nObsoletes: python-") |
||||
print(string.sub(package,9,string.len(package))) |
||||
print(" < ") |
||||
print(vr) |
||||
elseif (string.starts(package, "python" .. rpm.expand("%{python3_pkgversion}") .. "-")) then |
||||
--No unversioned provides as python3 is not default |
||||
elseif (rpm.expand("%{?python3_other_pkgversion}") ~= "" and string.starts(package, "python" .. rpm.expand("%{python3_other_pkgversion}") .. "-")) then |
||||
--No unversioned provides as python3_other is not default |
||||
elseif (string.starts(package, "pypy-")) then |
||||
--No unversioned provides as pypy is not default |
||||
elseif (string.starts(package, "pypy3-")) then |
||||
--No unversioned provides as pypy is not default |
||||
elseif (string.starts(package, "python-")) then |
||||
--Providing the current default python |
||||
print("Provides: python2-") |
||||
print(string.sub(package,8,string.len(package))) |
||||
print(" = ") |
||||
print(vr) |
||||
else |
||||
print("%python_provide: ERROR: ") |
||||
print(package) |
||||
print(" not recognized.") |
||||
end |
||||
} |
@ -0,0 +1,37 @@
@@ -0,0 +1,37 @@
|
||||
%__python2 /usr/bin/python2 |
||||
%python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") |
||||
%python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))") |
||||
%python2_version %(%{__python2} -c "import sys; sys.stdout.write('{0.major}.{0.minor}'.format(sys.version_info))") |
||||
%python2_version_nodots %(%{__python2} -c "import sys; sys.stdout.write('{0.major}{0.minor}'.format(sys.version_info))") |
||||
|
||||
%py2_shbang_opts -s |
||||
|
||||
# Use the slashes after expand so that the command starts on the same line as |
||||
# the macro |
||||
%py2_build() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} build --executable="%{__python2} %{py2_shbang_opts}" %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py2_build_egg() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_egg %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py2_build_wheel() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} bdist_wheel %{?*} |
||||
sleep 1 |
||||
} |
||||
|
||||
%py2_install() %{expand:\\\ |
||||
CFLAGS="%{optflags}" %{__python2} %{py_setup} %{?py_setup_args} install -O1 --skip-build --root %{buildroot} %{?*} |
||||
} |
||||
|
||||
%py2_install_egg() %{expand:\\\ |
||||
mkdir -p %{buildroot}%{python2_sitelib} |
||||
easy_install-%{python2_version} -m --prefix %{buildroot}%{_prefix} -Z dist/*-py%{python2_version}.egg %{?*} |
||||
} |
||||
|
||||
%py2_install_wheel() %{expand:\\\ |
||||
pip%{python2_version} install -I dist/%{1} --root %{buildroot} --strip-file-prefix %{buildroot} --no-deps |
||||
} |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash |
||||
exec `python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific = True))"`/pynche/pynche |
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
--- Python-2.5c1/Makefile.pre.in.cflags 2006-08-18 11:05:40.000000000 -0400 |
||||
+++ Python-2.5c1/Makefile.pre.in 2006-08-18 11:09:26.000000000 -0400 |
||||
@@ -334,7 +334,7 @@ |
||||
|
||||
# Build the interpreter |
||||
$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) |
||||
- $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ |
||||
+ $(LINKCC) $(CFLAGS) $(LDFLAGS) $(LINKFORSHARED) -o $@ \ |
||||
Modules/python.o \ |
||||
$(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) |
||||
|
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
diff -up Python-2.5.1/Lib/gettext.py.plural Python-2.5.1/Lib/gettext.py |
||||
--- Python-2.5.1/Lib/gettext.py.plural 2007-09-10 11:38:57.000000000 -0400 |
||||
+++ Python-2.5.1/Lib/gettext.py 2007-09-10 11:39:00.000000000 -0400 |
||||
@@ -299,6 +299,8 @@ class GNUTranslations(NullTranslations): |
||||
item = item.strip() |
||||
if not item: |
||||
continue |
||||
+ if item.startswith("#"): |
||||
+ continue |
||||
if ':' in item: |
||||
k, v = item.split(':', 1) |
||||
k = k.strip().lower() |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
diff -up Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding Python-2.5.1/Lib/sqlite3/dbapi2.py |
||||
--- Python-2.5.1/Lib/sqlite3/dbapi2.py.encoding 2007-09-14 10:41:50.000000000 -0400 |
||||
+++ Python-2.5.1/Lib/sqlite3/dbapi2.py 2007-09-14 10:42:00.000000000 -0400 |
||||
@@ -1,7 +1,6 @@ |
||||
-# -*- coding: iso-8859-1 -*- |
||||
# pysqlite2/dbapi2.py: the DB-API 2.0 interface |
||||
# |
||||
-# Copyright (C) 2004-2005 Gerhard Häring <gh@ghaering.de> |
||||
+# Copyright (C) 2004-2005 Gerhard Haering <gh@ghaering.de> |
||||
# |
||||
# This file is part of pysqlite. |
||||
# |
||||
diff -up Python-2.5.1/Lib/sqlite3/__init__.py.encoding Python-2.5.1/Lib/sqlite3/__init__.py |
||||
--- Python-2.5.1/Lib/sqlite3/__init__.py.encoding 2007-09-14 10:41:47.000000000 -0400 |
||||
+++ Python-2.5.1/Lib/sqlite3/__init__.py 2007-09-14 10:42:06.000000000 -0400 |
||||
@@ -1,7 +1,6 @@ |
||||
-#-*- coding: ISO-8859-1 -*- |
||||
# pysqlite2/__init__.py: the pysqlite2 package. |
||||
# |
||||
-# Copyright (C) 2005 Gerhard Häring <gh@ghaering.de> |
||||
+# Copyright (C) 2005 Gerhard Haering <gh@ghaering.de> |
||||
# |
||||
# This file is part of pysqlite. |
||||
# |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
diff -up Python-2.6/configure.ac.rpath Python-2.6/configure.ac |
||||
--- Python-2.6/configure.ac.rpath 2008-11-24 02:51:06.000000000 -0500 |
||||
+++ Python-2.6/configure.ac 2008-11-24 02:51:21.000000000 -0500 |
||||
@@ -729,7 +729,7 @@ if test $enable_shared = "yes"; then |
||||
;; |
||||
OSF*) |
||||
LDLIBRARY='libpython$(VERSION).so' |
||||
- BLDLIBRARY='-rpath $(LIBDIR) -L. -lpython$(VERSION)' |
||||
+ BLDLIBRARY='-L. -lpython$(VERSION)' |
||||
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} |
||||
;; |
||||
atheos*) |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
diff -up Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath Python-2.6.4/Lib/distutils/unixccompiler.py |
||||
--- Python-2.6.4/Lib/distutils/unixccompiler.py.distutils-rpath 2009-09-09 04:34:06.000000000 -0400 |
||||
+++ Python-2.6.4/Lib/distutils/unixccompiler.py 2010-03-15 21:33:25.000000000 -0400 |
||||
@@ -142,6 +142,16 @@ class UnixCCompiler(CCompiler): |
||||
if sys.platform == "cygwin": |
||||
exe_extension = ".exe" |
||||
|
||||
+ def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): |
||||
+ """Remove standard library path from rpath""" |
||||
+ libraries, library_dirs, runtime_library_dirs = \ |
||||
+ CCompiler._fix_lib_args(self, libraries, library_dirs, |
||||
+ runtime_library_dirs) |
||||
+ libdir = sysconfig.get_config_var('LIBDIR') |
||||
+ if runtime_library_dirs and (libdir in runtime_library_dirs): |
||||
+ runtime_library_dirs.remove(libdir) |
||||
+ return libraries, library_dirs, runtime_library_dirs |
||||
+ |
||||
def preprocess(self, source, |
||||
output_file=None, macros=None, include_dirs=None, |
||||
extra_preargs=None, extra_postargs=None): |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
diff -up Python-2.7/Lib/sysconfig.py.lib64-sysconfig Python-2.7/Lib/sysconfig.py |
||||
--- Python-2.7/Lib/sysconfig.py.lib64-sysconfig 2010-07-08 14:18:41.386898476 -0400 |
||||
+++ Python-2.7/Lib/sysconfig.py 2010-07-08 14:22:02.837896461 -0400 |
||||
@@ -7,20 +7,20 @@ from os.path import pardir, realpath |
||||
|
||||
_INSTALL_SCHEMES = { |
||||
'posix_prefix': { |
||||
- 'stdlib': '{base}/lib/python{py_version_short}', |
||||
- 'platstdlib': '{platbase}/lib/python{py_version_short}', |
||||
+ 'stdlib': '{base}/lib64/python{py_version_short}', |
||||
+ 'platstdlib': '{platbase}/lib64/python{py_version_short}', |
||||
'purelib': '{base}/lib/python{py_version_short}/site-packages', |
||||
- 'platlib': '{platbase}/lib/python{py_version_short}/site-packages', |
||||
+ 'platlib': '{platbase}/lib64/python{py_version_short}/site-packages', |
||||
'include': '{base}/include/python{py_version_short}', |
||||
'platinclude': '{platbase}/include/python{py_version_short}', |
||||
'scripts': '{base}/bin', |
||||
'data': '{base}', |
||||
}, |
||||
'posix_home': { |
||||
- 'stdlib': '{base}/lib/python', |
||||
- 'platstdlib': '{base}/lib/python', |
||||
+ 'stdlib': '{base}/lib64/python', |
||||
+ 'platstdlib': '{base}/lib64/python', |
||||
'purelib': '{base}/lib/python', |
||||
- 'platlib': '{base}/lib/python', |
||||
+ 'platlib': '{base}/lib64/python', |
||||
'include': '{base}/include/python', |
||||
'platinclude': '{base}/include/python', |
||||
'scripts': '{base}/bin', |
||||
@@ -65,10 +65,10 @@ _INSTALL_SCHEMES = { |
||||
'data' : '{userbase}', |
||||
}, |
||||
'posix_user': { |
||||
- 'stdlib': '{userbase}/lib/python{py_version_short}', |
||||
- 'platstdlib': '{userbase}/lib/python{py_version_short}', |
||||
+ 'stdlib': '{userbase}/lib64/python{py_version_short}', |
||||
+ 'platstdlib': '{userbase}/lib64/python{py_version_short}', |
||||
'purelib': '{userbase}/lib/python{py_version_short}/site-packages', |
||||
- 'platlib': '{userbase}/lib/python{py_version_short}/site-packages', |
||||
+ 'platlib': '{userbase}/lib64/python{py_version_short}/site-packages', |
||||
'include': '{userbase}/include/python{py_version_short}', |
||||
'scripts': '{userbase}/bin', |
||||
'data' : '{userbase}', |
@ -0,0 +1,283 @@
@@ -0,0 +1,283 @@
|
||||
--- Python-2.7.4/Modules/Setup.dist.rhconfig 2013-04-06 16:02:34.000000000 +0200 |
||||
+++ Python-2.7.4/Modules/Setup.dist 2013-04-08 10:05:16.369985654 +0200 |
||||
@@ -153,7 +153,7 @@ GLHACK=-Dclear=__GLclear |
||||
# modules are to be built as shared libraries (see above for more |
||||
# detail; also note that *static* reverses this effect): |
||||
|
||||
-#*shared* |
||||
+*shared* |
||||
|
||||
# GNU readline. Unlike previous Python incarnations, GNU readline is |
||||
# now incorporated in an optional module, configured in the Setup file |
||||
@@ -163,77 +163,77 @@ GLHACK=-Dclear=__GLclear |
||||
# it, depending on your system -- see the GNU readline instructions. |
||||
# It's okay for this to be a shared library, too. |
||||
|
||||
-#readline readline.c -lreadline -ltermcap |
||||
+readline readline.c -lreadline -ltermcap |
||||
|
||||
|
||||
# Modules that should always be present (non UNIX dependent): |
||||
|
||||
-#array arraymodule.c # array objects |
||||
-#cmath cmathmodule.c _math.c # -lm # complex math library functions |
||||
-#math mathmodule.c _math.c # -lm # math library functions, e.g. sin() |
||||
-#_struct _struct.c # binary structure packing/unpacking |
||||
-#time timemodule.c # -lm # time operations and variables |
||||
-#operator operator.c # operator.add() and similar goodies |
||||
-#_testcapi _testcapimodule.c # Python C API test module |
||||
-#_random _randommodule.c # Random number generator |
||||
-#_collections _collectionsmodule.c # Container types |
||||
+array arraymodule.c # array objects |
||||
+cmath cmathmodule.c _math.c # -lm # complex math library functions |
||||
+math mathmodule.c _math.c # -lm # math library functions, e.g. sin() |
||||
+_struct _struct.c # binary structure packing/unpacking |
||||
+time timemodule.c # -lm # time operations and variables |
||||
+operator operator.c # operator.add() and similar goodies |
||||
+_testcapi _testcapimodule.c # Python C API test module |
||||
+_random _randommodule.c # Random number generator |
||||
+_collections _collectionsmodule.c # Container types |
||||
#_heapq _heapqmodule.c # Heapq type |
||||
-#itertools itertoolsmodule.c # Functions creating iterators for efficient looping |
||||
-#strop stropmodule.c # String manipulations |
||||
-#_functools _functoolsmodule.c # Tools for working with functions and callable objects |
||||
+itertools itertoolsmodule.c # Functions creating iterators for efficient looping |
||||
+strop stropmodule.c # String manipulations |
||||
+_functools _functoolsmodule.c # Tools for working with functions and callable objects |
||||
#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator |
||||
#_pickle _pickle.c # pickle accelerator |
||||
#datetime datetimemodule.c # date/time type |
||||
-#_bisect _bisectmodule.c # Bisection algorithms |
||||
+_bisect _bisectmodule.c # Bisection algorithms |
||||
|
||||
-#unicodedata unicodedata.c # static Unicode character database |
||||
+unicodedata unicodedata.c # static Unicode character database |
||||
|
||||
# access to ISO C locale support |
||||
-#_locale _localemodule.c # -lintl |
||||
+_locale _localemodule.c # -lintl |
||||
|
||||
# Standard I/O baseline |
||||
#_io -I$(srcdir)/Modules/_io _io/bufferedio.c _io/bytesio.c _io/fileio.c _io/iobase.c _io/_iomodule.c _io/stringio.c _io/textio.c |
||||
|
||||
|
||||
# Modules with some UNIX dependencies -- on by default: |
||||
# (If you have a really backward UNIX, select and socket may not be |
||||
# supported...) |
||||
|
||||
-#fcntl fcntlmodule.c # fcntl(2) and ioctl(2) |
||||
-#spwd spwdmodule.c # spwd(3) |
||||
-#grp grpmodule.c # grp(3) |
||||
-#select selectmodule.c # select(2); not on ancient System V |
||||
+fcntl fcntlmodule.c # fcntl(2) and ioctl(2) |
||||
+spwd spwdmodule.c # spwd(3) |
||||
+grp grpmodule.c # grp(3) |
||||
+select selectmodule.c # select(2); not on ancient System V |
||||
|
||||
# Memory-mapped files (also works on Win32). |
||||
-#mmap mmapmodule.c |
||||
+mmap mmapmodule.c |
||||
|
||||
# CSV file helper |
||||
-#_csv _csv.c |
||||
+_csv _csv.c |
||||
|
||||
# Socket module helper for socket(2) |
||||
-#_socket socketmodule.c timemodule.c |
||||
+_socket socketmodule.c timemodule.c |
||||
|
||||
# Socket module helper for SSL support; you must comment out the other |
||||
# socket line above, and possibly edit the SSL variable: |
||||
#SSL=/usr/local/ssl |
||||
-#_ssl _ssl.c \ |
||||
-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ |
||||
-# -L$(SSL)/lib -lssl -lcrypto |
||||
+_ssl _ssl.c \ |
||||
+ -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ |
||||
+ -L$(SSL)/lib -lssl -lcrypto |
||||
|
||||
# The crypt module is now disabled by default because it breaks builds |
||||
# on many systems (where -lcrypt is needed), e.g. Linux (I believe). |
||||
# |
||||
# First, look at Setup.config; configure may have set this for you. |
||||
|
||||
-#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems |
||||
+crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems |
||||
|
||||
|
||||
# Some more UNIX dependent modules -- off by default, since these |
||||
# are not supported by all UNIX systems: |
||||
|
||||
-#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere |
||||
-#termios termios.c # Steen Lumholt's termios module |
||||
-#resource resource.c # Jeremy Hylton's rlimit interface |
||||
+nis nismodule.c -lnsl # Sun yellow pages -- not everywhere |
||||
+termios termios.c # Steen Lumholt's termios module |
||||
+resource resource.c # Jeremy Hylton's rlimit interface |
||||
|
||||
|
||||
# Multimedia modules -- off by default. |
||||
@@ -238,8 +238,8 @@ GLHACK=-Dclear=__GLclear |
||||
# #993173 says audioop works on 64-bit platforms, though. |
||||
# These represent audio samples or images as strings: |
||||
|
||||
-#audioop audioop.c # Operations on audio samples |
||||
-#imageop imageop.c # Operations on images |
||||
+audioop audioop.c # Operations on audio samples |
||||
+imageop imageop.c # Operations on images |
||||
|
||||
|
||||
# Note that the _md5 and _sha modules are normally only built if the |
||||
@@ -249,14 +249,14 @@ GLHACK=-Dclear=__GLclear |
||||
# Message-Digest Algorithm, described in RFC 1321. The necessary files |
||||
# md5.c and md5.h are included here. |
||||
|
||||
-#_md5 md5module.c md5.c |
||||
+_md5 md5module.c md5.c |
||||
|
||||
|
||||
# The _sha module implements the SHA checksum algorithms. |
||||
# (NIST's Secure Hash Algorithms.) |
||||
-#_sha shamodule.c |
||||
-#_sha256 sha256module.c |
||||
-#_sha512 sha512module.c |
||||
+_sha shamodule.c |
||||
+_sha256 sha256module.c |
||||
+_sha512 sha512module.c |
||||
|
||||
|
||||
# SGI IRIX specific modules -- off by default. |
||||
@@ -303,12 +303,12 @@ GLHACK=-Dclear=__GLclear |
||||
# A Linux specific module -- off by default; this may also work on |
||||
# some *BSDs. |
||||
|
||||
-#linuxaudiodev linuxaudiodev.c |
||||
+linuxaudiodev linuxaudiodev.c |
||||
|
||||
|
||||
# George Neville-Neil's timing module: |
||||
|
||||
-#timing timingmodule.c |
||||
+timing timingmodule.c |
||||
|
||||
|
||||
# The _tkinter module. |
||||
@@ -323,7 +323,7 @@ GLHACK=-Dclear=__GLclear |
||||
# every system. |
||||
|
||||
# *** Always uncomment this (leave the leading underscore in!): |
||||
-# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ |
||||
+_tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ |
||||
# *** Uncomment and edit to reflect where your Tcl/Tk libraries are: |
||||
# -L/usr/local/lib \ |
||||
# *** Uncomment and edit to reflect where your Tcl/Tk headers are: |
||||
@@ -333,7 +333,7 @@ GLHACK=-Dclear=__GLclear |
||||
# *** Or uncomment this for Solaris: |
||||
# -I/usr/openwin/include \ |
||||
# *** Uncomment and edit for Tix extension only: |
||||
-# -DWITH_TIX -ltix8.1.8.2 \ |
||||
+ -DWITH_TIX -ltix \ |
||||
# *** Uncomment and edit for BLT extension only: |
||||
# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \ |
||||
# *** Uncomment and edit for PIL (TkImaging) extension only: |
||||
@@ -342,7 +342,7 @@ GLHACK=-Dclear=__GLclear |
||||
# *** Uncomment and edit for TOGL extension only: |
||||
# -DWITH_TOGL togl.c \ |
||||
# *** Uncomment and edit to reflect your Tcl/Tk versions: |
||||
-# -ltk8.2 -ltcl8.2 \ |
||||
+ -ltk -ltcl \ |
||||
# *** Uncomment and edit to reflect where your X11 libraries are: |
||||
# -L/usr/X11R6/lib \ |
||||
# *** Or uncomment this for Solaris: |
||||
@@ -352,7 +352,7 @@ GLHACK=-Dclear=__GLclear |
||||
# *** Uncomment for AIX: |
||||
# -lld \ |
||||
# *** Always uncomment this; X11 libraries to link with: |
||||
-# -lX11 |
||||
+ -lX11 |
||||
|
||||
# Lance Ellinghaus's syslog module |
||||
#syslog syslogmodule.c # syslog daemon interface |
||||
@@ -374,7 +374,7 @@ GLHACK=-Dclear=__GLclear |
||||
# it is a highly experimental and dangerous device for calling |
||||
# *arbitrary* C functions in *arbitrary* shared libraries: |
||||
|
||||
-#dl dlmodule.c |
||||
+dl dlmodule.c |
||||
|
||||
|
||||
# Modules that provide persistent dictionary-like semantics. You will |
||||
@@ -397,7 +397,7 @@ GLHACK=-Dclear=__GLclear |
||||
# |
||||
# First, look at Setup.config; configure may have set this for you. |
||||
|
||||
-#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm |
||||
+gdbm gdbmmodule.c -lgdbm |
||||
|
||||
|
||||
# Sleepycat Berkeley DB interface. |
||||
@@ -412,11 +412,9 @@ GLHACK=-Dclear=__GLclear |
||||
# |
||||
# Edit the variables DB and DBLIBVERto point to the db top directory |
||||
# and the subdirectory of PORT where you built it. |
||||
-#DB=/usr/local/BerkeleyDB.4.0 |
||||
-#DBLIBVER=4.0 |
||||
-#DBINC=$(DB)/include |
||||
-#DBLIB=$(DB)/lib |
||||
-#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) |
||||
+DBINC=/usr/include/libdb |
||||
+DBLIB=/usr/lib |
||||
+_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb |
||||
|
||||
# Historical Berkeley DB 1.85 |
||||
# |
||||
@@ -431,14 +430,14 @@ GLHACK=-Dclear=__GLclear |
||||
|
||||
|
||||
# Helper module for various ascii-encoders |
||||
-#binascii binascii.c |
||||
+binascii binascii.c |
||||
|
||||
# Fred Drake's interface to the Python parser |
||||
-#parser parsermodule.c |
||||
+parser parsermodule.c |
||||
|
||||
# cStringIO and cPickle |
||||
-#cStringIO cStringIO.c |
||||
-#cPickle cPickle.c |
||||
+cStringIO cStringIO.c |
||||
+cPickle cPickle.c |
||||
|
||||
|
||||
# Lee Busby's SIGFPE modules. |
||||
@@ -461,7 +460,7 @@ GLHACK=-Dclear=__GLclear |
||||
# Andrew Kuchling's zlib module. |
||||
# This require zlib 1.1.3 (or later). |
||||
# See http://www.gzip.org/zlib/ |
||||
-#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz |
||||
+zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz |
||||
|
||||
# Interface to the Expat XML parser |
||||
# |
||||
@@ -480,14 +479,14 @@ GLHACK=-Dclear=__GLclear |
||||
# Hye-Shik Chang's CJKCodecs |
||||
|
||||
# multibytecodec is required for all the other CJK codec modules |
||||
-#_multibytecodec cjkcodecs/multibytecodec.c |
||||
+_multibytecodec cjkcodecs/multibytecodec.c |
||||
|
||||
-#_codecs_cn cjkcodecs/_codecs_cn.c |
||||
-#_codecs_hk cjkcodecs/_codecs_hk.c |
||||
-#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c |
||||
-#_codecs_jp cjkcodecs/_codecs_jp.c |
||||
-#_codecs_kr cjkcodecs/_codecs_kr.c |
||||
-#_codecs_tw cjkcodecs/_codecs_tw.c |
||||
+_codecs_cn cjkcodecs/_codecs_cn.c |
||||
+_codecs_hk cjkcodecs/_codecs_hk.c |
||||
+_codecs_iso2022 cjkcodecs/_codecs_iso2022.c |
||||
+_codecs_jp cjkcodecs/_codecs_jp.c |
||||
+_codecs_kr cjkcodecs/_codecs_kr.c |
||||
+_codecs_tw cjkcodecs/_codecs_tw.c |
||||
|
||||
# Example -- included for reference only: |
||||
# xx xxmodule.c |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
diff -up Python-2.7.1/Lib/test/test_abc.py.cache_leak Python-2.7.1/Lib/test/test_abc.py |
||||
--- Python-2.7.1/Lib/test/test_abc.py.cache_leak 2010-12-28 18:06:35.551938356 -0500 |
||||
+++ Python-2.7.1/Lib/test/test_abc.py 2010-12-28 18:09:09.021059202 -0500 |
||||
@@ -3,6 +3,8 @@ |
||||
|
||||
"""Unit tests for abc.py.""" |
||||
|
||||
+import sys |
||||
+ |
||||
import unittest, weakref |
||||
from test import test_support |
||||
|
||||
@@ -229,8 +231,12 @@ class TestABC(unittest.TestCase): |
||||
# Trigger cache. |
||||
C().f() |
||||
del C |
||||
- test_support.gc_collect() |
||||
- self.assertEqual(r(), None) |
||||
+ # This doesn't work in our debug build, presumably due to its use |
||||
+ # of COUNT_ALLOCS, which makes heap-allocated types immortal (once |
||||
+ # they've ever had an instance): |
||||
+ if not hasattr(sys, 'getcounts'): |
||||
+ test_support.gc_collect() |
||||
+ self.assertEqual(r(), None) |
||||
|
||||
def test_main(): |
||||
test_support.run_unittest(TestABC) |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
diff -up Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config Python-2.7.2/Misc/python-config.in |
||||
--- Python-2.7.2/Misc/python-config.in.add-extension-suffix-to-python-config 2011-08-23 18:15:41.832497124 -0400 |
||||
+++ Python-2.7.2/Misc/python-config.in 2011-08-23 18:17:25.854490011 -0400 |
||||
@@ -6,7 +6,7 @@ import getopt |
||||
from distutils import sysconfig |
||||
|
||||
valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', |
||||
- 'ldflags', 'help'] |
||||
+ 'ldflags', 'extension-suffix', 'help'] |
||||
|
||||
def exit_with_usage(code=1): |
||||
print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0], |
||||
@@ -54,3 +54,5 @@ for opt in opt_flags: |
||||
libs.extend(getvar('LINKFORSHARED').split()) |
||||
print ' '.join(libs) |
||||
|
||||
+ elif opt == '--extension-suffix': |
||||
+ print (sys.pydebug and "_d" or "") + sysconfig.get_config_var('SO') |
@ -0,0 +1,292 @@
@@ -0,0 +1,292 @@
|
||||
diff -up Python-2.7.3/configure.ac.debug-build Python-2.7.3/configure.ac |
||||
--- Python-2.7.3/configure.ac.debug-build 2012-04-18 19:46:22.066498521 -0400 |
||||
+++ Python-2.7.3/configure.ac 2012-04-18 19:46:22.078498372 -0400 |
||||
@@ -635,7 +635,7 @@ AC_SUBST(LIBRARY) |
||||
AC_MSG_CHECKING(LIBRARY) |
||||
if test -z "$LIBRARY" |
||||
then |
||||
- LIBRARY='libpython$(VERSION).a' |
||||
+ LIBRARY='libpython$(VERSION)$(DEBUG_EXT).a' |
||||
fi |
||||
AC_MSG_RESULT($LIBRARY) |
||||
|
||||
@@ -780,8 +780,8 @@ if test $enable_shared = "yes"; then |
||||
INSTSONAME="$LDLIBRARY".$SOVERSION |
||||
;; |
||||
Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*) |
||||
- LDLIBRARY='libpython$(VERSION).so' |
||||
- BLDLIBRARY='-L. -lpython$(VERSION)' |
||||
+ LDLIBRARY='libpython$(VERSION)$(DEBUG_EXT).so' |
||||
+ BLDLIBRARY='-L. -lpython$(VERSION)$(DEBUG_EXT)' |
||||
RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} |
||||
case $ac_sys_system in |
||||
FreeBSD*) |
||||
@@ -905,6 +905,14 @@ else AC_MSG_RESULT(no); Py_DEBUG='false' |
||||
fi], |
||||
[AC_MSG_RESULT(no)]) |
||||
|
||||
+if test "$Py_DEBUG" = 'true' |
||||
+then |
||||
+ DEBUG_EXT=_d |
||||
+ DEBUG_SUFFIX=-debug |
||||
+fi |
||||
+AC_SUBST(DEBUG_EXT) |
||||
+AC_SUBST(DEBUG_SUFFIX) |
||||
+ |
||||
# XXX Shouldn't the code above that fiddles with BASECFLAGS and OPT be |
||||
# merged with this chunk of code? |
||||
|
||||
diff -up Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build Python-2.7.3/Lib/distutils/command/build_ext.py |
||||
--- Python-2.7.3/Lib/distutils/command/build_ext.py.debug-build 2012-04-09 19:07:29.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/command/build_ext.py 2012-04-18 19:46:22.079498360 -0400 |
||||
@@ -676,7 +676,10 @@ class build_ext (Command): |
||||
so_ext = get_config_var('SO') |
||||
if os.name == 'nt' and self.debug: |
||||
return os.path.join(*ext_path) + '_d' + so_ext |
||||
- return os.path.join(*ext_path) + so_ext |
||||
+ |
||||
+ # Similarly, extensions in debug mode are named 'module_d.so', to |
||||
+ # avoid adding the _d to the SO config variable: |
||||
+ return os.path.join(*ext_path) + (sys.pydebug and "_d" or "") + so_ext |
||||
|
||||
def get_export_symbols (self, ext): |
||||
"""Return the list of symbols that a shared extension has to |
||||
@@ -761,6 +764,8 @@ class build_ext (Command): |
||||
template = "python%d.%d" |
||||
pythonlib = (template % |
||||
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) |
||||
+ if sys.pydebug: |
||||
+ pythonlib += '_d' |
||||
return ext.libraries + [pythonlib] |
||||
else: |
||||
return ext.libraries |
||||
diff -up Python-2.7.3/Lib/distutils/sysconfig.py.debug-build Python-2.7.3/Lib/distutils/sysconfig.py |
||||
--- Python-2.7.3/Lib/distutils/sysconfig.py.debug-build 2012-04-18 19:46:21.988499499 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/sysconfig.py 2012-04-18 19:46:22.080498348 -0400 |
||||
@@ -85,7 +85,8 @@ def get_python_inc(plat_specific=0, pref |
||||
# Include is located in the srcdir |
||||
inc_dir = os.path.join(srcdir, "Include") |
||||
return inc_dir |
||||
- return os.path.join(prefix, "include", "python" + get_python_version()) |
||||
+ return os.path.join(prefix, "include", |
||||
+ "python" + get_python_version() + (sys.pydebug and '-debug' or '')) |
||||
elif os.name == "nt": |
||||
return os.path.join(prefix, "include") |
||||
elif os.name == "os2": |
||||
@@ -250,7 +251,7 @@ def get_makefile_filename(): |
||||
if python_build: |
||||
return os.path.join(project_base, "Makefile") |
||||
lib_dir = get_python_lib(plat_specific=1, standard_lib=1) |
||||
- return os.path.join(lib_dir, "config", "Makefile") |
||||
+ return os.path.join(lib_dir, "config" + (sys.pydebug and "-debug" or ""), "Makefile") |
||||
|
||||
|
||||
def parse_config_h(fp, g=None): |
||||
diff -up Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build Python-2.7.3/Lib/distutils/tests/test_install.py |
||||
--- Python-2.7.3/Lib/distutils/tests/test_install.py.debug-build 2012-04-18 19:46:21.997499385 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/tests/test_install.py 2012-04-18 19:46:22.080498348 -0400 |
||||
@@ -20,8 +20,9 @@ from distutils.tests import support |
||||
|
||||
|
||||
def _make_ext_name(modname): |
||||
- if os.name == 'nt' and sys.executable.endswith('_d.exe'): |
||||
+ if sys.pydebug: |
||||
modname += '_d' |
||||
+ |
||||
return modname + sysconfig.get_config_var('SO') |
||||
|
||||
|
||||
diff -up Python-2.7.3/Makefile.pre.in.debug-build Python-2.7.3/Makefile.pre.in |
||||
--- Python-2.7.3/Makefile.pre.in.debug-build 2012-04-18 19:46:22.073498437 -0400 |
||||
+++ Python-2.7.3/Makefile.pre.in 2012-04-18 19:48:46.336694896 -0400 |
||||
@@ -102,8 +102,8 @@ SCRIPTDIR= $(prefix)/lib64 |
||||
# Detailed destination directories |
||||
BINLIBDEST= $(LIBDIR)/python$(VERSION) |
||||
LIBDEST= $(SCRIPTDIR)/python$(VERSION) |
||||
-INCLUDEPY= $(INCLUDEDIR)/python$(VERSION) |
||||
-CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION) |
||||
+INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX) |
||||
+CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION)$(DEBUG_SUFFIX) |
||||
LIBP= $(LIBDIR)/python$(VERSION) |
||||
|
||||
# Symbols used for using shared libraries |
||||
@@ -117,6 +117,12 @@ DESTSHARED= $(BINLIBDEST)/lib-dynload |
||||
EXE= @EXEEXT@ |
||||
BUILDEXE= @BUILDEXEEXT@ |
||||
|
||||
+# DEBUG_EXT is used by ELF files (names and SONAMEs); it will be "_d" for a debug build |
||||
+# DEBUG_SUFFIX is used by filesystem paths; it will be "-debug" for a debug build |
||||
+# Both will be empty in an optimized build |
||||
+DEBUG_EXT= @DEBUG_EXT@ |
||||
+DEBUG_SUFFIX= @DEBUG_SUFFIX@ |
||||
+ |
||||
# Short name and location for Mac OS X Python framework |
||||
UNIVERSALSDK=@UNIVERSALSDK@ |
||||
PYTHONFRAMEWORK= @PYTHONFRAMEWORK@ |
||||
@@ -180,8 +186,8 @@ LIBOBJDIR= Python/ |
||||
LIBOBJS= @LIBOBJS@ |
||||
UNICODE_OBJS= @UNICODE_OBJS@ |
||||
|
||||
-PYTHON= python$(EXE) |
||||
-BUILDPYTHON= python$(BUILDEXE) |
||||
+PYTHON= python$(DEBUG_SUFFIX)$(EXE) |
||||
+BUILDPYTHON= python$(DEBUG_SUFFIX)$(BUILDEXE) |
||||
|
||||
PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@ |
||||
_PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@ |
||||
@@ -413,7 +419,7 @@ sharedmods: $(BUILDPYTHON) |
||||
$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \ |
||||
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build |
||||
|
||||
-libpython$(VERSION).so: $(LIBRARY_OBJS) |
||||
+libpython$(VERSION)$(DEBUG_EXT).so: $(LIBRARY_OBJS) |
||||
if test $(INSTSONAME) != $(LDLIBRARY); then \ |
||||
$(BLDSHARED) -Wl,-h$(INSTSONAME) -o $(INSTSONAME) $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ |
||||
$(LN) -f $(INSTSONAME) $@; \ |
||||
@@ -796,18 +802,18 @@ bininstall: altbininstall |
||||
then rm -f $(DESTDIR)$(BINDIR)/$(PYTHON); \ |
||||
else true; \ |
||||
fi |
||||
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(EXE) $(PYTHON)) |
||||
- -rm -f $(DESTDIR)$(BINDIR)/python2$(EXE) |
||||
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(EXE) python2$(EXE)) |
||||
- -rm -f $(DESTDIR)$(BINDIR)/python2-config |
||||
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-config python2-config) |
||||
- -rm -f $(DESTDIR)$(BINDIR)/python-config |
||||
- (cd $(DESTDIR)$(BINDIR); $(LN) -s python2-config python-config) |
||||
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)$(EXE) $(PYTHON)) |
||||
+ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)$(EXE) |
||||
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)$(EXE) python2$(DEBUG_SUFFIX)$(EXE)) |
||||
+ -rm -f $(DESTDIR)$(BINDIR)/python2$(DEBUG_SUFFIX)-config |
||||
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)$(DEBUG_SUFFIX)-config python2$(DEBUG_SUFFIX)-config) |
||||
+ -rm -f $(DESTDIR)$(BINDIR)/python$(DEBUG_SUFFIX)-config |
||||
+ (cd $(DESTDIR)$(BINDIR); $(LN) -s python2$(DEBUG_SUFFIX)-config python$(DEBUG_SUFFIX)-config) |
||||
-test -d $(DESTDIR)$(LIBPC) || $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(LIBPC) |
||||
- -rm -f $(DESTDIR)$(LIBPC)/python2.pc |
||||
- (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION).pc python2.pc) |
||||
- -rm -f $(DESTDIR)$(LIBPC)/python.pc |
||||
- (cd $(DESTDIR)$(LIBPC); $(LN) -s python2.pc python.pc) |
||||
+ -rm -f $(DESTDIR)$(LIBPC)/python2$(DEBUG_SUFFIX).pc |
||||
+ (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION)$(DEBUG_SUFFIX).pc python2$(DEBUG_SUFFIX).pc) |
||||
+ -rm -f $(DESTDIR)$(LIBPC)/python$(DEBUG_SUFFIX).pc |
||||
+ (cd $(DESTDIR)$(LIBPC); $(LN) -s python2$(DEBUG_SUFFIX).pc python$(DEBUG_SUFFIX).pc) |
||||
|
||||
# Install the interpreter with $(VERSION) affixed |
||||
# This goes into $(exec_prefix) |
||||
@@ -820,7 +826,7 @@ altbininstall: $(BUILDPYTHON) |
||||
else true; \ |
||||
fi; \ |
||||
done |
||||
- $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(EXE) |
||||
+ $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE) |
||||
if test -f $(LDLIBRARY); then \ |
||||
if test -n "$(DLLLIBRARY)" ; then \ |
||||
$(INSTALL_SHARED) $(DLLLIBRARY) $(DESTDIR)$(BINDIR); \ |
||||
@@ -970,10 +976,11 @@ $(srcdir)/Lib/$(PLATDIR): |
||||
fi; \ |
||||
cd $(srcdir)/Lib/$(PLATDIR); $(RUNSHARED) ./regen |
||||
|
||||
-python-config: $(srcdir)/Misc/python-config.in |
||||
+python$(DEBUG_SUFFIX)-config: $(srcdir)/Misc/python-config.in |
||||
# Substitution happens here, as the completely-expanded BINDIR |
||||
# is not available in configure |
||||
- sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(EXE)," < $(srcdir)/Misc/python-config.in >python-config |
||||
+ sed -e "s,@EXENAME@,$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)$(EXE)," < $(srcdir)/Misc/python-config.in >python$(DEBUG_SUFFIX)-config |
||||
+ |
||||
|
||||
# Install the include files |
||||
INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY) |
||||
@@ -994,13 +1001,13 @@ inclinstall: |
||||
$(INSTALL_DATA) pyconfig.h $(DESTDIR)$(CONFINCLUDEPY)/pyconfig.h |
||||
|
||||
# Install the library and miscellaneous stuff needed for extending/embedding |
||||
-# This goes into $(exec_prefix) |
||||
-LIBPL= $(LIBP)/config |
||||
+# This goes into $(exec_prefix)$(DEBUG_SUFFIX) |
||||
+LIBPL= $(LIBP)/config$(DEBUG_SUFFIX) |
||||
|
||||
# pkgconfig directory |
||||
LIBPC= $(LIBDIR)/pkgconfig |
||||
|
||||
-libainstall: all python-config |
||||
+libainstall: all python$(DEBUG_SUFFIX)-config |
||||
@for i in $(LIBDIR) $(LIBP) $(LIBPL) $(LIBPC); \ |
||||
do \ |
||||
if test ! -d $(DESTDIR)$$i; then \ |
||||
@@ -1016,11 +1023,10 @@ libainstall: all python-config |
||||
$(INSTALL_DATA) Modules/Setup $(DESTDIR)$(LIBPL)/Setup |
||||
$(INSTALL_DATA) Modules/Setup.local $(DESTDIR)$(LIBPL)/Setup.local |
||||
$(INSTALL_DATA) Modules/Setup.config $(DESTDIR)$(LIBPL)/Setup.config |
||||
- $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION).pc |
||||
+ $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION)$(DEBUG_SUFFIX).pc |
||||
$(INSTALL_SCRIPT) $(srcdir)/Modules/makesetup $(DESTDIR)$(LIBPL)/makesetup |
||||
$(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh |
||||
- $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(VERSION)-config |
||||
- rm python-config |
||||
+ $(INSTALL_SCRIPT) python$(DEBUG_SUFFIX)-config $(DESTDIR)$(BINDIR)/python$(VERSION)$(DEBUG_SUFFIX)-config |
||||
@if [ -s Modules/python.exp -a \ |
||||
"`echo $(MACHDEP) | sed 's/^\(...\).*/\1/'`" = "aix" ]; then \ |
||||
echo; echo "Installing support files for building shared extension modules on AIX:"; \ |
||||
diff -up Python-2.7.3/Misc/python-config.in.debug-build Python-2.7.3/Misc/python-config.in |
||||
--- Python-2.7.3/Misc/python-config.in.debug-build 2012-04-09 19:07:33.000000000 -0400 |
||||
+++ Python-2.7.3/Misc/python-config.in 2012-04-18 19:46:22.082498324 -0400 |
||||
@@ -45,7 +45,7 @@ for opt in opt_flags: |
||||
|
||||
elif opt in ('--libs', '--ldflags'): |
||||
libs = getvar('LIBS').split() + getvar('SYSLIBS').split() |
||||
- libs.append('-lpython'+pyver) |
||||
+ libs.append('-lpython' + pyver + (sys.pydebug and "_d" or "")) |
||||
# add the prefix/lib/pythonX.Y/config dir, but only if there is no |
||||
# shared library in prefix/lib/. |
||||
if opt == '--ldflags': |
||||
diff -up Python-2.7.3/Modules/makesetup.debug-build Python-2.7.3/Modules/makesetup |
||||
--- Python-2.7.3/Modules/makesetup.debug-build 2012-04-09 19:07:34.000000000 -0400 |
||||
+++ Python-2.7.3/Modules/makesetup 2012-04-18 19:46:22.083498312 -0400 |
||||
@@ -233,7 +233,7 @@ sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' | |
||||
*$mod.o*) base=$mod;; |
||||
*) base=${mod}module;; |
||||
esac |
||||
- file="$srcdir/$base\$(SO)" |
||||
+ file="$srcdir/$base\$(DEBUG_EXT)\$(SO)" |
||||
case $doconfig in |
||||
no) SHAREDMODS="$SHAREDMODS $file";; |
||||
esac |
||||
diff -up Python-2.7.3/Python/dynload_shlib.c.debug-build Python-2.7.3/Python/dynload_shlib.c |
||||
--- Python-2.7.3/Python/dynload_shlib.c.debug-build 2012-04-09 19:07:35.000000000 -0400 |
||||
+++ Python-2.7.3/Python/dynload_shlib.c 2012-04-18 19:46:22.083498312 -0400 |
||||
@@ -46,11 +46,16 @@ const struct filedescr _PyImport_DynLoad |
||||
{"module.exe", "rb", C_EXTENSION}, |
||||
{"MODULE.EXE", "rb", C_EXTENSION}, |
||||
#else |
||||
+#ifdef Py_DEBUG |
||||
+ {"_d.so", "rb", C_EXTENSION}, |
||||
+ {"module_d.so", "rb", C_EXTENSION}, |
||||
+#else |
||||
{".so", "rb", C_EXTENSION}, |
||||
{"module.so", "rb", C_EXTENSION}, |
||||
-#endif |
||||
-#endif |
||||
-#endif |
||||
+#endif /* Py_DEBUG */ |
||||
+#endif /* __VMS */ |
||||
+#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */ |
||||
+#endif /* __CYGWIN__ */ |
||||
{0, 0} |
||||
}; |
||||
|
||||
diff -up Python-2.7.3/Python/sysmodule.c.debug-build Python-2.7.3/Python/sysmodule.c |
||||
--- Python-2.7.3/Python/sysmodule.c.debug-build 2012-04-09 19:07:35.000000000 -0400 |
||||
+++ Python-2.7.3/Python/sysmodule.c 2012-04-18 19:46:22.083498312 -0400 |
||||
@@ -1506,6 +1506,12 @@ _PySys_Init(void) |
||||
PyString_FromString("legacy")); |
||||
#endif |
||||
|
||||
+#ifdef Py_DEBUG |
||||
+ PyDict_SetItemString(sysdict, "pydebug", Py_True); |
||||
+#else |
||||
+ PyDict_SetItemString(sysdict, "pydebug", Py_False); |
||||
+#endif |
||||
+ |
||||
#undef SET_SYS_FROM_STRING |
||||
if (PyErr_Occurred()) |
||||
return NULL; |
@ -0,0 +1,196 @@
@@ -0,0 +1,196 @@
|
||||
diff -up Python-2.7.3/Lib/distutils/command/install.py.lib64 Python-2.7.3/Lib/distutils/command/install.py |
||||
--- Python-2.7.3/Lib/distutils/command/install.py.lib64 2012-04-09 19:07:29.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/command/install.py 2013-02-19 13:58:20.446015129 -0500 |
||||
@@ -42,14 +42,14 @@ else: |
||||
INSTALL_SCHEMES = { |
||||
'unix_prefix': { |
||||
'purelib': '$base/lib/python$py_version_short/site-packages', |
||||
- 'platlib': '$platbase/lib/python$py_version_short/site-packages', |
||||
+ 'platlib': '$platbase/lib64/python$py_version_short/site-packages', |
||||
'headers': '$base/include/python$py_version_short/$dist_name', |
||||
'scripts': '$base/bin', |
||||
'data' : '$base', |
||||
}, |
||||
'unix_home': { |
||||
'purelib': '$base/lib/python', |
||||
- 'platlib': '$base/lib/python', |
||||
+ 'platlib': '$base/lib64/python', |
||||
'headers': '$base/include/python/$dist_name', |
||||
'scripts': '$base/bin', |
||||
'data' : '$base', |
||||
diff -up Python-2.7.3/Lib/distutils/sysconfig.py.lib64 Python-2.7.3/Lib/distutils/sysconfig.py |
||||
--- Python-2.7.3/Lib/distutils/sysconfig.py.lib64 2012-04-09 19:07:29.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/distutils/sysconfig.py 2013-02-19 13:58:20.446015129 -0500 |
||||
@@ -114,8 +114,12 @@ def get_python_lib(plat_specific=0, stan |
||||
prefix = plat_specific and EXEC_PREFIX or PREFIX |
||||
|
||||
if os.name == "posix": |
||||
+ if plat_specific or standard_lib: |
||||
+ lib = "lib64" |
||||
+ else: |
||||
+ lib = "lib" |
||||
libpython = os.path.join(prefix, |
||||
- "lib", "python" + get_python_version()) |
||||
+ lib, "python" + get_python_version()) |
||||
if standard_lib: |
||||
return libpython |
||||
else: |
||||
diff -up Python-2.7.3/Lib/site.py.lib64 Python-2.7.3/Lib/site.py |
||||
--- Python-2.7.3/Lib/site.py.lib64 2012-04-09 19:07:31.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/site.py 2013-02-19 13:58:20.447015128 -0500 |
||||
@@ -300,12 +300,16 @@ def getsitepackages(): |
||||
if sys.platform in ('os2emx', 'riscos'): |
||||
sitepackages.append(os.path.join(prefix, "Lib", "site-packages")) |
||||
elif os.sep == '/': |
||||
+ sitepackages.append(os.path.join(prefix, "lib64", |
||||
+ "python" + sys.version[:3], |
||||
+ "site-packages")) |
||||
sitepackages.append(os.path.join(prefix, "lib", |
||||
"python" + sys.version[:3], |
||||
"site-packages")) |
||||
sitepackages.append(os.path.join(prefix, "lib", "site-python")) |
||||
else: |
||||
sitepackages.append(prefix) |
||||
+ sitepackages.append(os.path.join(prefix, "lib64", "site-packages")) |
||||
sitepackages.append(os.path.join(prefix, "lib", "site-packages")) |
||||
if sys.platform == "darwin": |
||||
# for framework builds *only* we add the standard Apple |
||||
diff -up Python-2.7.3/Lib/test/test_site.py.lib64 Python-2.7.3/Lib/test/test_site.py |
||||
--- Python-2.7.3/Lib/test/test_site.py.lib64 2012-04-09 19:07:32.000000000 -0400 |
||||
+++ Python-2.7.3/Lib/test/test_site.py 2013-02-19 13:58:20.447015128 -0500 |
||||
@@ -241,17 +241,20 @@ class HelperFunctionsTests(unittest.Test |
||||
self.assertEqual(dirs[2], wanted) |
||||
elif os.sep == '/': |
||||
# OS X non-framwework builds, Linux, FreeBSD, etc |
||||
- self.assertEqual(len(dirs), 2) |
||||
- wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3], |
||||
+ self.assertEqual(len(dirs), 3) |
||||
+ wanted = os.path.join('xoxo', 'lib64', 'python' + sys.version[:3], |
||||
'site-packages') |
||||
self.assertEqual(dirs[0], wanted) |
||||
- wanted = os.path.join('xoxo', 'lib', 'site-python') |
||||
+ wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3], |
||||
+ 'site-packages') |
||||
self.assertEqual(dirs[1], wanted) |
||||
+ wanted = os.path.join('xoxo', 'lib', 'site-python') |
||||
+ self.assertEqual(dirs[2], wanted) |
||||
else: |
||||
# other platforms |
||||
self.assertEqual(len(dirs), 2) |
||||
self.assertEqual(dirs[0], 'xoxo') |
||||
- wanted = os.path.join('xoxo', 'lib', 'site-packages') |
||||
+ wanted = os.path.join('xoxo', 'lib64', 'site-packages') |
||||
self.assertEqual(dirs[1], wanted) |
||||
|
||||
class PthFile(object): |
||||
diff -up Python-2.7.3/Makefile.pre.in.lib64 Python-2.7.3/Makefile.pre.in |
||||
--- Python-2.7.3/Makefile.pre.in.lib64 2013-02-19 13:58:20.435015131 -0500 |
||||
+++ Python-2.7.3/Makefile.pre.in 2013-02-19 13:58:20.447015128 -0500 |
||||
@@ -97,7 +97,7 @@ LIBDIR= @libdir@ |
||||
MANDIR= @mandir@ |
||||
INCLUDEDIR= @includedir@ |
||||
CONFINCLUDEDIR= $(exec_prefix)/include |
||||
-SCRIPTDIR= $(prefix)/lib |
||||
+SCRIPTDIR= $(prefix)/lib64 |
||||
|
||||
# Detailed destination directories |
||||
BINLIBDEST= $(LIBDIR)/python$(VERSION) |
||||
diff -up Python-2.7.3/Modules/getpath.c.lib64 Python-2.7.3/Modules/getpath.c |
||||
--- Python-2.7.3/Modules/getpath.c.lib64 2012-04-09 19:07:34.000000000 -0400 |
||||
+++ Python-2.7.3/Modules/getpath.c 2013-02-19 13:58:20.448015128 -0500 |
||||
@@ -117,8 +117,8 @@ |
||||
#endif |
||||
|
||||
#ifndef PYTHONPATH |
||||
-#define PYTHONPATH PREFIX "/lib/python" VERSION ":" \ |
||||
- EXEC_PREFIX "/lib/python" VERSION "/lib-dynload" |
||||
+#define PYTHONPATH PREFIX "/lib64/python" VERSION ":" \ |
||||
+ EXEC_PREFIX "/lib64/python" VERSION "/lib-dynload" |
||||
#endif |
||||
|
||||
#ifndef LANDMARK |
||||
@@ -129,7 +129,7 @@ static char prefix[MAXPATHLEN+1]; |
||||
static char exec_prefix[MAXPATHLEN+1]; |
||||
static char progpath[MAXPATHLEN+1]; |
||||
static char *module_search_path = NULL; |
||||
-static char lib_python[] = "lib/python" VERSION; |
||||
+static char lib_python[] = "lib64/python" VERSION; |
||||
|
||||
static void |
||||
reduce(char *dir) |
||||
@@ -528,7 +528,7 @@ calculate_path(void) |
||||
} |
||||
else |
||||
strncpy(zip_path, PREFIX, MAXPATHLEN); |
||||
- joinpath(zip_path, "lib/python00.zip"); |
||||
+ joinpath(zip_path, "lib64/python00.zip"); |
||||
bufsz = strlen(zip_path); /* Replace "00" with version */ |
||||
zip_path[bufsz - 6] = VERSION[0]; |
||||
zip_path[bufsz - 5] = VERSION[2]; |
||||
@@ -538,7 +538,7 @@ calculate_path(void) |
||||
fprintf(stderr, |
||||
"Could not find platform dependent libraries <exec_prefix>\n"); |
||||
strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); |
||||
- joinpath(exec_prefix, "lib/lib-dynload"); |
||||
+ joinpath(exec_prefix, "lib64/lib-dynload"); |
||||
} |
||||
/* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ |
||||
|
||||
diff -up Python-2.7.3/Modules/Setup.dist.lib64 Python-2.7.3/Modules/Setup.dist |
||||
--- Python-2.7.3/Modules/Setup.dist.lib64 2013-02-19 13:58:20.442015131 -0500 |
||||
+++ Python-2.7.3/Modules/Setup.dist 2013-02-19 14:02:25.255998391 -0500 |
||||
@@ -413,7 +413,7 @@ gdbm gdbmmodule.c -lgdbm |
||||
# Edit the variables DB and DBLIBVERto point to the db top directory |
||||
# and the subdirectory of PORT where you built it. |
||||
DBINC=/usr/include/libdb |
||||
-DBLIB=/usr/lib |
||||
+DBLIB=/usr/lib64 |
||||
_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb |
||||
|
||||
# Historical Berkeley DB 1.85 |
||||
@@ -459,7 +459,7 @@ cPickle cPickle.c |
||||
# Andrew Kuchling's zlib module. |
||||
# This require zlib 1.1.3 (or later). |
||||
# See http://www.gzip.org/zlib/ |
||||
-zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz |
||||
+zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib64 -lz |
||||
|
||||
# Interface to the Expat XML parser |
||||
# |
||||
diff -up Python-2.7.3/setup.py.lib64 Python-2.7.3/setup.py |
||||
--- Python-2.7.3/setup.py.lib64 2012-04-09 19:07:36.000000000 -0400 |
||||
+++ Python-2.7.3/setup.py 2013-02-19 13:58:20.449015129 -0500 |
||||
@@ -369,7 +369,7 @@ class PyBuildExt(build_ext): |
||||
|
||||
def detect_modules(self): |
||||
# Ensure that /usr/local is always used |
||||
- add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') |
||||
+ add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib64') |
||||
add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') |
||||
self.add_gcc_paths() |
||||
self.add_multiarch_paths() |
||||
@@ -677,11 +677,11 @@ class PyBuildExt(build_ext): |
||||
elif curses_library: |
||||
readline_libs.append(curses_library) |
||||
elif self.compiler.find_library_file(lib_dirs + |
||||
- ['/usr/lib/termcap'], |
||||
+ ['/usr/lib64/termcap'], |
||||
'termcap'): |
||||
readline_libs.append('termcap') |
||||
exts.append( Extension('readline', ['readline.c'], |
||||
- library_dirs=['/usr/lib/termcap'], |
||||
+ library_dirs=['/usr/lib64/termcap'], |
||||
extra_link_args=readline_extra_link_args, |
||||
libraries=readline_libs) ) |
||||
else: |
||||
@@ -715,8 +715,8 @@ class PyBuildExt(build_ext): |
||||
if krb5_h: |
||||
ssl_incs += krb5_h |
||||
ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs, |
||||
- ['/usr/local/ssl/lib', |
||||
- '/usr/contrib/ssl/lib/' |
||||
+ ['/usr/local/ssl/lib64', |
||||
+ '/usr/contrib/ssl/lib64/' |
||||
] ) |
||||
|
||||
if (ssl_incs is not None and |
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
diff -up Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep Python-2.7rc1/Lib/ctypes/util.py |
||||
--- Python-2.7rc1/Lib/ctypes/util.py.binutils-no-dep 2010-03-15 09:42:23.000000000 -0400 |
||||
+++ Python-2.7rc1/Lib/ctypes/util.py 2010-06-06 05:03:02.155975210 -0400 |
||||
@@ -140,7 +140,9 @@ elif os.name == "posix": |
||||
dump = f.read() |
||||
rv = f.close() |
||||
if rv == 10: |
||||
- raise OSError, 'objdump command not found' |
||||
+ return os.path.basename(f) # This is good for GLibc, I think, |
||||
+ # and a dep on binutils is big (for |
||||
+ # live CDs). |
||||
f = os.popen(cmd) |
||||
try: |
||||
data = f.read() |
@ -0,0 +1,64 @@
@@ -0,0 +1,64 @@
|
||||
--- Python-2.7rc1/Modules/socketmodule.c.socketmodule 2010-05-09 10:46:46.000000000 -0400 |
||||
+++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:04:19.374234780 -0400 |
||||
@@ -4783,6 +4783,61 @@ init_socket(void) |
||||
PyModule_AddIntConstant(m, "SO_SETFIB", SO_SETFIB); |
||||
#endif |
||||
|
||||
+#ifdef SO_SNDBUFFORCE |
||||
+ PyModule_AddIntConstant(m, "SO_SNDBUFFORCE", SO_SNDBUFFORCE); |
||||
+#endif |
||||
+#ifdef SO_RCVBUFFORCE |
||||
+ PyModule_AddIntConstant(m, "SO_RCVBUFFORCE", SO_RCVBUFFORCE); |
||||
+#endif |
||||
+#ifdef SO_NO_CHECK |
||||
+ PyModule_AddIntConstant(m, "SO_NO_CHECK", SO_NO_CHECK); |
||||
+#endif |
||||
+#ifdef SO_PRIORITY |
||||
+ PyModule_AddIntConstant(m, "SO_PRIORITY", SO_PRIORITY); |
||||
+#endif |
||||
+#ifdef SO_BSDCOMPAT |
||||
+ PyModule_AddIntConstant(m, "SO_BSDCOMPAT", SO_BSDCOMPAT); |
||||
+#endif |
||||
+#ifdef SO_PASSCRED |
||||
+ PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED); |
||||
+#endif |
||||
+#ifdef SO_PEERCRED |
||||
+ PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED); |
||||
+#endif |
||||
+#ifdef SO_SECURITY_AUTHENTICATION |
||||
+ PyModule_AddIntConstant(m, "SO_SECURITY_AUTHENTICATION", SO_SECURITY_AUTHENTICATION); |
||||
+#endif |
||||
+#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT |
||||
+ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_TRANSPORT", SO_SECURITY_ENCRYPTION_TRANSPORT); |
||||
+#endif |
||||
+#ifdef SO_SECURITY_ENCRYPTION_NETWORK |
||||
+ PyModule_AddIntConstant(m, "SO_SECURITY_ENCRYPTION_NETWORK", SO_SECURITY_ENCRYPTION_NETWORK); |
||||
+#endif |
||||
+#ifdef SO_BINDTODEVICE |
||||
+ PyModule_AddIntConstant(m, "SO_BINDTODEVICE", SO_BINDTODEVICE); |
||||
+#endif |
||||
+#ifdef SO_ATTACH_FILTER |
||||
+ PyModule_AddIntConstant(m, "SO_ATTACH_FILTER", SO_ATTACH_FILTER); |
||||
+#endif |
||||
+#ifdef SO_DETACH_FILTER |
||||
+ PyModule_AddIntConstant(m, "SO_DETACH_FILTER", SO_DETACH_FILTER); |
||||
+#endif |
||||
+#ifdef SO_PEERNAME |
||||
+ PyModule_AddIntConstant(m, "SO_PEERNAME", SO_PEERNAME); |
||||
+#endif |
||||
+#ifdef SO_TIMESTAMP |
||||
+ PyModule_AddIntConstant(m, "SO_TIMESTAMP", SO_TIMESTAMP); |
||||
+#endif |
||||
+#ifdef SO_PEERSEC |
||||
+ PyModule_AddIntConstant(m, "SO_PEERSEC", SO_PEERSEC); |
||||
+#endif |
||||
+#ifdef SO_PASSSEC |
||||
+ PyModule_AddIntConstant(m, "SO_PASSSEC", SO_PASSSEC); |
||||
+#endif |
||||
+#ifdef SO_TIMESTAMPNS |
||||
+ PyModule_AddIntConstant(m, "SO_TIMESTAMPNS", SO_TIMESTAMPNS); |
||||
+#endif |
||||
+ |
||||
/* Maximum number of connections for "listen" */ |
||||
#ifdef SOMAXCONN |
||||
PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN); |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
diff -up Python-2.7rc1/Modules/socketmodule.c.socketmodule2 Python-2.7rc1/Modules/socketmodule.c |
||||
--- Python-2.7rc1/Modules/socketmodule.c.socketmodule2 2010-06-07 23:06:59.133498087 -0400 |
||||
+++ Python-2.7rc1/Modules/socketmodule.c 2010-06-07 23:11:51.249520087 -0400 |
||||
@@ -5253,6 +5253,15 @@ init_socket(void) |
||||
#ifdef TCP_QUICKACK |
||||
PyModule_AddIntConstant(m, "TCP_QUICKACK", TCP_QUICKACK); |
||||
#endif |
||||
+#ifdef TCP_CONGESTION |
||||
+ PyModule_AddIntConstant(m, "TCP_CONGESTION", TCP_CONGESTION); |
||||
+#endif |
||||
+#ifdef TCP_MD5SIG |
||||
+ PyModule_AddIntConstant(m, "TCP_MD5SIG", TCP_MD5SIG); |
||||
+#endif |
||||
+#ifdef TCP_MD5SIG_MAXKEYLEN |
||||
+ PyModule_AddIntConstant(m, "TCP_MD5SIG_MAXKEYLEN", TCP_MD5SIG_MAXKEYLEN); |
||||
+#endif |
||||
|
||||
|
||||
/* IPX options */ |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash |
||||
|
||||
[ $# -ge 1 ] || { |
||||
cat > /dev/null |
||||
exit 0 |
||||
} |
||||
|
||||
case $1 in |
||||
-P|--provides) |
||||
shift |
||||
# Match buildroot/payload paths of the form |
||||
# /PATH/OF/BUILDROOT/usr/bin/pythonMAJOR.MINOR |
||||
# generating a line of the form |
||||
# python(abi) = MAJOR.MINOR |
||||
# (Don't match against -config tools e.g. /usr/bin/python2.6-config) |
||||
grep "/usr/bin/python.\..$" \ |
||||
| sed -e "s|.*/usr/bin/python\(.\..\)|python(abi) = \1|" |
||||
;; |
||||
-R|--requires) |
||||
shift |
||||
# Match buildroot paths of the form |
||||
# /PATH/OF/BUILDROOT/usr/lib/pythonMAJOR.MINOR/ and |
||||
# /PATH/OF/BUILDROOT/usr/lib64/pythonMAJOR.MINOR/ |
||||
# generating (uniqely) lines of the form: |
||||
# python(abi) = MAJOR.MINOR |
||||
grep "/usr/lib[^/]*/python.\../.*" \ |
||||
| sed -e "s|.*/usr/lib[^/]*/python\(.\..\)/.*|python(abi) = \1|g" \ |
||||
| sort | uniq |
||||
;; |
||||
esac |
||||
|
||||
exit 0 |
Loading…
Reference in new issue