Search code examples
regexvalidationc++11gsoap

gSOAP regex validation


I have a pattern restriction in my WSDL defined like this:

<complexType name="xxxXXX">
<attribute name="state" use="optional">
    <simpleType>
        <restriction base="xs:string">
            <pattern value="((\-1)|[0-5])(;((\-1)|[0-5]))*"/>
        </restriction>
    </simpleType>
</attribute>
</complexType>

But when I do a request with state="" gSOAP accepts it. I saw that I have to define the function fsvalidate (here https://www.genivia.com/doc/databinding/html/) but it seems never called (doesn't trigger the breakpoint). Futhermore, the generated gsoap's code doesn't contain the regex, even if the tool wsdl2h generates this :

class ns1__xxxXXX
{ public:
@/// Content pattern is "((\\-1)|[0-5])(;((\\-1)|[0-5]))*".
    std::string                                                        
                                        *state                          0;  ///< Optional attribute.
/// A handle to the soap struct that manages this instance (automatically set).
    struct soap                         *soap                          ;
};

Maybe I'm missing some options for the generation but I didn't find anythink on wsdl2h (https://linux.die.net/man/1/wsdl2h) nor soapcpp2

Additional information:

I searched for fsvalidate in gSOAP's generated code and I found:

#ifndef WITH_LEANER
  if (pattern && soap->fsvalidate && (soap->error = soap->fsvalidate(soap, pattern, s)))
    return NULL;
#endif

However, it seems always called with a NULL pattern.. (!(t = soap_string_in(soap, 1, 0, -1, NULL))).

Note: I'm using gSOAP 2.8.23.

-- EDIT:

I followed @Alex's advice to extract the type from the complexType like this:

<xs:simpleType name="stateType">
    <xs:restriction base="xs:string">
        <xs:pattern value="((\-1)|[0-5])(;((\-1)|[0-5]))*"/>
    </xs:restriction>
</xs:simpleType>
<complexType name="xxxXXX">
    <attribute name="state" type="tns:stateType" use="optional" />
</complexType>

And the wsdl2h seems to generate something good:

/// Content pattern is "((\\-1)|[0-5])(;((\\-1)|[0-5]))*".
typedef std::string ns1__stateType "((\\-1)|[0-5])(;((\\-1)|[0-5]))*";

class ns1__xxxXXX
{ public:
/// Attribute "state" of XSD type "http://new.webservice.namespace":stateType.
   @ns1__stateType*                      state                          0;  

But the final type generated by gsoap is a std::string:

class SOAP_CMAC ns1__xxxXXX
{
public:
    std::string *state;

and, of course, it doesn't validate the regex.


Solution

  • It appears that local regex patterns are ignored (i.e. local to a class), but non-local patterns work fine. To enforce pattern validation, the pattern has to be lifted from the complexType (lifted from the class):

    typedef std::string ns1__xxxXXX_string "((\\-1)|[0-5])(;((\\-1)|[0-5]))*";
    
    class ns1__xxxXXX
    { public:
      ns1__xxxXXX_string *state;
    

    Then set the fsvalidate() callback to check the string content against the pattern.

    It is an annoying limitation. I'd suggest to submit a bug/feature request to https://sourceforge.net/p/gsoap2/bugs/