How can I create and process SOAP requests in Delphi without HTTP? - delphi

Is there a recommended way / a tutorial which shows how to create and process plain SOAP request with Delphi without THTTPRio, for example, if I want to implement SOAP over JMS, SOAP over AMQP or SOAP over SMTP?
Simplified code examples:
// create a SOAP request (client side)
RequestXML := Service.Add(Arg1, Arg2);
This code would generate the XML with the SOAP message for the 'Add' method invocation with the arguments Arg1 and Arg2.
// process a SOAP request (server side)
ResponseXML := Service.ProcessRequest(RequestXML);
This code would take the SOAP request XML and invoke the method. The result of the method invocation will be wrapped as a SOAP response and is ready to be sent to the client.

Take a peek at the TLinkedRIO class ( http://shenoyatwork.blogspot.com/2004/10/using-tlinkedrio.html ). It creates the SOAP request and writes it to a file. Since TLinkedRIO is used for testing purposes, it also contains code to find a (Delphi) Server that implements the Service and have the server read the request from the file, process it and write a response to another file. The caller (client) then reads from the response file. If you want to use a different transport you won't have to do that part: the response will come from a true Service. However, it's a good example to show how the XML serialization is separate from the transport.
PS: The SOAP serialization basically expects IWebNode for its transport needs. And namely the Execute method of that interface. How/where you send the request stream to and how/where you get the response stream from is up to the transport implementation.

Related

Post Https SOAP request for performing an action in application using robot framework

I wrote this robot framework test to post a https request to a webservice. The request body is in xml format and not in Json. I have used request library for this, but i am receiving error when i post using the code listed below.
With postman, i had send the body as raw data and got response as 200 ok, but when i try to do the same in robot framework its throwing error 404.
Please help me on this:
Is requests library relevant for post of https xml data soap request
to a web service?
Can any modification be made to below code for posting a https request
to a web service?
Is there any other library through which we could achieve calling
soap web service?
The Robot Framework Script
***Library***
Library String
Library Collections
Library RequestsLibrary
***Variables***
${user} = username
${passwd} = pwd
&{headers} Content-Type=application/soap+xml or text/xml Authorization=Basic encrypted details
${body_request} = <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://example.com/schemas</a:Action><a:MessageID>msgid</a:MessageID><a:ReplyTo><a:Address>url</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">serviceurl</a:To></s:Header><s:Body xmlns:xsi=body"></s:Body></s:Envelope>
*** Test Cases ***
${auth}= Create List ${user} ${passwd}
Create Session alias=proc url=url headers=${headers} auth=${auth}
Sleep 5
${resp2} Post Request alias=proc uri=url data=${body_request} json=None params=None
headers=${headers} files=None allow_redirects=True timeout=None
Should Be Equal As Strings ${resp2.status_code} 200
Log To Console ${resp2.status_code}
Answers to your question mentioned below,
Is requests library relevant for post of https xml data soap request to a web service? - yes, it can be used. however, there are better ways to achieve the same, see the solution below.
Can any modification be made to below code for posting a https request to a web service? - I think it is nothing to do with https, since 400 is bad request, you need to look at the body.
Is there any other library through which we could achieve calling soap web service? - SudsLibrary.
Although, you can make use of requests module to achieve your solution,
My philosophy when making use of robotframework is "SIMPLY MAKE USE OF EXISTING LIBRARIES" which is already verified. Please do not spend time to solve the problem keeping the thought process of "using a language".
Solution
Please make use of "SudsLibrary" library for SOAP requests, look at Keyword Documentation for your reference.
SudsLibrary is a library for functional testing of SOAP-based web services. SudsLibrary is based on Suds, a dynamic SOAP 1.1 client.
pip install robotframework-sudslibrary3
When you use the above library your code would be something similar to the one seen below,
*** Settings ***
Library SudsLibrary
Library Collections
*** Test Cases ***
Sample Testcase On SOAP
${BASE_URL} Set Variable http://www.someservice.com
${SERVICE} Create Dictionary
... name=someservice
... wsdl=someservice.asmx?WSDL
${PORT} Set variable SERVICE_PORT
${METHOD} Set variable CALLSOMEACTION
Set Binding SOAP-ENV http://www.w3.org/2003/05/soap-envelope
Create Soap Client ${BASE_URL}/${SERVICE.name}/${SERVICE.wsdl}
Set Port ${PORT}
Set Headers Content-Type application/soap+xml
Set Headers Authorization Basic encrypted details
Set Headers Soapaction ${EMPTY}
Set Headers Action "${BASE_URL}/${SERVICE.name}/${METHOD}"
${result} Call Soap Method ${METHOD}

Java SOAP client very slow

I am building a client for a web service. I didn't want to the client downloading the wsdl everytime and got this answer.
But evaluating the source files of WSServiceDelegate,
URL url = wsdl.getSystemId()==null ? null : JAXWSUtils.getEncodedURL(wsdl.getSystemId());
WSDLModel model = parseWSDL(url, wsdl, serviceClass);
service = model.getService(this.serviceName);
if (service == null)
throw new WebServiceException(
ClientMessages.INVALID_SERVICE_NAME(this.serviceName,
buildNameList(model.getServices().keySet())));
// fill in statically known ports
for (WSDLPort port : service.getPorts())
ports.put(port.getName(), new PortInfo(this, port));
I see that it still parses the wsdl to get the service. How can I get around that. I provided the endpoint url using the context.
I need the client to be as fast and as small as possible, adding a huge wsdl in there is worst than downloading the wsdl.
For the operations you are interested in, you can build your own SOAP messages based on the wsdl's Request/Response messages and the xsd. You can use Jaxb tools to convert from XSD to Java classes. You then need to make post calls using Http Clients (like Spring RestTemplate) to post the POST body, soap based, to the endpoint address. This will make your calls faster but you have to code more in order to benefit.

Using IdHTTP to send array of bytes to a PHP

I am trying to build a simple client - server - client application using the IdHTTP component.
How to use IdHttp component to send array of bytes from a client1 to a php file located on www.example.com and have this php file send the same data to be consumed by a client2 using the IdHTTp? Maybe I am taking the wrong path here.
For sending the data from client1 to the server I recommend to use Base64 encoding. This way you have a normal string instead of a byte array. Sending strings with IdHTTP is simple. An alternative is multipart form data (Java code here).
For receiving the data on client2: HTTP clients do not know when there is data on the server. Asynchronous receive (server push) is a feature of the new WebSocket protocol, which is an extension of HTTP so it needs specifix extensions on the client and server side. There are open source and commercial implementations of the WebSocket protocol for Delphi.
If your client2 is a normal HTTP client, it has no option than to continuously poll data from the server. For basic use cases, I would recommend a TIdTCPClient component instead of TidHTTP which gives you more control over the processing of incoming data. The client jst needs to open a socket connection on port 80 of the server, send a well-formed HTTP request and then run a loop to receive the response. When the server has new data, the PHP script will start to send data (maybe even without HTTP response headers) and then the Base64 encoded data.

How do I retrieve a complete HTTP response from a web server including response body using an Indy TIdTCPClient instance?

I have a Delphi 6 application that uses an Indy TIdTCPClient instance to communicate with a web server. The reason I am not using an HTTP client directly is because the the server is an image streaming server that uses the same socket connection for receiving the command to start streaming as it does to start "pushing" images back to you. In other words, after you send it a typical HTTP POST request, it replies with an HTTP response, and immediately after that it starts sending out a stream of JPEG images.
I already know how to craft a proper POST request and send it using the TIdTCPClient WriteBuffer() method and then use the ReadBuffer() method to receive reply data. What I'd like to do instead is to send a POST request and then ask Indy to wait for a typical HTTP response including retrieving all the bytes in the response body if there is a Content-Length header variable. I of course want it to leave the JPEG frames intact that may have piled in after the HTTP response in the receive queue until I start requesting them (that is, I don't want it including any of the JPEG frames in the HTTP response to my streaming request command until I ask for them using a successive read call).
Is there a method that I can call on a TIdTCPClient that will retrieve completely a typical HTTP response with body content, and nothing else? I thought about using SendCmd() and checking the LastCmdResult property (type: TIdRFCReply) for the response, but I can't tell from the Indy documentation if it retrieves the response body content too if there is a Content-Length header variable as part of the response it returns, nor can I tell if it leaves the rest of the receive queue after the response intact.
What is the best way to accomplish this mixed mode interaction with an HTTP web server that pushes out a stream of JPEG frames right after you make the HTTP request to start streaming?
Also, if there is a clever way to have Indy split the frames using the JPEG frame WINBONDBOUDARY delimiting string, rather than accumulating blocks of data and parsing them out myself, please share that technique.
The correct way to read an HTTP response is to first read the CRLF-delimited response headers line-by-line until a blank line is encountered, aka a CRLF+CRLF sequence, then you can use those headers to decide how to read the remaining response data. The headers will tell you not only what kind of stream is being sent (via the Content-Type header), but also how the data is being framed (Content-Length, Transfer-Encoding: chunked, something specific to the particular Content-Type, etc).
To receive the headers, you can use the connection's Capture() method, setting its ADelim parameter to a blank string.
How you read the remaining data afterwards depends on the actual formatting/framing of the stream. Without knowing exactly what kind of stream you are receiving, there is no way to advise you how best to read it, as there are several different types of streaming protocols used by HTTP servers, and most of them are not standardized. Provide that information, then I/we can show you how to implement it with Indy.
You cannot use SendCmd() as the HTTP protocol does not format its responses in a way that is compatible with that method.

Progress feedback in stateless HTTP session

I need to program a stateless server to execute remote methods. The client uses REST with a JSON parameter to pass the method name and its parameters. After servicing the result the session is closed. I have to use Indy10, TCP/IP as protocol, and therefore look at using IdHTTPServer.
Large result sets are chunked by Indy10 and sent to the client in parts.
My problem now is:
The methods on the server provide progress information if they take longer to produce the results. These are short messages. How can I write back to the client?
So far I have used writeflush on the server, but the client waited for the request to end before handing back the full resultset, including the progress information. What can I do to display/process such progress information on the client and yet keep the connection open to receive further data on the same request?
On the client side instead of the regular HTTP client component TIdHTTP you can instead use Indy class TIdTCPClientCustom in unit IdTCPClient to send the request and process the response.
This class gives total control over the processing of the server responses. I used the TIdTelnet class as a starting point to implement a client for a message broker messaging protocol, and found it stable and reliable for both text and binary data.
In the receiving thread, the incoming data can be read up to delimiters and parsed into chunks (for the progress information) and immediately processed.

Resources