[Inteproxy-commits] r21 - trunk
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Feb 7 19:04:34 CET 2007
Author: bh
Date: 2007-02-07 19:04:34 +0100 (Wed, 07 Feb 2007)
New Revision: 21
Added:
trunk/transcoder.py
Modified:
trunk/ChangeLog
trunk/InteProxy.py
Log:
* transcoder.py: New module for classes that are used to modify
http requests
* InteProxy.py (InteProxyHTTPRequestHandler.handle_proxy_request):
Use a transcoder to convert urls and -- this is new -- also the
body of the request if there is one.
(InteProxyHTTPRequestHandler.convert_url): Removed. The
functionality of this method is now in the transcoder module
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2007-02-07 15:33:31 UTC (rev 20)
+++ trunk/ChangeLog 2007-02-07 18:04:34 UTC (rev 21)
@@ -1,5 +1,16 @@
2007-02-07 Bernhard Herzog <bh at intevation.de>
+ * transcoder.py: New module for classes that are used to modify
+ http requests
+
+ * InteProxy.py (InteProxyHTTPRequestHandler.handle_proxy_request):
+ Use a transcoder to convert urls and -- this is new -- also the
+ body of the request if there is one.
+ (InteProxyHTTPRequestHandler.convert_url): Removed. The
+ functionality of this method is now in the transcoder module
+
+2007-02-07 Bernhard Herzog <bh at intevation.de>
+
* getpassword.py: New module for the password handling code.
* InteProxy.py: Move the password handling into a separate module.
Modified: trunk/InteProxy.py
===================================================================
--- trunk/InteProxy.py 2007-02-07 15:33:31 UTC (rev 20)
+++ trunk/InteProxy.py 2007-02-07 18:04:34 UTC (rev 21)
@@ -25,7 +25,7 @@
import Queue
import socket
import proxyconnection
-from getpassword import get_password_with_cache
+from transcoder import get_transcoder
inteproxy_version = "0.1.1"
@@ -101,8 +101,8 @@
#
# Create a http request for the real location
#
- netloc, url = self.convert_url(self.path)
- remote_url = "https://%s%s" % (netloc, url)
+ transcoder = get_transcoder(method, self.path)
+ remote_url = transcoder.get_url()
self.log_debug("Converted url: %r", remote_url)
# If any data is associated with the request read it
@@ -112,6 +112,14 @@
data = self.rfile.read(length)
self.log_debug("body of client request (%d bytes):\n%r",
length, data)
+ content_type = self.headers.getheader("Content-Type")
+ content_type, data = transcoder.convert_body(content_type, data)
+ self.log_debug("modified body of client request (%d bytes):\n%r",
+ len(data), data)
+ if len(data) != length:
+ self.headers["Content-length"] = str(len(data))
+ if content_type is not None:
+ self.headers["Content-type"] = content_type
else:
self.log_debug("client request has no body")
data = None
@@ -216,42 +224,6 @@
if chunked:
write("0\r\n\r\n")
- def convert_url(self, url):
- """Extract the real host from the url and return host and new url
-
- The URL parameter is the part of the URL from the GET or POST
- request which is actually only the path, query and fragment in
- the terminology of the urlparse module. For the InteProxy, the
- first component in the path is the actual host to connect to.
- This method extracts that part and creates a new path with that
- part removed. The return value of this method is the tuple
- (real_host, new_url) where new_url is the combined new path and
- the original query and fragment parts.
- """
- scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
-
- # XXX: This is hardcoded syntax for deegree OWS Proxy
- # Eventually this should be moved to a method of its own
- # and anyway this is just a dirty solution since passwords
- # are not really managed.
- user, password = get_password_with_cache(path)
- # TODO: Building the query this way is not safe.
- query += "&user=%s&password=%s" % (user, password)
-
- # both scheme and netloc must be empty strings because the url
- # we work with is the url on the first line of a HTTP request
- # which doesn't include them
- assert scheme == ""
- assert netloc == ""
-
- split_path = path.split("/")
- if not split_path[0]:
- del split_path[0]
- real_netloc = split_path.pop(0)
- real_path = "/" + "/".join(split_path)
- return real_netloc, urlparse.urlunsplit(("", "", real_path, query,
- fragment))
-
def log_exception(self, exc_info):
"""Log an exception
Added: trunk/transcoder.py
===================================================================
--- trunk/transcoder.py 2007-02-07 15:33:31 UTC (rev 20)
+++ trunk/transcoder.py 2007-02-07 18:04:34 UTC (rev 21)
@@ -0,0 +1,145 @@
+# 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 lxml import etree
+from StringIO import StringIO
+
+import getpassword
+
+
+class IdentityTranscoder:
+
+ """The null transcoder that does not acutally 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 OWSProxyGETTranscoder(IdentityTranscoder):
+
+ """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
+ query = "&".join(query.split("&")+ ["user=%s" % user,
+ "password=%s" % password])
+ return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
+
+
+class OWSProxyPOSTTranscoder(IdentityTranscoder):
+
+ """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 == "{http://www.opengis.net/wfs}GetFeature":
+ 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
+
+
+# Maps the path of an InteProxy request to transcoders. The key of the
+# transcoder_map is the path of the URL given to the InteProxy. E.g. if
+# the URL entered in the client is http://localhost:123/remote-host/wfs
+# the path is /remote-host/wfs. The values are dictionaries mapping the
+# http request method ("GET" or "POST") to the transcoder class. For
+# example, a value for transcoder_map might be
+#
+# transcoder_map = {
+# "/example.como/wfs": {"GET": OWSProxyGETTranscoder,
+# "POST": OWSProxyPOSTTranscoder},
+# }
+
+transcoder_map = {
+ }
+
+def get_transcoder(method, url):
+ """Return a transcoder for the given HTTP method and URL"""
+ scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
+
+ # both scheme and netloc must be empty strings because the url
+ # we work with is the url on the first line of a HTTP request
+ # which doesn't include them
+ assert scheme == ""
+ assert netloc == ""
+
+ # FIXME: ideally, we would use the IdentityTranscoder by default.
+ # However, until we have some way to populate the transcoder_map
+ # without hardcoding it, i. e. until we have a configuration file or
+ # a similar mechanism, we use the OWSProxyPOSTTranscoder and
+ # OWSProxyGETTranscoder as defaults so that the behavior is
+ # basically the same as before the introduction of the transcoders.
+ defaults = dict(GET=OWSProxyGETTranscoder, POST=OWSProxyPOSTTranscoder)
+ transcoder_class = transcoder_map.get(path, defaults).get(method,
+ IdentityTranscoder)
+
+ # determine the remote host encoded in the path
+ split_path = path.split("/")
+ if not split_path[0]:
+ del split_path[0]
+ real_netloc = split_path.pop(0)
+ real_path = "/" + "/".join(split_path)
+
+ return transcoder_class(method,
+ ("https", real_netloc, real_path, query, fragment))
Property changes on: trunk/transcoder.py
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ native
More information about the Inteproxy-commits
mailing list