[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