Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into feature/proxyip
Browse files Browse the repository at this point in the history
* upstream/master:
  removed python 2.6 from the tox settings
  fix ref (geopython#514)
  Fixed harvesting WMS. calling undefined function (geopython#518)
  Issue 508 read pycsw config from env (geopython#509)
  • Loading branch information
minhd committed Jun 6, 2017
2 parents 7e6d52b + 6ef74f6 commit e75129d
Show file tree
Hide file tree
Showing 5 changed files with 303 additions and 63 deletions.
9 changes: 7 additions & 2 deletions pycsw/core/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,12 @@ def _parse_wms(context, repos, record, identifier):
_set(context, serviceobj, 'pycsw:Schema', 'http://www.opengis.net/wms')
_set(context, serviceobj, 'pycsw:MdSource', record)
_set(context, serviceobj, 'pycsw:InsertDate', util.get_today_and_now())
_set(context, serviceobj, 'pycsw:AnyText', util.get_anytext(md.getServiceXML()))
_set(
context,
serviceobj,
'pycsw:AnyText',
repository.get_anytext(md.getServiceXML())
)
_set(context, serviceobj, 'pycsw:Type', 'service')
_set(context, serviceobj, 'pycsw:Title', md.identification.title)
_set(context, serviceobj, 'pycsw:Abstract', md.identification.abstract)
Expand Down Expand Up @@ -968,7 +973,7 @@ def _parse_sos(context, repos, record, identifier, version):
end = md.contents[offering].end_position
_set(context, recobj, 'pycsw:TempExtent_begin',
util.datetime2iso8601(begin) if begin is not None else None)
_set(context, recobj, 'pycsw:TempExtent_end',
_set(context, recobj, 'pycsw:TempExtent_end',
util.datetime2iso8601(end) if end is not None else None)

#For observed_properties that have mmi url or urn, we simply want the observation name.
Expand Down
4 changes: 2 additions & 2 deletions pycsw/plugins/repository/odc/odc.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from django.db.models import Avg, Max, Min, Count
from django.conf import settings

from pycsw.core import util
from pycsw.core import repository, util
from OpenDataCatalog.opendata.models import Resource

class OpenDataCatalogRepository(object):
Expand All @@ -58,7 +58,7 @@ def __init__(self, context, repo_filter=None):
connection.connection.create_function(
'query_spatial', 4, util.query_spatial)
connection.connection.create_function(
'get_anytext', 1, util.get_anytext)
'get_anytext', 1, repository.get_anytext)
connection.connection.create_function(
'get_geometry_area', 1, util.get_geometry_area)

Expand Down
196 changes: 139 additions & 57 deletions pycsw/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
# =================================================================
#
# Authors: Adam Hinz <hinz.adam@gmail.com>
# Ricardo Garcia Silva <ricardo.garcia.silva@gmail.com>
#
# Copyright (c) 2015 Adam Hinz
# Copyright (c) 2017 Ricardo Garcia Silva
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
Expand Down Expand Up @@ -52,85 +54,165 @@
# http://localhost:8000/
#

import gzip
import os
import sys

import six
from six.moves import configparser
from six.moves.urllib.parse import unquote

from pycsw import server


PYCSW_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def application(env, start_response):
"""WSGI wrapper"""
config = 'default.cfg'

if 'PYCSW_CONFIG' in env:
config = env['PYCSW_CONFIG']

root = PYCSW_ROOT

if 'PYCSW_ROOT' in env:
root = env['PYCSW_ROOT']

if env['QUERY_STRING'].lower().find('config') != -1:
for kvp in env['QUERY_STRING'].split('&'):
if kvp.lower().find('config') != -1:
config = unquote(kvp.split('=')[1])

if not os.path.isabs(config):
config = os.path.join(root, config)

pycsw_root = get_pycsw_root_path(os.environ, env)
configuration_path = get_configuration_path(os.environ, env, pycsw_root)
env['local.app_root'] = pycsw_root
if 'HTTP_HOST' in env and ':' in env['HTTP_HOST']:
env['HTTP_HOST'] = env['HTTP_HOST'].split(':')[0]

env['local.app_root'] = root

csw = server.Csw(config, env)

gzip = False
if ('HTTP_ACCEPT_ENCODING' in env and
env['HTTP_ACCEPT_ENCODING'].find('gzip') != -1):
# set for gzip compressed response
gzip = True

# set compression level
if csw.config.has_option('server', 'gzip_compresslevel'):
gzip_compresslevel = \
int(csw.config.get('server', 'gzip_compresslevel'))
else:
gzip_compresslevel = 0

csw = server.Csw(configuration_path, env)
status, contents = csw.dispatch_wsgi()
headers = {
'Content-Length': str(len(contents)),
'Content-Type': str(csw.contenttype)
}
if "gzip" in env.get("HTTP_ACCEPT_ENCODING", ""):
try:
compression_level = int(
csw.config.get("server", "gzip_compresslevel"))
contents, compress_headers = compress_response(
contents, compression_level)
headers.update(compress_headers)
except configparser.NoOptionError:
print(
"The client requested a gzip compressed response. However, "
"the server does not specify the 'gzip_compresslevel' option. "
"Returning an uncompressed response..."
)
start_response(status, list(headers.items()))
return [contents]

headers = {}

if gzip and gzip_compresslevel > 0:
import gzip

buf = six.BytesIO()
gzipfile = gzip.GzipFile(mode='wb', fileobj=buf,
compresslevel=gzip_compresslevel)
gzipfile.write(contents)
gzipfile.close()

contents = buf.getvalue()

headers['Content-Encoding'] = 'gzip'
def compress_response(response, compression_level):
"""Compress pycsw's response with gzip
Parameters
----------
response: str
The already processed CSW request
compression_level: int
Level of compression to use in gzip algorithm
Returns
-------
bytes
The full binary contents of the compressed response
dict
Extra HTTP headers that are useful for the response
"""

buf = six.BytesIO()
gzipfile = gzip.GzipFile(mode='wb', fileobj=buf,
compresslevel=compression_level)
gzipfile.write(response)
gzipfile.close()
compressed_response = buf.getvalue()
compression_headers = {'Content-Encoding': 'gzip'}
return compressed_response, compression_headers


def get_pycsw_root_path(process_environment, request_environment=None,
root_path_key="PYCSW_ROOT"):
"""Get pycsw's root path.
The root path will be searched in the ``process_environment`` first, then
in the ``request_environment``. If it cannot be found then it is determined
based on the location on disk.
Parameters
----------
process_environment: dict
A mapping with the process environment.
request_environment: dict, optional
A mapping with the request environment. Typically the WSGI's
environment
root_path_key: str
Name of the key in both the ``process_environment`` and the
``request_environment`` parameters that specifies the path to pycsw's
root path.
Returns
-------
str
Path to pycsw's root path, as read from the supplied configuration.
"""

req_env = (
dict(request_environment) if request_environment is not None else {})
app_root = process_environment.get(
root_path_key,
req_env.get(
root_path_key,
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
)
return app_root


def get_configuration_path(process_environment, request_environment,
pycsw_root, config_path_key="PYCSW_CONFIG"):
"""Get the path for pycsw configuration file.
The configuration file path is searched in the following:
* The presence of a ``config`` parameter in the request's query string;
* A ``PYCSW_CONFIG`` environment variable;
* A ``PYCSW_CONFIG`` WSGI variable.
Parameters
----------
process_environment: dict
A mapping with the process environment.
request_environment: dict
A mapping with the request's environment. Typically the WSGI's
environment
pycsw_root: str
pycsw's default root path
config_path_key: str, optional
Name of the variable that specifies the path to pycsw's configuration
file.
Returns
-------
str
Path where pycsw expects to find its own configuration file
"""

query_string = request_environment.get("QUERY_STRING", "").lower()
for kvp in query_string.split('&'):
if "config" in kvp:
configuration_path = unquote(kvp.split('=')[1])
break
else: # did not find any `config` parameter in the request
configuration_path = process_environment.get(
config_path_key,
request_environment.get(config_path_key, "")
)
if not os.path.isabs(configuration_path):
configuration_path = os.path.join(pycsw_root, configuration_path)
return configuration_path

headers['Content-Length'] = str(len(contents))
headers['Content-Type'] = str(csw.contenttype)
start_response(status, list(headers.items()))

return [contents]

if __name__ == '__main__': # run inline using WSGI reference implementation
from wsgiref.simple_server import make_server
port = 8000
if len(sys.argv) > 1:
port = int(sys.argv[1])
httpd = make_server('', port, application)
print('Serving on port %d...' % port)
print('Serving on port {}...'.format(port))
httpd.serve_forever()
Loading

0 comments on commit e75129d

Please sign in to comment.