Menu

#772 empty SOAP body request (option -j)

closed-fixed
None
5
2014-08-22
2011-10-12
steph96
No

Hello!

I believe the generated code (option -j) does not work with empty request messages. I have a patched WS-Transfer wsdl file with only a Get-Operation that returns Metadata according WS-Mex. The function definition in (wsdl2h generated) gSOAP header file looks like the following:

//gsoap wst4 service method-style: Get document
//gsoap wst4 service method-encoding: Get literal
//gsoap wst4 service method-action: Get http://schemas.xmlsoap.org/ws/2004/09/transfer/Get
int __wst4__Get(
_wsx4__Metadata* wsx4__Metadata ///< Response parameter
);

Using code generation (with option -j) generates the following request xml file:

<SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>

</SOAP-ENV:Body>

It is correct without any element within the SOAP body. Anyhow, in the generated dispatch() function the operation is missing after the soap_peek_element() call (see below)!
Aditionally there is a soap_get___wst4__Get() call in the serve___wst4__Get() function that always returns 3 (SOAP_TAG_MISMATCH). This is not surprising, since there is no element within the SOAP body. The following snippet is from the <name>Service.cpp file:

static int serve___wst4__Get(TransferBindingService*);

int TransferBindingService::dispatch()
{ TransferBindingService_init(this->soap->imode, this->soap->omode);
soap_peek_element(this->soap);
return this->soap->error = SOAP_NO_METHOD;
}

