[Inteproxy-commits] r59 - in trunk: . inteproxy test
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Mon Apr 23 14:54:25 CEST 2007
Author: bh
Date: 2007-04-23 14:54:25 +0200 (Mon, 23 Apr 2007)
New Revision: 59
Added:
trunk/inteproxy/
trunk/inteproxy/__init__.py
trunk/inteproxy/getpassword.py
trunk/inteproxy/proxyconnection.py
trunk/inteproxy/threadpool.py
trunk/inteproxy/transcoder.py
Removed:
trunk/getpassword.py
trunk/proxyconnection.py
trunk/threadpool.py
trunk/transcoder.py
Modified:
trunk/ChangeLog
trunk/InteProxy.py
trunk/test/test_owsproxy_get_transcoder.py
trunk/test/test_owsproxy_post_transcoder.py
trunk/test/test_threadpool.py
trunk/test/test_transcoder_map.py
Log:
* inteproxy, inteproxy/__init__.py: New. Introduce inteproxy
package for better code organisation
* getpassword.py, proxyconnection.py, threadpool.py, transcoder.py:
Moved to the new inteproxy package
* InteProxy.py, test/test_owsproxy_get_transcoder.py,
test/test_owsproxy_post_transcoder.py, test/test_threadpool.py,
test/test_transcoder_map.py: Adapt to code reorganization
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/ChangeLog 2007-04-23 12:54:25 UTC (rev 59)
@@ -1,3 +1,15 @@
+2007-04-23 Bernhard Herzog <bh at intevation.de>
+
+ * inteproxy, inteproxy/__init__.py: New. Introduce inteproxy
+ package for better code organisation
+
+ * getpassword.py, proxyconnection.py, threadpool.py, transcoder.py:
+ Moved to the new inteproxy package
+
+ * InteProxy.py, test/test_owsproxy_get_transcoder.py,
+ test/test_owsproxy_post_transcoder.py, test/test_threadpool.py,
+ test/test_transcoder_map.py: Adapt to code reorganization
+
2007-04-20 Stephan Holl <stephan.holl at intevation.de>
* website/index-de.htm4: german translation finished
Modified: trunk/InteProxy.py
===================================================================
--- trunk/InteProxy.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/InteProxy.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -22,10 +22,10 @@
import urllib2
import BaseHTTPServer
import socket
-import proxyconnection
-from transcoder import transcoder_map
-from getpassword import getpassword
-from threadpool import ThreadPool
+import inteproxy.proxyconnection as proxyconnection
+from inteproxy.transcoder import transcoder_map
+from inteproxy.getpassword import getpassword
+from inteproxy.threadpool import ThreadPool
inteproxy_version = "0.1.2"
Deleted: trunk/getpassword.py
===================================================================
--- trunk/getpassword.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/getpassword.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -1,120 +0,0 @@
-# Copyright (C) 2007 by Intevation GmbH
-# Authors:
-# Bernhard Herzog <bh at intevation.de>
-#
-# This program is free software under the GPL (>=v2)
-# Read the file COPYING coming with the software for details.
-
-"""Code to ask the user for username and password"""
-
-import threading
-import traceback
-
-# Determine the window system we're using. This determines how the user
-# is asked for the username/password.
-try:
- # If gtk isn't available, we get an ImportError here. However, on
- # Unix, if we gtk cannot establish the connection to the X-server,
- # we get a RuntimeError here. We do not catch the RuntimeError for
- # now, because we want to use gtk by default and don't want to hide
- # configuration errors like missing or incorrect DISPLAY variables.
- import gtk
- windowsystem = "gtk"
-except ImportError:
- try:
- import pywin.dialogs.login
- windowsystem = "pywin"
- except ImportError:
- windowsystem = "tty"
-
-def getpassword_gtk(title):
- dialog = gtk.Dialog("My dialog", None,
- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
- (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
- gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
- label = gtk.Label(title)
- label.show()
- dialog.vbox.pack_start(label, True, True, 5)
-
- table = gtk.Table(2, 2)
- dialog.vbox.pack_start(table)
-
- def add_field(row, name, visibility):
- label = gtk.Label(name)
- label.set_alignment(1.0, 0.5)
- table.attach(label, 0, 1, row, row + 1, xoptions=gtk.FILL,
- xpadding=5, ypadding=5)
- entry = gtk.Entry()
- entry.set_visibility(visibility)
- table.attach(entry, 1, 2, row, row + 1, xoptions=gtk.FILL|gtk.EXPAND,
- xpadding=5, ypadding=5)
- return entry
-
- username_entry = add_field(0, "Username:", True)
- password_entry = add_field(1, "Password:", False)
-
- table.show_all()
-
- if dialog.run() == gtk.RESPONSE_ACCEPT:
- result = (username_entry.get_text(),
- password_entry.get_text())
- else:
- result = None
-
- dialog.destroy()
-
- # process pending events to make sure the dialog is destroyed and
- # unmapped properly from the screen.
- while gtk.events_pending():
- gtk.main_iteration_do()
-
- return result
-
-def getpassword_pywin(title):
- return pywin.dialogs.login.GetLogin(title)
-
-def getpassword_tty(title):
- import getpass
- try:
- user = raw_input(title)
- password = getpass.getpass()
- except IOError:
- import traceback
- traceback.print_exception()
- user = password = None
- return user, password
-
-getpassword = globals()["getpassword_" + windowsystem]
-
-# password cache and lock
-pw_cache = {}
-pw_lock = threading.Lock()
-
-def get_password_with_cache(path):
- """Ask the user for a username and password and cache the
- information. The path parameter should be a string with hostname
- and path of the URL the caller is trying to access. If a username
- and password for that string is already stored in the cache, the
- cached information is returned. Otherwise this function uses the
- getpassword function to ask the user and then adds this information
- to the cache and returns it.
-
- The return value is the tuple (username, password).
- """
- pw_lock.acquire()
- try:
- if path in pw_cache:
- user, password = pw_cache[path]
- else:
- title = "Username for %s: " % path
- user, password = getpassword(title)
- pw_cache[path] = user, password
-
- return user, password
- finally:
- pw_lock.release()
-
-
-if __name__ == "__main__":
- result = getpassword("Password Dialog Test")
- print repr(result)
Added: trunk/inteproxy/__init__.py
===================================================================
Property changes on: trunk/inteproxy/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ native
Copied: trunk/inteproxy/getpassword.py (from rev 58, trunk/getpassword.py)
Copied: trunk/inteproxy/proxyconnection.py (from rev 58, trunk/proxyconnection.py)
Copied: trunk/inteproxy/threadpool.py (from rev 58, trunk/threadpool.py)
Copied: trunk/inteproxy/transcoder.py (from rev 58, trunk/transcoder.py)
Deleted: trunk/proxyconnection.py
===================================================================
--- trunk/proxyconnection.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/proxyconnection.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -1,117 +0,0 @@
-# Copyright (C) 2006 by Alessandro Budai
-# from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/456195
-#
-# This software may be used and distributed according to the terms
-# of the Python License 2.3 or newer, see http://www.python.org/license
-
-"""
-urrlib2 opener for SSL proxy (CONNECT method)
-
-This small module builds an urllib2 opener that can be used to make a
-connection through a proxy using the http CONNECT method (that can be used to
-proxy SSLconnections). The current urrlib2 seems to not support this method.
-
-tested with python 2.4
-"""
-
-import urllib2
-import urllib
-import httplib
-import socket
-
-
-class ProxyHTTPConnection(httplib.HTTPConnection):
-
- _ports = {'http' : 80, 'https' : 443}
-
-
- def request(self, method, url, body=None, headers={}):
- #request is called before connect, so can interpret url and get
- #real host/port to be used to make CONNECT request to proxy
- proto, rest = urllib.splittype(url)
- if proto is None:
- raise ValueError, "unknown URL type: %s" % url
- #get host
- host, rest = urllib.splithost(rest)
- #try to get port
- host, port = urllib.splitport(host)
- #if port is not defined try to get from proto
- if port is None:
- try:
- port = self._ports[proto]
- except KeyError:
- raise ValueError, "unknown protocol for: %s" % url
- self._real_host = host
- self._real_port = int(port)
- httplib.HTTPConnection.request(self, method, rest or '/', body, headers)
-
-
- def connect(self):
- httplib.HTTPConnection.connect(self)
- #send proxy CONNECT request
- self.send("CONNECT %s:%d HTTP/1.0\r\n\r\n" % (self._real_host, self._real_port))
- #expect a HTTP/1.0 200 Connection established
- response = self.response_class(self.sock, strict=self.strict, method=self._method)
- (version, code, message) = response._read_status()
- #probably here we can handle auth requests...
- if code != 200:
- #proxy returned and error, abort connection, and raise exception
- self.close()
- raise socket.error, "Proxy connection failed: %d %s" % (code, message.strip())
- #eat up header block from proxy....
- while True:
- #should not use directly fp probably
- line = response.fp.readline()
- if line == '\r\n': break
-
-
-class ProxyHTTPSConnection(ProxyHTTPConnection):
-
- default_port = 443
-
- def __init__(self, host, port = None, key_file = None, cert_file = None, strict = None):
- ProxyHTTPConnection.__init__(self, host, port)
- self.key_file = key_file
- self.cert_file = cert_file
-
- def connect(self):
- ProxyHTTPConnection.connect(self)
- #make the sock ssl-aware
- ssl = socket.ssl(self.sock, self.key_file, self.cert_file)
- self.sock = httplib.FakeSocket(self.sock, ssl)
-
-
-class ConnectHTTPHandler(urllib2.HTTPHandler):
-
- def __init__(self, proxy=None, debuglevel=0):
- self.proxy = proxy
- urllib2.HTTPHandler.__init__(self, debuglevel)
-
- def do_open(self, http_class, req):
- if self.proxy is not None:
- req.set_proxy(self.proxy, 'http')
- return urllib2.HTTPHandler.do_open(self, ProxyHTTPConnection, req)
-
-
-class ConnectHTTPSHandler(urllib2.HTTPSHandler):
-
- def __init__(self, proxy=None, debuglevel=0):
- self.proxy = proxy
- urllib2.HTTPSHandler.__init__(self, debuglevel)
-
- def do_open(self, http_class, req):
- if self.proxy is not None:
- req.set_proxy(self.proxy, 'https')
- return urllib2.HTTPSHandler.do_open(self, ProxyHTTPSConnection, req)
-
-
-if __name__ == '__main__':
-
- import sys
-
- opener = urllib2.build_opener(ConnectHTTPHandler(sys.argv[2]),
- ConnectHTTPSHandler(sys.argv[2]))
- urllib2.install_opener(opener)
- req = urllib2.Request(url=sys.argv[1])
- f = urllib2.urlopen(req)
- print f.read()
Modified: trunk/test/test_owsproxy_get_transcoder.py
===================================================================
--- trunk/test/test_owsproxy_get_transcoder.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/test/test_owsproxy_get_transcoder.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -10,7 +10,7 @@
import urlparse
import unittest
-from transcoder import OWSProxyGETTranscoder
+from inteproxy.transcoder import OWSProxyGETTranscoder
class TestOWSProxyGETTranscoder(unittest.TestCase):
Modified: trunk/test/test_owsproxy_post_transcoder.py
===================================================================
--- trunk/test/test_owsproxy_post_transcoder.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/test/test_owsproxy_post_transcoder.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -8,7 +8,7 @@
"""Tests for OWSProxyPOSTTranscoder"""
import unittest
-from transcoder import OWSProxyPOSTTranscoder
+from inteproxy.transcoder import OWSProxyPOSTTranscoder
class TestOWSProxyPOSTTranscoder(unittest.TestCase):
Modified: trunk/test/test_threadpool.py
===================================================================
--- trunk/test/test_threadpool.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/test/test_threadpool.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -10,7 +10,7 @@
import threading
import unittest
-import threadpool
+import inteproxy.threadpool
def currentThreadSet():
"""Returns the currently running threads as a set"""
@@ -32,7 +32,7 @@
initial_threads = currentThreadSet()
# Create a thread pool and start its threads
- pool = threadpool.ThreadPool(5, handler)
+ pool = inteproxy.threadpool.ThreadPool(5, handler)
pool.start()
# check that 5 new threads have been started
Modified: trunk/test/test_transcoder_map.py
===================================================================
--- trunk/test/test_transcoder_map.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/test/test_transcoder_map.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -11,7 +11,7 @@
import support
-from transcoder import create_transcoder_map, \
+from inteproxy.transcoder import create_transcoder_map, \
OWSProxyGETTranscoder, OWSProxyPOSTTranscoder, IdentityTranscoder
Deleted: trunk/threadpool.py
===================================================================
--- trunk/threadpool.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/threadpool.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -1,72 +0,0 @@
-# Copyright (C) 2007 by Intevation GmbH
-# Authors:
-# Bernhard Herzog <bh at intevation.de>
-#
-# This program is free software under the GPL (>=v2)
-# Read the file COPYING coming with the software for details.
-
-"""Simple pool of worker threads to process tasks like e.g. HTTP requests"""
-
-
-import threading
-import Queue
-
-
-class ThreadPool(object):
-
- """A class to manage a set of threads that read tasks from a queue.
-
- The threads managed by the class are started as deamon threads so
- that it's not required to terminate them if the program using them
- wants to exit. Still, they can be explicitly stopped with the stop
- method.
-
- The threads read tasks from a Queue object managed by the ThreadPool
- instance using the queue's blocking get() method. Tasks taken from
- the queue are then passed to the handler_function which was
- specified then the ThreadPool instance was created. The
- handler_function is called with one parameter, the task object
- (which can be any object except None), and should return when the
- task is finished. Repeatedly getting new tasks from the queue is
- handled by the thread pool itself.
-
- The program using the thread pool puts tasks into the queue with the
- thread pool's put method.
- """
-
- def __init__(self, num_threads, handler_function):
- """Initialize the thread pool with a number of threads and a handler"""
- self.queue = Queue.Queue(0)
- self.num_threads = num_threads
- self.handler_function = handler_function
- self.threads = []
-
- def start(self):
- """Starts the threads"""
- self.threads = []
- for i in range(self.num_threads):
- thread = threading.Thread(target = self._thread)
- thread.setDaemon(1)
- thread.start()
- self.threads.append(thread)
-
- def _thread(self):
- """Takes tasks repeatedly the queue and calls the handler_function
- This is an internal method.
- """
- while 1:
- item = self.queue.get()
- if item is None:
- break
- self.handler_function(item)
-
- def stop(self):
- """Stops the worker threads"""
- for i in range(len(self.threads)):
- self.put(None)
- for thread in self.threads:
- thread.join()
-
- def put(self, item):
- """Puts item into the queue to be processed by a worker thread"""
- self.queue.put(item)
Deleted: trunk/transcoder.py
===================================================================
--- trunk/transcoder.py 2007-04-20 15:55:01 UTC (rev 58)
+++ trunk/transcoder.py 2007-04-23 12:54:25 UTC (rev 59)
@@ -1,221 +0,0 @@
-# Copyright (C) 2007 by Intevation GmbH
-# Authors:
-# Bernhard Herzog <bh at intevation.de>
-#
-# This program is free software under the GPL (>=v2)
-# Read the file COPYING coming with the software for details.
-
-"""Classes to modify HTTP requests."""
-
-import urlparse
-from urllib import quote_plus
-from StringIO import StringIO
-from ConfigParser import SafeConfigParser
-
-from lxml import etree
-
-import getpassword
-
-
-class IdentityTranscoder(object):
-
- """A transcoder that does not change anything
-
- Other transcoders can be derived from this class so that they only
- need to implement the methods that actually change parts of a
- request.
- """
-
- def __init__(self, method, spliturl):
- """Initializes the transcoder
-
- Parameters:
- method -- The HTTP method, either 'GET' or 'POST'
- spliturl -- A tuple with the split url of the real remote host.
- The tuple has the form of the returl value of
- urlparse.urlsplit
- """
- self.method = method
- self.spliturl = spliturl
-
- def get_password(self):
- """Returns the username and password needed for the request
-
- The default implementation here simply uses the host and path
- parts of the url as the parameter for the
- get_password_with_cache function.
- """
- return getpassword.get_password_with_cache("".join(self.spliturl[1:3]))
-
- def get_url(self):
- """Returns the real url to connect to when handling this request
-
- The default implementation simply returns the recombined url
- given to the constructor
- """
- return urlparse.urlunsplit(self.spliturl)
-
- def convert_body(self, content_type, body):
- """Convert the body of the request
-
- Parameters:
- content_type -- The value of the Content-Type header of the request.
- If no Content-Type was give, the value is None
- body -- The body of the request as a string.
-
- The return value is a tuple (new_content_type, new_body). The
- default implementation simply returns the parameters unchanged.
- """
- return content_type, body
-
-
-class HTTPSTranscoder(IdentityTranscoder):
-
- """Transcoder that turns the URL unconditionally into a HTTPS URL"""
-
- def __init__(self, method, spliturl):
- super(HTTPSTranscoder, self).__init__(method, ("https",) + spliturl[1:])
-
-
-class OWSProxyGETTranscoder(HTTPSTranscoder):
-
- """Transcoder for GET requests to the OWSProxy"""
-
- def get_url(self):
- """Returns the URL with username and password added to the query"""
- scheme, netloc, path, query, fragment = self.spliturl
- if self.method == "GET":
- user, password = self.get_password()
- # FIXME: quote username and password properly
- if query:
- split_query = query.split("&")
- else:
- split_query = []
- query = "&".join(split_query
- + ["user=%s" % quote_plus(user),
- "password=%s" % quote_plus(password)])
- return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
-
-
-class OWSProxyPOSTTranscoder(HTTPSTranscoder):
-
- """Transcoder for POST requests to the OWSProxy"""
-
- def convert_body(self, content_type, body):
- """Adds user and password attributes to the GetFeature element.
- """
- t = etree.parse(StringIO(body))
- root = t.getroot()
- if root.tag in ("{http://www.opengis.net/wfs}GetFeature",
- "{http://www.opengis.net/wfs}Transaction"):
- user, password = self.get_password()
- root.set("user", user)
- root.set("password", password)
- body = etree.tostring(t, xml_declaration=True)
- content_type = "text/xml"
- return content_type, body
-
-
-class TranscoderMap(object):
-
- """Manages the host specific transcoder settings"""
-
- def __init__(self, classes):
- """Initializes the TranscoderMap.
-
- The parameter 'classes' should be a sequence of (name, get,
- post) triples. They will be used to add classes with the
- add_class method. The first item in classes will become the
- default class.
- """
- self.hostmap = dict()
- self.classmap = dict()
- self.default_classname = None
-
- if classes:
- for item in classes:
- self.add_class(*item)
- self.set_default_class(classes[0][0])
-
- def set_default_class(self, name):
- """Sets the default class"""
- self.default_classname = name
-
- def add_class(self, name, get, post):
- """Adds a transcoder class named name.
- The get and post parameters are the python classes implementing
- the transcoder for the GET and POST methods.
- """
- self.classmap[name] = dict(GET=get, POST=post)
-
- def add_host(self, host, path, classname):
- """Adds a host description.
-
- A connection path on host will be done with the appropriate
- transcoder from the class given by classname.
- """
- self.hostmap[(host, path)] = classname
-
- def lookup(self, method, host, path):
- """Returns the python class implementing the transcoder for path on host
- """
- classname = self.hostmap.get((host, path), self.default_classname)
- return self.classmap[classname][method]
-
- def get_transcoder(self, method, url):
- """Returns a transcoder for the given HTTP method and URL
-
- URL should be the URL given for the GET or POST http request.
- This function extracts the real remote host from the URL and
- uses the URL to look up the transcoder with lookup_transcoder.
-
- This method supports two ways to encode the remote host in the
- URL:
-
- -- InteProxy is accessed directly as an HTTP server. In this
- cases URL is an absolute pathname and does not include a
- hostname in the normal URL syntax. Instead get_transcoder
- assumes that it encodes the real remote host in the first
- component of the path. This is the old InteProxy method
-
- -- InteProxy is used as a HTTP-proxy. In this case URL will
- be a full URL including a hostname. In this case
- get_transcoder will use the host of the URL as the real
- remote host. The path component of the URL is not
- modified.
- """
- scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
-
- # If scheme is given, InteProxy is used as a HTTP proxy, otherwise
- # it's the old InteProxy approach. Only the old approach needs
- # special casing.
- if not scheme:
- scheme = "http"
- # determine the remote host encoded in the path
- split_path = path.split("/")
- if not split_path[0]:
- del split_path[0]
- netloc = split_path.pop(0)
- path = "/" + "/".join(split_path)
-
- transcoder_class = self.lookup(method, netloc, path)
- return transcoder_class(method,
- (scheme, netloc, path, query, fragment))
-
- def read_config(self, filename):
- """Reads a configuration file and adds the host descriptions found"""
- parser = SafeConfigParser()
- parser.read([filename])
- for section in parser.sections():
- host = parser.get(section, "host")
- path = parser.get(section, "path")
- cls = parser.get(section, "class")
- self.add_host(host, path, cls)
-
-
-def create_transcoder_map():
- return TranscoderMap([
- ("identity", IdentityTranscoder, IdentityTranscoder),
- ("owsproxy", OWSProxyGETTranscoder, OWSProxyPOSTTranscoder),
- ])
-transcoder_map = create_transcoder_map()
More information about the Inteproxy-commits
mailing list