=== modified file 'OpenSSL/ssl/context.c'
--- OpenSSL/ssl/context.c	2011-09-11 13:35:32 +0000
+++ OpenSSL/ssl/context.c	2012-02-09 05:35:09 +0000
@@ -238,6 +238,66 @@
 }
 
 /*
+ * Globally defined next proto callback.  This is called from OpenSSL internally.
+ * The GIL will not be held when this function is invoked.  It must not be held
+ * when the function returns.
+ *
+ * Arguments: ssl   - The Connection
+ *            **out - handle to where we can put a new string to be returned
+ *            *outlen - pointer to where we can put the len of the string we want to return
+ * Returns:   SSL_TLSEXT_ERR_OK
+ */
+static int
+global_next_proto_callback(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg)
+{
+    ssl_ConnectionObj *conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl);
+    PyObject *argv, *ret, *item;
+    Py_ssize_t length, i, strlength;
+    unsigned char *outptr;
+
+    /*
+     * GIL isn't held yet.  First things first - acquire it, or any Python API
+     * we invoke might segfault or blow up the sun.  The reverse will be done
+     * before returning.
+     */
+    MY_END_ALLOW_THREADS(conn->tstate);
+
+    argv = Py_BuildValue("(O)", (PyObject *)conn);
+    ret = PyEval_CallObject(conn->context->next_protos_advertised_callback, argv);
+    Py_DECREF(argv);
+
+    length = PyList_Size(ret);
+    for (i = 0; i < length; i++) {
+        *outlen += PyBytes_Size(PyList_GetItem(ret, i)) + 1;
+        /* FIXME: need to test that all strings are less than 255 */
+    }
+    *out = outptr = OPENSSL_malloc(*outlen);
+    for (i = 0; i < length; i++) {
+        item = PyList_GetItem(ret, i);
+        strlength = PyBytes_Size(item);
+        *outptr = Py_SAFE_DOWNCAST(strlength, Py_ssize_t, char);
+        outptr++;
+        strncpy((char *)outptr, PyString_AsString(item), strlength);
+        outptr += strlength; 
+    }
+    
+    if (ret == NULL) {
+        /*
+         * XXX - This should be reported somehow. -exarkun
+         */
+        PyErr_Clear();
+    } else {
+        Py_DECREF(ret);
+    }
+
+    /*
+     * This function is returning into OpenSSL.  Release the GIL again.
+     */
+    MY_BEGIN_ALLOW_THREADS(conn->tstate);
+    return SSL_TLSEXT_ERR_OK;
+}
+
+/*
  * Globally defined TLS extension server name callback.  This is called from
  * OpenSSL internally.  The GIL will not be held when this function is invoked.
  * It must not be held when the function returns.
@@ -1030,6 +1090,35 @@
     return Py_None;
 }
 
+static char ssl_Context_set_next_protos_advertised_callback_doc[] = "\n\
+Set the next protos advertised callback\n\
+\n\
+:param callback: The Python callback to use\n\
+:return: None\n\
+";
+static PyObject *
+ssl_Context_set_next_protos_advertised_callback(ssl_ContextObj *self, PyObject *args)
+{
+    PyObject *callback;
+
+    if (!PyArg_ParseTuple(args, "O:set_next_protos_advertised_callback", &callback))
+        return NULL;
+
+    if (!PyCallable_Check(callback))
+    {
+        PyErr_SetString(PyExc_TypeError, "expected PyCallable");
+        return NULL;
+    }
+
+    Py_DECREF(self->next_protos_advertised_callback);
+    Py_INCREF(callback);
+    self->next_protos_advertised_callback = callback;
+    SSL_CTX_set_next_protos_advertised_cb(self->ctx, global_next_proto_callback, NULL);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static char ssl_Context_get_app_data_doc[] = "\n\
 Get the application data (supplied via set_app_data())\n\
 \n\
@@ -1187,6 +1276,7 @@
     ADD_METHOD(set_timeout),
     ADD_METHOD(get_timeout),
     ADD_METHOD(set_info_callback),
+    ADD_METHOD(set_next_protos_advertised_callback),
     ADD_METHOD(get_app_data),
     ADD_METHOD(set_app_data),
     ADD_METHOD(get_cert_store),
@@ -1241,6 +1331,9 @@
     self->info_callback = Py_None;
 
     Py_INCREF(Py_None);
+    self->next_protos_advertised_callback = Py_None;
+
+    Py_INCREF(Py_None);
     self->tlsext_servername_callback = Py_None;
 
     Py_INCREF(Py_None);
@@ -1320,6 +1413,8 @@
         ret = visit((PyObject *)self->verify_callback, arg);
     if (ret == 0 && self->info_callback != NULL)
         ret = visit((PyObject *)self->info_callback, arg);
+    if (ret == 0 && self->next_protos_advertised_callback != NULL)
+        ret = visit((PyObject *)self->next_protos_advertised_callback, arg);
     if (ret == 0 && self->app_data != NULL)
         ret = visit(self->app_data, arg);
     return ret;
@@ -1342,6 +1437,8 @@
     self->verify_callback = NULL;
     Py_XDECREF(self->info_callback);
     self->info_callback = NULL;
+    Py_XDECREF(self->next_protos_advertised_callback);
+    self->next_protos_advertised_callback = NULL;
     Py_XDECREF(self->app_data);
     self->app_data = NULL;
     return 0;

=== modified file 'OpenSSL/ssl/context.h'
--- OpenSSL/ssl/context.h	2011-05-26 22:47:00 +0000
+++ OpenSSL/ssl/context.h	2012-02-09 05:09:32 +0000
@@ -29,6 +29,7 @@
                         *passphrase_userdata,
                         *verify_callback,
                         *info_callback,
+                        *next_protos_advertised_callback,
                         *tlsext_servername_callback,
                         *app_data;
     PyThreadState       *tstate;

=== modified file 'OpenSSL/test/test_ssl.py'
--- OpenSSL/test/test_ssl.py	2011-09-11 14:01:31 +0000
+++ OpenSSL/test/test_ssl.py	2012-02-09 05:13:06 +0000
@@ -587,6 +587,41 @@
         # Kind of lame.  Just make sure it got called somehow.
         self.assertTrue(called)
 
+    def FAIL_test_set_next_protos_advertised_callback_callback(self):
+        """
+        :py:obj:`Context.set_info_callback` accepts a callable which will be invoked
+        when certain information about an SSL connection is available.
+        """
+        (server, client) = socket_pair()
+
+        clientSSL = Connection(Context(SSLv3_METHOD), client)
+        clientSSL.set_connect_state()
+
+        called = []
+        def next_protos_advertised(conn):
+            called.append(conn)
+            return ['spdy/2', 'http/1.1']
+        context = Context(SSLv3_METHOD)
+        context.set_next_protos_advertised_callback(next_protos_advertised)
+        context.use_certificate(
+            load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
+        context.use_privatekey(
+            load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
+
+        serverSSL = Connection(context, server)
+        serverSSL.set_accept_state()
+
+        while not called:
+            for ssl in clientSSL, serverSSL:
+                try:
+                    ssl.do_handshake()
+                except WantReadError:
+                    print 'r'
+                    pass
+
+        # Kind of lame.  Just make sure it got called somehow.
+        self.assertTrue(called)
+
 
     def _load_verify_locations_test(self, *args):
         """