static int serve___wst4__Get(TransferBindingService *service)
{ struct soap *soap = service->soap;
struct __wst4__Get soap_tmp___wst4__Get;
_wsx4__Metadata wsx4__Metadata;
wsx4__Metadata.soap_default(soap);
soap_default___wst4__Get(soap, &soap_tmp___wst4__Get);
soap->encodingStyle = NULL;
if (!soap_get___wst4__Get(soap, &soap_tmp___wst4__Get, "-wst4:Get", NULL))
return soap->error;
if (soap_body_end_in(soap)
|| soap_envelope_end_in(soap)
|| soap_end_recv(soap))
return soap->error;
soap->error = service->Get(&wsx4__Metadata);
...

Thanks,
Steph

Discussion

  • Robert van Engelen

    Try gSOAP 2.8.4 because a similar problem was reported and fixed. Hope this fix in 2.8.4 will work for you.

     
  • Robert van Engelen

    • assigned_to: nobody --> engelen
    • status: open --> pending
     
  • steph96

    steph96 - 2011-10-26

    The problem still remains in gsoap 2.8.4. My compiler warns that the function was declared but never referenced:

    warning (etoa:4177): function 'serve___wst4__Get' was declared but never referenced
    static int serve___wst4__Get(TransferBindingService *service)

    Current work around for me is to
    - manually remove the static in front of the function's declaration and definition
    - comment out the soap_get___wst4__Get() (whole if statement) and
    - avoid using the dispatch function by calling serve___wst4__Get directly in case of a matching soap action.

     
  • steph96

    steph96 - 2011-10-26
    • status: pending --> open
     
  • Robert van Engelen

    • status: open --> pending-fixed
     
  • Robert van Engelen

    Patch:

    In src/symbol2.c:4519 in function gen_object_code():

    }
    else
    catch_method = method;
    }

    move the else clause one level down:

    }
    }
    else
    catch_method = method;

    The fix will be implemented in the upcoming 2.8.5 release.

     
  • steph96

    steph96 - 2011-11-23

    stripped wsdl file that produces the bug

     
  • steph96

    steph96 - 2011-11-23

    Still does not work. I attached a stripped version of the wsdl file.

     
  • steph96

    steph96 - 2011-11-23
    • status: pending-fixed --> open
     
  • Robert van Engelen

    Tested against your previous WSDL and that worked. In fact, now no soapcpp2 option (-i or -j) will help for your new example.

    To enable this, change the code so that catch_method is set in the else's for two if-then-else branches:

    }
    else
    catch_method = method;
    }
    else
    catch_method = method;
    }

    The two functions to change in src/symbol2.c are: soap_serve() and gen_object_code() and make sure that in the latter to code output is correct as follows:

    if (catch_method)
    fprintf(fd, "\n\treturn serve_%s(this);\n}", ident(catch_method->sym->name));

     
  • Robert van Engelen

    • status: open --> open-fixed
     
  • steph96

    steph96 - 2011-12-08
    • status: open-fixed --> open-accepted
     
  • steph96

    steph96 - 2011-12-08

    Thanks for the help so far, but is only fixed half.

    In the generated (-j) dispatch function the serve function is now correctly inserted (and called at runtime).
    The second problem still exists: soap_get___wst4__Get() is still called in the serve___wst4__Get() function. Since the request does not contain an element within the SOAP body this call failed with SOAP_TAG_MISMATCH.

     
  • Robert van Engelen

    You say "The second problem still exists: soap_get___wst4__Get() is still called in the serve___wst4__Get() function. Since the request does not contain an
    element within the SOAP body this call failed with SOAP_TAG_MISMATCH."

    But this is the purpose of the soap_get_xyz method! To accept a message without a body and produce a response in your service operation. If that does not work in your case, then the service definition requires an element that is not there. Please check your code. Note that "-wst4:Get" does not parse an element, due to the leading "-". However, if the "Get" operation requires operands, then this will surely fail.

     
  • Robert van Engelen

    • status: open-accepted --> pending-fixed
     
  • steph96

    steph96 - 2011-12-16

    I still believe there is a bug.

    soap_get___wst4__Get() calls soap_in___wst4__Get(), but this function always returns NULL (see below). This NULL is passed back to the original soap_get___wst4__Get() call that is why this function call fails with SOAP_TAG_MISMATCH.

    SOAP_FMAC3 struct __wst4__Get * SOAP_FMAC4 soap_in___wst4__Get(struct soap *soap, const char *tag, struct __wst4__Get *a, const char *type)
    {
    a = (struct __wst4__Get *)soap_id_enter(soap, "", a, SOAP_TYPE_DSC___wst4__Get, sizeof(struct __wst4__Get), 0, NULL, NULL, NULL);
    if (!a)
    return NULL;
    soap_default___wst4__Get(soap, a);
    soap->error = SOAP_TAG_MISMATCH;
    a = NULL;
    return a;
    }

    soap_id_enter() has the following debug output:
    Enter id='' type=164 loc=0012FDDF size=1 level=0

    Which seems to be correct for me, since 164 is the correct type:

    #ifndef SOAP_TYPE_DSC___wst4__Get
    #define SOAP_TYPE_DSC___wst4__Get (164)
    /* Operation wrapper: */
    struct __wst4__Get
    {
    #ifdef WITH_NOEMPTYSTRUCT
    private:
    char dummy; /* dummy member to enable compilation */
    #endif
    };
    #endif

    In gSOAP 2.8.2 the corresponding code in symbol2.c was changed: http://gsoap2.svn.sourceforge.net/viewvc/gsoap2/gsoap/src/symbol2.c?annotate=9#l10416
    When removing these two lines that generate:
    soap->error = SOAP_TAG_MISMATCH;
    a = NULL;
    it works for me. (They appear twice, once for structs and once for class types lines 10905f in gSOAP 2.8.2)

     
  • steph96

    steph96 - 2011-12-16
    • status: pending-fixed --> open
     
  • Robert van Engelen

    The reason for the change that you observed was to fix an infinite loop when the deserializer does not consume any input, which happens when parsing a vector of elements with no content and no element tag name (empty wrappers). The Get() operation is an empty wrapper. So some additional non-trivial logic will be needed to keep the fix in place while handling the empty wrapper service operation. I will take a closer look and update the code generator.

     
  • Robert van Engelen

    • status: open --> pending-fixed
     
  • Robert van Engelen

    Fixed. Download the patched file from SVN gsoap/src/symbol2.c

     
  • Robert van Engelen

    • status: pending-fixed --> closed-fixed
     

Log in to post a comment.