source: cowsclient/trunk/cowsclient/lib/wmc_util.py @ 5841

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cowsclient/trunk/cowsclient/lib/wmc_util.py@5841
Revision 5841, 7.6 KB checked in by pnorton, 12 years ago (diff)

Improved the proxy code so that no errors occurr if the http_proxy environment variable is not set.

Line 
1# Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council).
2# This software may be distributed under the terms of the
3# Q Public License, version 1.0 or later.
4# http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5"""
6Utils to aid use of wmc docs - including interfacing these with the con terra client
7and getting associated legend data
8
9@author: Calum Byrom, modified for NDG Security by Dominic Lowe
10"""
11from cowsclient.lib.base import *
12from cowsclient.model.WMC import WMC
13from cowsclient.lib import exceptions
14import urllib2, urllib
15import os
16import logging
17import urlparse
18log = logging.getLogger(__name__)
19
20
21def getConTerraDoc(wmcURLs):
22    """
23    Construct an aggregated XML file and display this as a temporary webpage; this will automatically be
24    POSTED so that the data is sent via POST to the Con Terra mapClient to visualise (as required by this client)
25    @param wmcURLS: An array of URLs pointing to WMC docs to visualise
26    """
27    # firstly, retrieve each WMC doc
28    wmcDocs = []
29    for wmcURL in wmcURLs:
30        wmcDocs.append(WMC(wmcURL))
31
32    # now create a dictionary of WMS/layer from these docs - to avoid duplicate layers
33    c.wms = {}
34    for wmcDoc in wmcDocs:
35        for layer in wmcDoc.layers:
36            if layer.wmsURL not in c.wms:
37                c.wms[layer.wmsURL] = [layer.name]
38            else:
39                if layer.name not in c.wms[layer.wmsURL]:
40                    c.wms[layer.wmsURL].append(layer.name)
41
42    # now create the form to post this data
43    c.redirectToConterra = True; #TODO, remove?
44    response.write(render('selectedItems'))
45
46
47
48def GetWebMapContext(self):
49    """
50    Lookup a WMC doc and return it in the response
51    """
52    # retrieve context data from the specifiled url
53    wmcDoc = RetrieveWebMapContext(self, self.inputs['ENDPOINT'])
54    log.info('WMC RESPONSE %s'%response)
55    response.headers['Content-Type'] = 'text/xml'
56    response.write(wmcDoc)
57
58def GetLegend(self):
59    """
60    Lookup a legend for a WMS map
61    NB, all required parameters are already included in the endpoint by this stage
62    """
63    endpoint = self.inputs['ENDPOINT']
64
65    if not endpoint:
66        raise exceptions.MissingParameterValue, "ENDPOINT parameter required"
67    try:
68        #req = urllib2.Request(endpoint,urllib.urlencode(request.params),{'Cookie': request.headers.get('Cookie', '')})
69        log.debug("endpoint = %s" % (endpoint,))
70        req = urllib2.Request(endpoint, None, {'Cookie': request.headers.get('Cookie', '')})
71        url = req.get_full_url()
72
73        filehandle = openURL(req)
74    except IOError:
75        raise exceptions.URLUnavailable, "Could not access WMC endpoint: %s" % endpoint
76   
77    return "<img src=\"%s\" />" % (url,)
78#    response.headers['Content-Type'] = 'image/gif'
79#    response.write(filehandle.read())
80
81def RetrieveWebMapContext(self, endpoint):
82    """
83    Get a WMC doc from a specified endpoint
84    @param endpoint: endpoint to retrieve WMC doc from
85    """
86    if not endpoint:
87        raise exceptions.MissingParameterValue, "ENDPOINT parameter required"
88    log.info('Getting WebMapContext from endpoint: ' + endpoint)
89    #urlstring=('%s&request=GetContext'%(str(endpoint)))
90    urlstring=('%s?request=GetContext&service=WMS'%(str(endpoint)))
91#    urlstring = str(endpoint)
92    log.info("urlstring=%s" % (urlstring,))
93    #cookies are passed to enable authorisation mechanisms e.g. ndg security
94    #try:
95
96    req = urllib2.Request(urlstring)
97    req.add_header('Cookie', request.headers.get('Cookie', ''))
98    filehandle = openURL(req)
99    return filehandle.read()
100
101def GetWebMapCapabilities(endpoint):
102   
103    urlstring = parseEndpointString(endpoint, {'REQUEST':'GetCapabilities',
104                                               'SERVICE':'WMS'} )
105    log.debug("urlstring = %s" % (urlstring,))
106    req = urllib2.Request(urlstring)
107    req.add_header('Cookie', request.headers.get('Cookie', ''))
108   
109    try:   
110        filehandle = openURL(req)
111        return filehandle.read()
112    except urllib2.HTTPError, e:           
113        log.exception("exception occurred")
114        if e.code == 401:
115            log.info ('401 unauthorized error in cowsclient')
116            return abort(401) #triggers ndg security framework
117        elif e.code == 403:  #TODO: 403 response is UNTESTED.
118            # User is authenticated but doesn't have the required permissions
119            # or an error occurred in the authorization process
120            # Read response                   
121            xresponse = e.read()
122            # Send response to user
123            self.start_response("%d %s" % (e.code, e.msg), e.headers.dict.items())
124            return xresponse
125        else:
126            raise e
127
128def GetResponse(url):
129    req = urllib2.Request(url)
130    req.add_header('Cookie', request.headers.get('Cookie', ''))
131    filehandle = openURL(req)
132    return filehandle.read()   
133   
134
135noProxyOpener = urllib2.build_opener(urllib2.HTTPHandler(), urllib2.ProxyHandler({}))
136
137def openURL(req):
138    log.info("Making request: %s "%(req.get_full_url(),))
139    if _shouldUseProxy(req.get_full_url()):
140        log.debug("using proxy")
141        fh = urllib2.urlopen(req)
142    else:
143        log.debug("not using proxy")
144        fh = noProxyOpener.open(req)
145       
146    return fh
147
148def _shouldUseProxy(urlstring) :
149    no_proxy   = os.environ.get('no_proxy', '')
150   
151    urlObj = urlparse.urlparse(urlstring)
152    for np in no_proxy.split(','):
153        if urlObj.hostname == urlparse.urlparse(np).hostname:
154            return False
155   
156    return True
157
158def proxyFix(url):
159    oldProxyVal = os.environ.get('http_proxy', None)
160   
161    if oldProxyVal != None:
162        if os.environ['http_proxy'] != "" and not _shouldUseProxy(url):
163            os.environ['http_proxy'] = ""
164            reload(urllib2)
165
166    return oldProxyVal
167
168
169def resetProxy(oldProxyVal):
170   
171    if oldProxyVal == None or oldProxyVal == "":
172        return
173   
174    if os.environ['http_proxy'] != oldProxyVal:
175        os.environ['http_proxy'] = oldProxyVal
176        reload(urllib2)
177
178
179def parseEndpointString(endpointString, requiredParams):
180    """
181    Take an endpoint string and add the required params if they don't already appear
182    on the string.
183    """
184    urlObj = urlparse.urlparse(endpointString)
185   
186    queryParams = _parse_qs(urlObj.query)
187   
188    for k, v in requiredParams.items():
189        queryParams[k.lower()] = v
190   
191    queryString = _build_qs(queryParams)
192   
193    # as urlObj.query isn't writable extract the data to a list
194    # and replace the query data with the new query string
195    res = [x for x in urlObj]
196    res[4] = queryString
197                             
198    return urlparse.urlunparse(res)
199
200def _parse_qs(queryString):
201    """
202    returns a dictionary of key, value pairs from the query string. The keys in
203    the return dictionary are in all lowercase. Empty parameters are ignored.
204    The query string shouln't have a leading '?' character.
205    """
206    queryDict = {}
207   
208    for kvString in queryString.split('&'):
209       
210        if kvString == '':
211            continue
212       
213        key, value = kvString.split('=')
214       
215        if value in ['', None]:
216            continue
217           
218        queryDict[key.lower()] = value
219   
220    return queryDict
221
222def _build_qs(queryDict, upperCaseKeys=True):
223    """
224    Builds a url query string out of a dictionary. doesn't add the initial '?' character.
225   
226    If upperCaseKeys == True then all the dictionary keys will be included as capital letters.
227    """
228   
229    queryStr = ""
230    for k, v in queryDict.items():
231       
232        if upperCaseKeys:
233            k = k.upper()
234       
235        queryStr += "%s=%s&" % (k, v)
236   
237    #remove the last &
238    queryStr = queryStr[:-1]
239    return queryStr
240   
Note: See TracBrowser for help on using the repository browser.