]> granicus.if.org Git - python/commitdiff
Issue #10075: Add a session_stats() method to SSLContext objects.
authorAntoine Pitrou <solipsis@pitrou.net>
Tue, 12 Oct 2010 20:09:02 +0000 (20:09 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Tue, 12 Oct 2010 20:09:02 +0000 (20:09 +0000)
Doc/library/ssl.rst
Lib/test/test_ssl.py
Misc/NEWS
Modules/_ssl.c

index f36dbc766642f5c89be6706e60befe553e06b9cd..c9c6ca0de327e6888ad14d9636fbe02ddb2e92f8 100644 (file)
@@ -481,13 +481,17 @@ SSL Contexts
 
 .. versionadded:: 3.2
 
+An SSL context holds various data longer-lived than single SSL connections,
+such as SSL configuration options, certificate(s) and private key(s).
+It also manages a cache of SSL sessions for server-side sockets, in order
+to speed up repeated connections from the same clients.
+
 .. class:: SSLContext(protocol)
 
-   An object holding various data longer-lived than single SSL connections,
-   such as SSL configuration options, certificate(s) and private key(s).
-   You must pass *protocol* which must be one of the ``PROTOCOL_*`` constants
-   defined in this module.  :data:`PROTOCOL_SSLv23` is recommended for
-   maximum interoperability.
+   Create a new SSL context.  You must pass *protocol* which must be one
+   of the ``PROTOCOL_*`` constants defined in this module.
+   :data:`PROTOCOL_SSLv23` is recommended for maximum interoperability.
+
 
 :class:`SSLContext` objects have the following methods and attributes:
 
@@ -542,6 +546,18 @@ SSL Contexts
    and *suppress_ragged_eofs* have the same meaning as in the top-level
    :func:`wrap_socket` function.
 
+.. method:: SSLContext.session_stats()
+
+   Get statistics about the SSL sessions created or managed by this context.
+   A dictionary is returned which maps the names of each `piece of information
+   <http://www.openssl.org/docs/ssl/SSL_CTX_sess_number.html>`_ to their
+   numeric values.  For example, here is the total number of hits and misses
+   in the session cache since the context was created::
+
+      >>> stats = context.session_stats()
+      >>> stats['hits'], stats['misses']
+      (0, 0)
+
 .. attribute:: SSLContext.options
 
    An integer representing the set of SSL options enabled on this context.
index b4ec4d52b5736251dd1b3846c4dac5de76c8e251..bf08f6fe1eb5dec412ef4d10e0fbf6e168284e1b 100644 (file)
@@ -391,6 +391,23 @@ class ContextTests(unittest.TestCase):
         ctx.load_verify_locations(CERTFILE, CAPATH)
         ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH)
 
+    def test_session_stats(self):
+        for proto in PROTOCOLS:
+            ctx = ssl.SSLContext(proto)
+            self.assertEqual(ctx.session_stats(), {
+                'number': 0,
+                'connect': 0,
+                'connect_good': 0,
+                'connect_renegotiate': 0,
+                'accept': 0,
+                'accept_good': 0,
+                'accept_renegotiate': 0,
+                'hits': 0,
+                'misses': 0,
+                'timeouts': 0,
+                'cache_full': 0,
+            })
+
 
 class NetworkedTests(unittest.TestCase):
 
index ab0e29c3d80552cea1c569e5b54f1a8a6d6a9418..597f76bfb0e2d87e8e0fc72a7b14ee8d91b1c675 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #10075: Add a session_stats() method to SSLContext objects.
+
 - Issue #9948: Fixed problem of losing filename case information.
 
 Extensions
index fd0ea43fe40b316ce55d13113f9597902dcbe93f..254dde69eb2e41acf340806dea5ea831c4086333 100644 (file)
@@ -1716,6 +1716,45 @@ context_wrap_socket(PySSLContext *self, PyObject *args, PyObject *kwds)
     return (PyObject *) newPySSLSocket(self->ctx, sock, server_side);
 }
 
+static PyObject *
+session_stats(PySSLContext *self, PyObject *unused)
+{
+    int r;
+    PyObject *value, *stats = PyDict_New();
+    if (!stats)
+        return NULL;
+
+#define ADD_STATS(SSL_NAME, KEY_NAME) \
+    value = PyLong_FromLong(SSL_CTX_sess_ ## SSL_NAME (self->ctx)); \
+    if (value == NULL) \
+        goto error; \
+    r = PyDict_SetItemString(stats, KEY_NAME, value); \
+    Py_DECREF(value); \
+    if (r < 0) \
+        goto error;
+
+    ADD_STATS(number, "number");
+    ADD_STATS(connect, "connect");
+    ADD_STATS(connect_good, "connect_good");
+    ADD_STATS(connect_renegotiate, "connect_renegotiate");
+    ADD_STATS(accept, "accept");
+    ADD_STATS(accept_good, "accept_good");
+    ADD_STATS(accept_renegotiate, "accept_renegotiate");
+    ADD_STATS(accept, "accept");
+    ADD_STATS(hits, "hits");
+    ADD_STATS(misses, "misses");
+    ADD_STATS(timeouts, "timeouts");
+    ADD_STATS(cache_full, "cache_full");
+
+#undef ADD_STATS
+
+    return stats;
+
+error:
+    Py_DECREF(stats);
+    return NULL;
+}
+
 static PyGetSetDef context_getsetlist[] = {
     {"options", (getter) get_options,
                 (setter) set_options, NULL},
@@ -1733,6 +1772,8 @@ static struct PyMethodDef context_methods[] = {
                         METH_VARARGS | METH_KEYWORDS, NULL},
     {"load_verify_locations", (PyCFunction) load_verify_locations,
                               METH_VARARGS | METH_KEYWORDS, NULL},
+    {"session_stats", (PyCFunction) session_stats,
+                      METH_NOARGS, NULL},
     {NULL, NULL}        /* sentinel */
 };