1. PageKite: why Python?

    Bjarni Rúnar Einarsson • PageKite.net

  2. What is PageKite?

  3. Enabling (web)servers everywhere

    PageKite is a tool for enabling (web)servers anywhere:

    Problems to solve:

    IPv6?

  4. Diagram: A PageKite-enabled website

  5. pagekite.py + pagekite.net

  6. Introducing pagekite.py

    pagekite.py implements a tunneled reverse proxy.

  7. A trivial example

    This is one way to make a web server on localhost (ports 8000 and 8443) visible as http://bar.foo.net/, ...

    foo.net $ sudo pagekite.py --runas=nobody \
     --isfrontend --ports=80,443 \
     --domain=raw,http,https:*.foo.net:s3cr37
    
    
    laptop $ pagekite.py \
     --frontend=foo.net:443 \
     --backend=http:bar.foo.net:localhost:8000:s3cr37 \
     --backend=https:bar.foo.net:localhost:8443:s3cr37
    
    
  8. Introducing pagekite.net

    pagekite.net is a front-end service provider, a "FOSS start-up"

  9. Use-cases I've seen...

    Some of the use-cases I have seen so far:

    Basically any time a router or firewall is in the way.

  10. ... so why Python?

  11. Choosing a programming language

    Language requirements:

    1. Must not suck!
    2. Same language for program and service
    3. Ease of program deployment
    4. Good support for the WWW

    Things we don't care about (yet):

    1. Raw speed
    2. Footprint (RAM, disk)
  12. So how is it doing? - good

    The good:

  13. So how is it doing? - bad

    The bad:

  14. So how is it doing? - ugly

    Things moved around during Python's development ...

    try:
      from urlparse import parse_qs, urlparse
    
    except ImportError, e:
      from cgi import parse_qs
      from urlparse import urlparse
    
  15. So how is it doing? - ugly

    Argh, different OSes throw different errors!

      HARMLESS_ERRNOS = (errno.EINTR, errno.EAGAIN, errno.ENOMEM, errno.EBUSY,
                         errno.EDEADLK, errno.EWOULDBLOCK, errno.ENOBUFS,
                         errno.EALREADY)
    ...
          try:
            sent_bytes = self.fd.send(sending)
          except IOError, err:
            if err.errno not in self.HARMLESS_ERRNOS:
              self.LogError('Error sending: %s' % err)
              return False
    ...
    
  16. So how is it doing? - ugly

    The SSL APIs are a bit inconsistent, so ...

    def Shutdown(self, direction):
      try:
        if self.fd:
          if 'sock_shutdown' in dir(self.fd):
            # This is a pyOpenSSL socket, which has incompatible shutdown.
            if direction == socket.SHUT_RD: self.fd.shutdown()
          else:
            self.fd.shutdown(direction)
    
      except Exception, e:
        self.LogDebug('Shutdown (%s/%s) error: %s' % (direction, self.fd, e))
    
  17. Thank you!


    Questions?

    Links:

  18. Bonus FAQ slide!