I am trying to code the following solution in C using gSOAP: * read some existing XML from a buffer (or file) into a gSOAP DOM tree structure (SOAP_DOM_TREE) * manipulate some of the soap_dom_elements * and then send it as the body of a SOAP request to web service using gSOAP
For various reasons we want to manipulate the XML generically using the DOM, rather than using generated or custom serializers/deserializers. I can successfully read in the XML file and the DOM structure looks as expected, I serialize the tree and send it successfully, but the request is rejected by the HTTP layer with error 400 "Bad Request". My sent gSoap messages are recorded in a log file, and when examining it, it is clear that the HTTP Content-Length is incorrect. The length is specified as 232 but the actual XML data is 612 bytes. My XML input file does not contain any "SOAP-ENV:Envelope" or "SOAP-ENV:Body elements", just the payload. The resulting HTTP Post is as follows. 232 bytes is reached before the end of the Envelope. POST /sdk HTTP/1.1 Host: quahog.corp.bb User-Agent: gSOAP/2.7 Content-Type: text/xml; charset=utf-8 Content-Length: 232 Connection: close SOAPAction: "" <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <vim:RetrieveServiceContent xmlns:vim="urn:vim2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <vim:_this type="ServiceInstance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="vim:ManagedObjectReference">ServiceInstance</vim:_this> </vim:RetrieveServiceContent> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Below I have included my source code. The point at which it fails is in the following "if" statement if (soap_begin_recv(gpDomSoap) || soap_envelope_begin_in(gpDomSoap) || soap_recv_header(gpDomSoap) || soap_body_begin_in(gpDomSoap)) as indicated by the comment "/* FAILS HERE" where Soap error 400 is being returned. The error "HTTP Error: 400 Bad Request" is also echoed to the command line. static struct soap gpDomSoap = soap_new1(SOAP_DOM_TREE | SOAP_C_UTFSTRING); LIBEXTERN int VmwDomSendRequest ( const char *soap_endpoint, const char *soap_action, char *pstrXmlInputFile ) { int iResult = SOAP_OK; struct soap_dom_element dom; char *pstrErrorString = NULL; gpDomSoap->encodingStyle = NULL; soap_begin(gpDomSoap); soap_serializeheader(gpDomSoap); if (NULL != pstrXmlInputFile) { FileHandleT tFileHandle; if (TRUE == FileSysOpen(&tFileHandle, pstrXmlInputFile, FILE_MODE_READ_TEXT)) { gpDomSoap->recvfd = tFileHandle; // Read XML from a file // Read in the XML if (soap_begin_recv(gpDomSoap) || NULL == soap_in_xsd__anyType(gpDomSoap, NULL, &dom, NULL) || soap_end_recv(gpDomSoap)) { iResult = gpSoap->error; TRACE((-1,__LINE__,NORMAL, "DOM: Read XML from file failed = %d", iResult)); } else { struct soap_dom_element *ptrDomElement; struct soap_dom_attribute *ptrDomAttribute; TRACE((-1,__LINE__,NORMAL,"DOM: Read XML into tree")); gpDomSoap->recvfd = 0; // Set back to stdin TRACE((-1,__LINE__,NORMAL,"DOM: Connecting to '%s' action '%s'", STR_STRING(soap_endpoint), STR_STRING(soap_action))); soap_set_namespaces(gpDomSoap, vim_pjg_namespaces); // Connect to server, serialize the DOM and send it if (soap_connect(gpDomSoap, soap_endpoint, soap_action) || soap_envelope_begin_out(gpDomSoap) || soap_putheader(gpDomSoap) || soap_body_begin_out(gpDomSoap) || soap_put_xsd__anyType(gpDomSoap, &dom, "-vim:RetrieveServiceContent", NULL) || soap_body_end_out(gpDomSoap) || soap_envelope_end_out(gpDomSoap) || soap_end_send(gpDomSoap)) { iResult = gpDomSoap->error; TRACE((-1,__LINE__,NORMAL,"DOM: Send failed = %d", iResult)); soap_closesock(gpDomSoap); } else { struct soap_dom_element response; struct soap_dom_element *ptrDomElement; struct soap_dom_attribute *ptrDomAttribute; TRACE((-1,__LINE__,NORMAL,"DOM: Send XML OK")); // Read response... soap_default_xsd__anyType(gpDomSoap, &response); if (soap_begin_recv(gpDomSoap) || soap_envelope_begin_in(gpDomSoap) || soap_recv_header(gpDomSoap) || soap_body_begin_in(gpDomSoap)) { /********************/ /* */ /* FAILS HERE */ /* with Error = 400 */ /* */ *********************/ iResult = gpDomSoap->error; TRACE((-1,__LINE__,NORMAL,"DOM: Soap recv failed = %d", iResult)); soap_closesock(gpDomSoap); } else { soap_get_xsd__anyType(gpDomSoap, &response, "RetrieveServiceContentResponse", ""); soap_body_end_in(gpDomSoap); soap_end_recv(gpDomSoap); soap_closesock(gpDomSoap); // Parse the returned result } } } FileSysClose(&tFileHandle); } } return iResult; }