[IronPython] ssl server mode issue

Dino Viehland dinov at microsoft.com
Fri Apr 23 00:46:11 CEST 2010


Ok, took me a while to get back to this, but I haven’t forgotten.  So I’ve taken your code below and combined it with the code in test_ssl to have the full end to end test case.  I’ve included that here.  Let me know if there’s anything that’s significantly different.

First thing I tried w/ this was using the ‘keycert.pem’ which copes with the CPython test case and that seemed to behave similarly between IronPython and CPython.  There does seem to be one difference which is with CPython the connection from the browser stays open and w/ IronPython it closes.  This is after a GET request which we can’t respond to:

DINOV1.redmond.corp.microsoft.com - - [22/Apr/2010 15:38:16] code 501, message Unsupported method ('GET')
DINOV1.redmond.corp.microsoft.com - - [22/Apr/2010 15:38:16] "GET / HTTP/1.1" 501 –

That’s probably a bug but not the issue you’re running into but I’ve opened a bug here: http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=26852.

So then I generated a self-signed request as described here: http://sial.org/howto/openssl/self-signed/ with a .cnf file as described here: http://bugs.gentoo.org/show_bug.cgi?id=251047 but minus the x509_extensions line.  With that I get the same result as I get with keycert.pem.

So my guess is that I’m not generating the self signed certificate in the same way that you are and that there’s something about your cert which doesn’t work.  Does your generation differ from what I did?

import BaseHTTPServer
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import threading
import socket
import sys
import traceback
import ssl
CERTFILE = 'host.pem'
HOST='localhost'
import time

class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_CONNECT(self):
        print self.raw_requestline
        # "CONNECT twitter.com:443 HTTP/1.1"
        self.sslhost = self.raw_requestline.split()[1]
        self.wfile.write(self.protocol_version + " 200 Connection established\r\n")
        self.wfile.write("Proxy-agent: qiuyingbo\r\n\r\n")
        self.rfile = pseudofile(ssl.wrap_socket(self.connection, None, CERTFILE, True))
        self.wfile = self.rfile
        self.handle_one_request()


class SocketServerHTTPSServer(threading.Thread):
    class HTTPSServer(HTTPServer):
        def __init__(self, server_address, RequestHandlerClass, certfile):
            HTTPServer.__init__(self, server_address, RequestHandlerClass)
            # we assume the certfile contains both private key and certificate
            self.certfile = certfile
            self.active = False
            self.active_lock = threading.Lock()
            self.allow_reuse_address = True

        def __str__(self):
            return ('<%s %s:%s>' %
                    (self.__class__.__name__,
                     self.server_name,
                     self.server_port))

        def get_request (self):
            # override this to wrap socket with SSL
            sock, addr = self.socket.accept()
            sslconn = ssl.wrap_socket(sock, server_side=True,
                                      certfile=self.certfile)
            return sslconn, addr

        # The methods overridden below this are mainly so that we
        # can run it in a thread and be able to stop it from another
        # You probably wouldn't need them in other uses.

        def server_activate(self):
            # We want to run this in a thread for testing purposes,
            # so we override this to set timeout, so that we get
            # a chance to stop the server
            self.socket.settimeout(0.5)
            HTTPServer.server_activate(self)

        def serve_forever(self):
            # We want this to run in a thread, so we use a slightly
            # modified version of "forever".
            self.active = True
            while 1:
                try:
                    # We need to lock while handling the request.
                    # Another thread can close the socket after self.active
                    # has been checked and before the request is handled.
                    # This causes an exception when using the closed socket.
                    with self.active_lock:
                        if not self.active:
                            break
                        self.handle_request()
                except socket.timeout:
                    pass
                except KeyboardInterrupt:
                    self.server_close()
                    return
                except:
                    sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())))
                    break
                time.sleep(0.1)

        def server_close(self):
            # Again, we want this to run in a thread, so we need to override
            # close to clear the "active" flag, so that serve_forever() will
            # terminate.
            with self.active_lock:
                HTTPServer.server_close(self)
                self.active = False

    def __init__(self, certfile):
        self.flag = None
        self.active = False
        self.port = 1234
        self.server = self.HTTPSServer(
            (HOST, self.port), ProxyHandler, certfile)
        threading.Thread.__init__(self)
        self.daemon = True

    def __str__(self):
        return "<%s %s>" % (self.__class__.__name__, self.server)

    def start (self, flag=None):
        self.flag = flag
        threading.Thread.start(self)

    def run (self):
        self.active = True
        if self.flag:
            self.flag.set()
        self.server.serve_forever()
        self.active = False

    def stop (self):
        self.active = False
        self.server.server_close()


class pseudofile():
    ''' SSL Pseudo File Object'''
    def __init__(self, sslobj):
        self.sslobj = sslobj
        self.closed = 0

    def read(self, size):
        chunks = []
        read = 0
        while read < size:
            data = self.sslobj.read(size-read)
            read += len(data)
            chunks.append(data)
        return ''.join(chunks)

    def readline(self):
        line = []
        while 1:
            char = self.sslobj.read(1)
            line.append(char)
            if char == "\n": return ''.join(line)

    def write(self, data):
        bytes = len(data)
        while bytes > 0:
            sent = self.sslobj.write(data)
            if sent == bytes:
                break    # avoid copy
            data = data[sent:]
            bytes = bytes - sent

    def flush(self):
        pass
    close = flush


server=SocketServerHTTPSServer(CERTFILE)
flag = threading.Event()
server.start(flag)
# wait for it to start
flag.wait()
print 'started'
time.sleep(100000)


From: users-bounces at lists.ironpython.com [mailto:users-bounces at lists.ironpython.com] On Behalf Of qiuyingbo at sohu.com
Sent: Wednesday, April 14, 2010 5:41 PM
To: Discussion of IronPython
Subject: Re: [IronPython] ssl server mode issue


I'm doing a web browser to ironpython connection. It is difficult to explain what I am doing,  I'm hacking a http proxy that inherit BaseHTTPServer.BaseHTTPRequestHandler. Next code snippets show how I support HTTPS proxy.. (Linux version run well)



class ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_CONNECT(self):
        # print self.raw_requestline
        # "CONNECT twitter.com:443 HTTP/1.1"
        self.sslhost = self.raw_requestline.split()[1]
        self.wfile.write(self.protocol_version + " 200 Connection established\r\n")
        self.wfile.write("Proxy-agent: qiuyingbo\r\n\r\n")
        import ssl
        self.rfile = pseudofile(ssl.wrap_socket(self.connection, None, CERTFILE, True))
        self.wfile = self.rfile
        self.handle_one_request()



class pseudofile():
    ''' SSL Pseudo File Object'''
    def __init__(self, sslobj):
        self.sslobj = sslobj
        self.closed = 0



    def read(self, size):
        chunks = []
        read = 0
        while read < size:
            data = self.sslobj.read(size-read)
            read += len(data)
            chunks.append(data)
        return ''.join(chunks)



    def readline(self):
        line = []
        while 1:
            char = self.sslobj.read(1)
            line.append(char)
            if char == "\n": return ''.join(line)



    def write(self, data):
        bytes = len(data)
        while bytes > 0:
            sent = self.sslobj.write(data)
            if sent == bytes:
                break    # avoid copy
            data = data[sent:]
            bytes = bytes - sent

    def flush(self):
        pass

    close = flush
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/ironpython-users/attachments/20100422/93925ad6/attachment.html>


More information about the Ironpython-users mailing list