[Pywps-devel] problem with CGI and Wget
Jorge de Jesus
jorge.de-jesus at jrc.it
Wed Jan 21 17:38:55 CET 2009
Hi to all
I had some problems, with the WPS service
1. I made the following command:
wget -nv -q -O - --post-file=dummyprocess.xml
http://localhost/cgi-bin/wps.py <http://localhost/cgi-bin/wps.py>
But nothing worked, actualy the sysin (in the script wps.py) used to
catch the POST file was completely empty. It took me a while but I
discovered that wget (1.11.4) was sending the header with:
CONTENT_TYPE = application/x-www-form-
urlencoded
CONTENT_LENGTH = 0
I then made a simple html form file submitter to send the XML file.
<html><body>
<form enctype="multipart/form-data" action="../cgi-bin/wps.py"
method="post">
<p>File: <input type="file" name="file"></p>
<p><input type="submit" value="Upload"></p>
</form>
</body></html>
Actually the problem is with the content type that SHOULD be as
multipart/form-data
I didnt found any information on this.....does anyone knows something ?!
2. Request problem and XML parsing
After implementing the above, the XML parser crashed.... it seems that
when you do something like this:
>cat dummyrequest.xml | wps.py
Everything is fine, the problem is that when using CGI, the sysin
contains the content headers and footer
-----------------------------101407164111186312061014035381
Content-Disposition: form-data; name="file"; filename="dummyrequest.xml"
Content-Type: text/xml
<wps:Execute service="WPS" version="1.0.0"
xmlns:ows="http://www.opengis.net/ows/1.1
<http://www.opengis.net/ows/1.1>"
xmlns:wps="http://www.opengis.net/wps/1.0.0
<http://www.opengis.net/wps/1.0.0>"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
<http://www.w3.org/2001/XMLSchema-instance>"
xsi:schemaLocation="http://www.opengis.net/wps/1.0.0
<http://www.opengis.net/wps/1.0.0>
http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd
<http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd>"><ows:Identifier>dummyprocess</ows:Identifier><wps:DataInputs><wps:Input>
:
:
</wps:Execute>
-----------------------------101407164111186312061014035381--
3. Code to solve the problems
The first problem was solved by adding the following to the wps.py (I
att. the new file in the email)
try:
if int(os.environ["CONTENT_LENGTH"]):
parser = Post(self)
parser.parse(sys.stdin)
else:
raise Exceptions.NoApplicableCode("Couldn't get the POST
request or empty POST request")
except:
parser = Post(self)
parser.parse(sys.stdin)
On the post.py file I had a simple rsplit algorithm that splits the
strings by "\n\r" and then assumes that the XML request should be the
biggest string:
# read the document
if maxFileSize > 0:
inputXmlRaw = file.read(maxFileSize)
if file.read() != "":
raise self.wps.exceptions.FileSizeExceeded()
else:
inputXmlRaw = file.read()
#The input XML may have the header from the HTTP-POST request,
therefore it needs to be clean
rawStringList=inputXmlRaw.rsplit("\r\n")
inputXml=rawStringList[0]
for item in rawStringList:
if len(item)>len(inputXml):
inputXml=item
# make DOM from XML
Maybe this could be done in a more elegant way......
Best Jorge
--
Ph.D. Jorge Samuel Mendes de Jesus
European Commission (EC)
Joint Research Centre Directorate (DG JRC)
Institute for Environment and Sustainability (IES)
TP 441, Via Fermi 1
21020 Ispra (VA)
Italy
Phone: +39 0332 78 3536
Fax: +39 0332 78 5466
http://rem.jrc.ec.europa.eu
"The views expressed are purely those of the writer and may not in any circumstances be regarded as stating an official position of the European Commission"
------------------------------------------------------------------------
#!/usr/bin/python
#-*- coding: utf-8 -*-
"""
This program is simple implementation of OGC's [http://opengeospatial.org]
Web Processing Service (OpenGIS(r) Web Processing Service - OGC 05-007r7)
version 1.0.0 from 2007-06-08
Target of this application is to bring functionality of GIS GRASS
[http://grass.itc.it] to the World Wide Web - it should work like
wrapper for modules of this GIS. Though GRASS was at the first place in the
focus, it is not necessary to use it's modules - you can use any program
you can script in Python or other language.
The first version was written with support of Deutsche Bundesstiftung
Umwelt, Osnabrueck, Germany on the spring 2006. SVN server is hosted by
GDF-Hannover, Hannover, Germany.
Current development is supported mainly by:
Help Service - Remote Sensing s.r.o
Cernoleska 1600
256 01 - Benesov u Prahy
Czech Republic
Europe
For setting see comments in 'etc' directory and documentation.
This program is free software, distributed under the terms of GNU General
Public License as published by the Free Software Foundation version 2 of the
License.
Enjoy and happy GISing!
$Id: wps.py 673 2008-10-01 16:19:27Z jachym $
"""
__version__ = "3.0-svn"
# Author: Jachym Cepicky
# http://les-ejk.cz
# License:
#
# Web Processing Service implementation
# Copyright (C) 2006 Jachym Cepicky
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import pywps
from pywps import Parser
from pywps import Exceptions
from pywps import Wps
from pywps.Exceptions import *
import sys, os, ConfigParser
class WPS:
"""This is main PyWPS Class, which parses the request, performs the
desired operation and writes required response back.
"""
method ="" # HTTP POST or GET
parser = None
config = None #Â Configuration
workingDir = None # this working directory
exceptions = pywps.Exceptions
inputs = {} # parsed input values
request = None # object with getcapabilities/describeprocess/execute
# class
defaultLanguage = "eng"
languages = [defaultLanguage]
defaultVersion = "1.0.0"
versions=[defaultVersion]
# global variables
METHOD_GET="GET"
METHOD_POST="POST"
OWS_NAMESPACE = "http://www.opengis.net/ows/1.1"
WPS_NAMESPACE = "http://www.opengis.net/wps/1.0.0"
XLINK_NAMESPACE = "http://www.w3.org/1999/xlink"
def __init__(self):
"""Class constructor
Will load configuration files, parse the input parameters and
perform the request.
"""
# get settings
self._loadConfiguration()
# set default language
self.languages = self.getConfigValue("wps","lang").split(",")
self.defaultLanguage = self.languages[0]
# set default version
self.versions=self.getConfigValue("wps","version").split(",")
self.defaultVersion = self.versions[0]
# find out the request method
self.method = os.getenv("REQUEST_METHOD")
if not self.method: # set standard method
self.method = self.METHOD_POST
# decide, which method to use
# HTTP GET vs. HTTP POST
if self.method == self.METHOD_GET:
from pywps.Parser.Get import Get
parser = Get(self)
querystring = ""
try:
querystring = os.environ["QUERY_STRING"]
#logfile=open("/home/jesus/logfile.txt","w")
#logfile.write(str(os.environ))
#logfile.close()
except KeyError:
# if QUERY_STRING isn't found in env-dictionary, try to read
# query from command line:
if len(sys.argv)>1: # any arguments available?
querystring = sys.argv[1]
if querystring:
parser.parse(querystring)
else:
raise Exceptions.NoApplicableCode("No query string found.")
else:
from pywps.Parser.Post import Post
try:
if int(os.environ["CONTENT_LENGTH"]):
parser = Post(self)
parser.parse(sys.stdin)
else:
raise Exceptions.NoApplicableCode("Couldn't get the POST request or empty POST request")
except:
parser = Post(self)
parser.parse(sys.stdin)
# inputs parsed, perform request
if self.inputs:
self.performRequest()
# request performed, write the response back
if self.request.response:
# print only to standard out
if self.request.statusFiles == sys.stdout or\
sys.stdout in self.request.statusFiles:
print "Content-type: text/xml\n"
self.request.printResponse(self.request.statusFiles)
return
def _loadConfiguration(self):
"""Load PyWPS configuration from configuration files. This are
Both:
$PYWPS_CFG environment variable
Unix/Linux:
pywps/default.cfg
/etc/pywps.cfg
pywps/etc/pywps.cfg
$HOME/.pywps.cfg
Windows:
pywps\\default.cfg
pywps\\etc\\default.cfg
The later overwrites configuration from the first
"""
cfgfiles = None
# configuration file as environment variable
if os.getenv("PYWPS_CFG"):
# Windows or Unix
if sys.platform == 'win32':
cfgfiles = (os.path.join(self.workingDir,"pywps","default.cfg"),
os.getenv("PYWPS_CFG"))
else:
cfgfiles = (os.path.join(pywps.__path__[0],"default.cfg"),
os.getenv("PYWPS_CFG"))
# try to eastimate the default location
else:
# Windows or Unix
if sys.platform == 'win32':
self.workingDir = os.path.abspath(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])))
cfgfiles = (os.path.join(self.workingDir,"pywps","default.cfg"),
os.path.join(self.workingDir, "pywps","etc","pywps.cfg"),
os.path.join(os.getenv("HOME"),".pywps.cfg"))
else:
cfgfiles = (os.path.join(pywps.__path__[0],"default.cfg"),
os.path.join(pywps.__path__[0],"etc", "pywps.cfg"), "/etc/pywps.cfg")
self.config = ConfigParser.ConfigParser()
self.config.read(cfgfiles)
def performRequest(self):
"""Performs the desired WSP Request."""
# the modules are imported first, when the request type is known
if self.inputs["request"] == "getcapabilities":
from pywps.Wps.GetCapabilities import GetCapabilities
self.request = GetCapabilities(self)
elif self.inputs["request"] == "describeprocess":
from pywps.Wps.DescribeProcess import DescribeProcess
self.request = DescribeProcess(self)
elif self.inputs["request"] == "execute":
from pywps.Wps.Execute import Execute
self.request = Execute(self)
else:
raise self.exceptions.InvalidParameterValue(
"request: "+self.inputs["request"])
def getConfigValue(self,*args):
"""Return desired value from the configuration files
Keyword arguments:
section -- section in configuration files
key -- key in the section
"""
value = self.config.get(*args)
# Convert Boolean string to real Boolean values
if value.lower() == "false":
value = False
elif value.lower() == "true" :
value = True
return value
if __name__ == "__main__":
wps = WPS()
------------------------------------------------------------------------
# Author: Jachym Cepicky
# http://les-ejk.cz
# Lince:
#
# Web Processing Service implementation
# Copyright (C) 2006 Jachym Cepicky
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import types,sys
import xml
from xml.dom.minidom import parseString
from pywps.Parser.Parser import Parser
from pywps.Process.Lang import Lang
class Post(Parser):
"""Main class for parsing of HTTP POST request types"""
document = None # Document Object Model
requestParser = None
GET_CAPABILITIES = "GetCapabilities"
DESCRIBE_PROCESS = "DescribeProcess"
EXECUTE = "Execute"
def parse(self,file):
"""
Parse parameters stored as XML file
"""
maxFileSize = None
inputXml = None
# get the maximal input file size from configuration
maxFileSize = self.getMaxFileSize(
self.wps.config.get("server","maxFileSize").lower())
# read the document
if maxFileSize > 0:
inputXmlRaw = file.read(maxFileSize)
if file.read() != "":
raise self.wps.exceptions.FileSizeExceeded()
else:
inputXmlRaw = file.read()
#The input XML may have the header from the HTTP-POST request, therefore it needs to be clean
rawStringList=inputXmlRaw.rsplit("\r\n")
inputXml=rawStringList[0]
for item in rawStringList:
if len(item)>len(inputXml):
inputXml=item
# make DOM from XML
try:
self.document = parseString(inputXml)
except xml.parsers.expat.ExpatError,e:
raise self.wps.exceptions.NoApplicableCode(e.message)
# get first child
firstChild = self.getFirstChildNode(self.document)
# check service name
self.checkService(firstChild)
# find request type
self.checkRequestType(firstChild)
# parse the document
self.requestParser.parse(self.document)
def checkService(self, node):
""" Check mandatory service name parameter. """
# service name is mandatory for all requests (OWS_1-1-0 p.14 tab.3 +
# p.46 tab.26); service must be "WPS" (WPS_1-0-0 p.17 tab.13 + p.32 tab.39)
if node.hasAttribute("service"):
value=node.getAttribute("service").upper()
if value != "WPS":
raise self.wps.exceptions.InvalidParameterValue("service")
else:
self.wps.inputs["service"] = "WPS"
else:
raise self.wps.exceptions.MissingParameterValue("service")
def checkLanguage(self, node):
""" Check optional language parameter. """
if node.hasAttribute("language"):
value=Lang.getCode(node.getAttribute("language").lower())
if value not in self.wps.languages:
raise self.wps.exceptions.InvalidParameterValue("language")
else:
self.wps.inputs["language"] = value
else:
self.wps.inputs["language"] = self.wps.defaultLanguage
def checkVersion(self, node):
""" Check optional language parameter. """
if node.hasAttribute("version"):
value=node.getAttribute("version")
if value not in self.wps.versions:
raise self.wps.exceptions.VersionNegotiationFailed(
'The requested version "' + value + \
'" is not supported by this server.')
else:
self.wps.inputs["version"] = value
else:
raise self.wps.exceptions.MissingParameterValue("version")
def checkRequestType(self, node):
"""Find requested request type and import given request parser."""
firstTagName = node.tagName
if firstTagName.find(self.GET_CAPABILITIES) > -1:
import GetCapabilities
self.requestParser = GetCapabilities.Post(self.wps)
self.wps.inputs["request"] = "getcapabilities"
elif firstTagName.find(self.DESCRIBE_PROCESS) > -1:
import DescribeProcess
self.requestParser = DescribeProcess.Post(self.wps)
self.wps.inputs["request"] = "describeprocess"
elif firstTagName.find(self.EXECUTE) > -1:
import Execute
self.requestParser = Execute.Post(self.wps)
self.wps.inputs["request"] = "execute"
else:
raise self.wps.Exceptions.InvalidParameterValue("request")
def getFirstChildNode(self,document):
"""Find first usable child node of the document (no comments)"""
node = None
# get the first child (omit comments)
for node in document.childNodes:
if node.nodeType == xml.dom.minidom.Element.nodeType:
firstChild = node
if firstChild == None:
raise self.wps.exceptions.NoApplicableCode(
"No root Element found!")
return firstChild
def getMaxFileSize(self,maxFileSize):
""" Convert given filesize string to number of bytes.
This is used mainly for the parsing of the value from the
--
Ph.D. Jorge Samuel Mendes de Jesus
European Commission (EC)
Joint Research Centre Directorate (DG JRC)
Institute for Environment and Sustainability (IES)
TP 441, Via Fermi 1
21020 Ispra (VA)
Italy
Phone: +39 0332 78 3536
Fax: +39 0332 78 5466
http://rem.jrc.ec.europa.eu
"The views expressed are purely those of the writer and may not in any circumstances be regarded as stating an official position of the European Commission"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.wald.intevation.org/pipermail/pywps-devel/attachments/20090121/41954277/attachment-0001.html
More information about the Pywps-devel
mailing list