SOAP
You are encouraged to solve this task according to the task description, using any language you may know.
In this task, the goal is to create a SOAP client which accesses functions defined at http://example.com/soap/wsdl, and calls the functions soapFunc( ) and anotherSoapFunc( ).
ActionScript
import mx.rpc.soap.WebService;
import mx.rpc.events.ResultEvent;
var ws:WebService = new WebService();
ws.wsdl = 'http://example.com/soap/wsdl';
ws.soapFunc.addEventListener("result",soapFunc_Result);
ws.anotherSoapFunc.addEventListener("result",anotherSoapFunc_Result);
ws.loadWSDL();
ws.soapFunc();
ws.anotherSoapFunc();
// method invocation callback handlers
private function soapFunc_Result(event:ResultEvent):void {
// do something
}
private function anotherSoapFunc_Result(event:ResultEvent):void {
// do another something
}
AutoHotkey
using embedded vb scripting.
WS_Initialize()
WS_Exec("Set client = CreateObject(""MSSOAP.SoapClient"")")
WS_Exec("client.MSSoapInit ""http://example.com/soap/wsdl""")
callhello = client.soapFunc("hello")
callanother = client.anotherSoapFunc(34234)
WS_Eval(result, callhello)
WS_Eval(result2, callanother)
Msgbox % result . "`n" . result2
WS_Uninitialize()
#Include ws4ahk.ahk ; http://www.autohotkey.net/~easycom/ws4ahk_public_api.html
C
Although this is a generic task to show that calling SOAP functions are possible, the following implementation is geared for the real world. In order to execute it, just choose an actual WSDL URL and construct the input XML files for the functions properly, this can also be done in C but requires libraries like xerces unless you want to really construct the XML from scratch.
#include <curl/curl.h>
#include <string.h>
#include <stdio.h>
size_t write_data(void *ptr, size_t size, size_t nmeb, void *stream){
return fwrite(ptr,size,nmeb,stream);
}
size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream){
return fread(ptr,size,nmeb,stream);
}
void callSOAP(char* URL, char * inFile, char * outFile) {
FILE * rfp = fopen(inFile, "r");
if(!rfp)
perror("Read File Open:");
FILE * wfp = fopen(outFile, "w+");
if(!wfp)
perror("Write File Open:");
struct curl_slist *header = NULL;
header = curl_slist_append (header, "Content-Type:text/xml");
header = curl_slist_append (header, "SOAPAction: rsc");
header = curl_slist_append (header, "Transfer-Encoding: chunked");
header = curl_slist_append (header, "Expect:");
CURL *curl;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, URL);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
curl_easy_setopt(curl, CURLOPT_READDATA, rfp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, wfp);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)-1);
curl_easy_setopt(curl, CURLOPT_VERBOSE,1L);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
}
int main(int argC,char* argV[])
{
if(argC!=4)
printf("Usage : %s <URL of WSDL> <Input file path> <Output File Path>",argV[0]);
else
callSOAP(argV[1],argV[2],argV[3]);
return 0;
}
Input XML for soapFunc()
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dom="http://example.com/soap/wsdl">
<soapenv:Header/>
<soapenv:Body>
<dom:soapFunc soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</soapenv:Body>
</soapenv:Envelope>
Input XML for anotherSoapFunc()
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:dom="http://example.com/soap/wsdl">
<soapenv:Header/>
<soapenv:Body>
<dom:anotherSoapFunc soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</soapenv:Body>
</soapenv:Envelope>
Clojure
(require '[clj-soap.core :as soap])
(let [client (soap/client-fn "http://example.com/soap/wsdl")]
(client :soapFunc)
(client :anotherSoapFunc))
ColdFusion
<cfset client = createObject("webservice","http://example.com/soap/wsdl")>
<cfset result = client.soapFunc("hello")>
<cfset result = client.anotherSoapFunc(34234)>
Diego
apt_knowledge(webservices); // Commanding apt_protocol(SOAP); will also apt_knowledge(webservices);
set_namespace(rosettacode);
add_webserv(ws)_protocol(SOAP)_wdsl(http://example.com/soap/wsdl)_me();
invoke_webserv(ws)_soapFunc(hello)_msg()_result()_me();
me_msg()_invoke(ws)_anotherSoapFunc(32234); // alternative syntax
reset_namespace();
F#
The availability of functions and the type of parameters is checked at compile time. The development environment supports auto-completion and parameter information just like for regular types.
open Microsoft.FSharp.Data.TypeProviders
type Wsdl = WsdlService<"http://example.com/soap/wsdl">
let result = Wsdl.soapFunc("hello")
let result2 = Wsdl.anotherSoapFunc(34234)
FreeBASIC
#include once "windows.bi"
#include once "win/wininet.bi"
#define CRLF !"\r\n"
Function sendSoapRequest(endpoint As String, soapAction As String, soapBody As String) As String
Dim As HINTERNET hInternet = InternetOpen("SOAP Client", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0)
Dim As String response = ""
If hInternet Then
Dim As HINTERNET hConnect = InternetConnect(hInternet, "example.com", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0)
If hConnect Then
Dim As HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", endpoint, NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0)
If hRequest Then
' Set headers
Dim As String headers = _
"Content-Type: text/xml;charset=UTF-8" & vbCrLf & _
"SOAPAction: " & soapAction & CRLF
HttpAddRequestHeaders(hRequest, headers, Len(headers), HTTP_ADDREQ_FLAG_ADD)
' Send request
If HttpSendRequest(hRequest, NULL, 0, Strptr(soapBody), Len(soapBody)) Then
' Read response
Dim As String buffer = Space(1024)
Dim As DWORD bytesRead
Do
If InternetReadFile(hRequest, Strptr(buffer), Len(buffer), @bytesRead) Then
If bytesRead = 0 Then Exit Do
response &= Left(buffer, bytesRead)
End If
Loop
End If
InternetCloseHandle(hRequest)
End If
InternetCloseHandle(hConnect)
End If
InternetCloseHandle(hInternet)
End If
Return response
End Function
Function soapFunc() As String
Dim As String endpoint = "http://example.com/soap"
Dim As String soapAction = "http://example.com/soap/soapFunc"
Dim As String soapEnvelope = _
"<?xml version='1.0' encoding='UTF-8'?>" & _
"<soap:Envelope " & _
"xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' " & _
"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" & _
"<soap:Body>" & _
"<soapFunc xmlns='http://example.com/soap'>" & _
"</soapFunc>" & _
"</soap:Body>" & _
"</soap:Envelope>"
Return sendSoapRequest(endpoint, soapAction, soapEnvelope)
End Function
Function anotherSoapFunc() As String
Dim As String endpoint = "http://example.com/soap"
Dim As String soapAction = "http://example.com/soap/anotherSoapFunc"
Dim As String soapEnvelope = _
"<?xml version='1.0' encoding='UTF-8'?>" & _
"<soap:Envelope " & _
"xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/' " & _
"xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" & _
"<soap:Body>" & _
"<anotherSoapFunc xmlns='http://example.com/soap'>" & _
"</anotherSoapFunc>" & _
"</soap:Body>" & _
"</soap:Envelope>"
Return sendSoapRequest(endpoint, soapAction, soapEnvelope)
End Function
' Main program
Print "Calling soapFunc..."
Print soapFunc()
Print
Print "Calling anotherSoapFunc..."
Print anotherSoapFunc()
Sleep
Go
To make this example a bit more interesting we test against a publicly available working SOAP server at the date of posting.
package main
import (
"fmt"
"github.com/tiaguinho/gosoap"
"log"
)
type CheckVatResponse struct {
CountryCode string `xml:"countryCode"`
VatNumber string `xml:"vatNumber"`
RequestDate string `xml:"requestDate"`
Valid string `xml:"valid"`
Name string `xml:"name"`
Address string `xml:"address"`
}
var (
rv CheckVatResponse
)
func check(err error) {
if err != nil {
log.Fatal(err)
}
}
func main() {
// create SOAP client
soap, err := gosoap.SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl")
// map parameter names to values
params := gosoap.Params{
"vatNumber": "6388047V",
"countryCode": "IE",
}
// call 'checkVat' function
err = soap.Call("checkVat", params)
check(err)
// unmarshal response to 'rv'
err = soap.Unmarshal(&rv)
check(err)
// print response
fmt.Println("Country Code : ", rv.CountryCode)
fmt.Println("Vat Number : ", rv.VatNumber)
fmt.Println("Request Date : ", rv.RequestDate)
fmt.Println("Valid : ", rv.Valid)
fmt.Println("Name : ", rv.Name)
fmt.Println("Address : ", rv.Address)
}
- Output:
Country Code : IE Vat Number : 6388047V Request Date : 2019-02-08+01:00 Valid : true Name : GOOGLE IRELAND LIMITED Address : 3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4
Icon and Unicon
provides the Soap package.
This code uses Unicon features not available in Icon.
import soap
procedure main(A)
soap := SoapClient(A[1] | "http://example.com/soap/wsdl") # Allow override of default
write("soapFunc: ",soap.call("soapFunc"))
write("anotherSoapFunc: ",soap.call("anotherSoapFunc"))
end
A matching SOAP server can be implemented as:
import soap
procedure main()
server := SoapServer("http://example.com/soap/wsdl")
server.addService("soapFunc", soapFunc)
server.addService("anotherSoapFunc", anotherSoapFunc)
msg := server.handleRequest()
write(msg)
exit(0)
end
procedure soapFunc(A[])
every (s := " ") ||:= (!A || " ")
return "Hello" || s[1:-1]
end
procedure anotherSoapFunc(A[])
every (s := " ") ||:= (!A || " ")
return "Goodbye" || s[1:-1]
end
Julia
using LibCURL
function callSOAP(url, infilename, outfilename)
rfp = open(infilename, "r")
wfp = open(outfilename, "w+")
header = curl_slist_append(header, "Content-Type:text/xml")
header = curl_slist_append(header, "SOAPAction: rsc");
header = curl_slist_append(header, "Transfer-Encoding: chunked")
header = curl_slist_append(header, "Expect:")
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, URL)
curl_easy_setopt(curl, CURLOPT_POST, 1L)
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data)
curl_easy_setopt(curl, CURLOPT_READDATA, rfp)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data)
curl_easy_setopt(curl, CURLOPT_WRITEDATA, wfp)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header)
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)-1)
curl_easy_setopt(curl, CURLOPT_VERBOSE,1L)
curl_easy_perform(curl)
curl_easy_cleanup(curl)
end
try
callSOAP(ARGS[1], ARGS[2], ARGS[3])
catch y
println("Usage : $(@__FILE__) <URL of WSDL> <Input file path> <Output File Path>")
end
Kotlin
Assuming that libcurl is already installed on your system in the default location(s), you first need to build libcurl.klib using the following .def file and the cinterop tool:
// libcurl.def headers = /usr/include/curl/curl.h linkerOpts.linux = -L/usr/lib/x86_64-linux-gnu -lcurl
Next, you need to compile the following Kotlin program, linking against libcurl.klib.
// Kotlin Native v0.6
import kotlinx.cinterop.*
import platform.posix.*
import libcurl.*
fun writeData(ptr: COpaquePointer?, size: size_t, nmeb: size_t, stream: COpaquePointer?)
= fwrite(ptr, size, nmeb, stream?.reinterpret<FILE>())
fun readData(ptr: COpaquePointer?, size: size_t, nmeb: size_t, stream: COpaquePointer?)
= fread(ptr, size, nmeb, stream?.reinterpret<FILE>())
fun callSOAP(url: String, inFile: String, outFile: String) {
val rfp = fopen(inFile, "r")
if (rfp == null) {
perror("Read File Open: ")
exit(1)
}
val wfp = fopen(outFile, "w+")
if (wfp == null) {
perror("Write File Open: ")
fclose(rfp)
exit(1)
}
var header: CPointer<curl_slist>? = null
header = curl_slist_append (header, "Content-Type:text/xml")
header = curl_slist_append (header, "SOAPAction: rsc")
header = curl_slist_append (header, "Transfer-Encoding: chunked")
header = curl_slist_append (header, "Expect:")
val curl = curl_easy_init()
if (curl != null) {
curl_easy_setopt(curl, CURLOPT_URL, url)
curl_easy_setopt(curl, CURLOPT_POST, 1L)
curl_easy_setopt(curl, CURLOPT_READFUNCTION, staticCFunction(::readData))
curl_easy_setopt(curl, CURLOPT_READDATA, rfp)
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, staticCFunction(::writeData))
curl_easy_setopt(curl, CURLOPT_WRITEDATA, wfp)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header)
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, -1L)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L)
curl_easy_perform(curl)
curl_easy_cleanup(curl)
}
curl_slist_free_all(header)
fclose(rfp)
fclose(wfp)
}
fun main(args: Array<String>) {
if (args.size != 3) {
println("You need to pass exactly 3 command line arguments, namely :-")
println(" <URL of WSDL> <Input file path> <Output File Path>")
return
}
callSOAP(args[0], args[1], args[2])
}
Finally, the resulting .kexe file should be executed passing it similar command line arguments to the C entry.
Mathematica /Wolfram Language
InstallService["http://example.com/soap/wsdl"];
soapFunc["Hello"];
anotherSoapFunc[12345];
Perl
use SOAP::Lite;
print SOAP::Lite
-> service('http://example.com/soap/wsdl')
-> soapFunc("hello");
print SOAP::Lite
-> service('http://example.com/soap/wsdl')
-> anotherSoapFunc(34234);
Phix
-- -- demo\rosetta\SOAP.exw -- ===================== -- -- translated from https://gist.github.com/p120ph37/8281362ae9da042f3043 -- without js -- (libcurl) include builtins\libcurl.e include builtins\xml.e -- xml_encode() function write_callback(atom pData, integer size, nmemb, atom /*pUserdata*/) integer bytes_written = size*nmemb puts(1,peek({pData,bytes_written})) return bytes_written end function constant write_cb = call_back({'+',write_callback}) function compose_soap_frobnicate(string foo, bar, baz) return sprintf(""" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <frobnicate xmlns="http://example.com/frobnicate"> <foo>%s</foo> <bar>%s</bar> <baz>%s</baz> </frobnicate> </soap:Body> </soap:Envelope>""",{xml_encode(foo),xml_encode(bar),xml_encode(baz)}) end function curl_global_init() atom curl = curl_easy_init() curl_easy_setopt(curl, CURLOPT_URL, "https://ameriwether.com/cgi-bin/info.pl") string soap = compose_soap_frobnicate("'Ein'", ">Zwei<", "\"Drei\"") curl_easy_setopt(curl, CURLOPT_POSTFIELDS, soap) curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC) curl_easy_setopt(curl, CURLOPT_USERNAME, "user") curl_easy_setopt(curl, CURLOPT_PASSWORD, "password") curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb) atom headers = NULL headers = curl_slist_append(headers, "Content-Type: text/xml; charset=utf-8") headers = curl_slist_append(headers, "SOAPAction: \"https://ameriwether.com/cgi-bin/info.pl/frobnicate\"") headers = curl_slist_append(headers, "Accept: text/plain") -- Example output easier to read as plain text. curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers) -- Make the example URL work even if your CA bundle is missing. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false) CURLcode res = curl_easy_perform(curl) if res!=CURLE_OK then printf(2, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)) end if curl_slist_free_all(headers) curl_easy_cleanup(curl) curl_global_cleanup()
- Output:
note: foo/bar/baz are shown properly escaped on the terminal.
TCP Connection: 127.0.0.1:40056 > 127.0.0.1:443 SSL Layer (TLSv1.2): CIPHER=ECDHE-RSA-AES256-GCM-SHA384 CIPHER_ALGKEYSIZE=256 CIPHER_EXPORT=false CIPHER_USEKEYSIZE=256 CLIENT_VERIFY=NONE COMPRESS_METHOD=NULL SECURE_RENEG=true SESSION_RESUMED=Initial TLS_SNI=ameriwether.com HTTP Request: POST /cgi-bin/info.pl HTTP/1.1 HTTP Headers: Accept: text/plain ContentLength: 411 ContentType: text/xml; charset=utf-8 Host: ameriwether.com Soapaction: "https://ameriwether.com/cgi-bin/info.pl/frobnicate" CGI Params: POSTDATA=<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <frobnicate xmlns="http://example.com/frobnicate"> <foo>'Ein'</foo> <bar>>Zwei<</bar> <baz>"Drei"</baz> </frobnicate> </soap:Body> </soap:Envelope>
PHP
<?php
//load the wsdl file
$client = new SoapClient("http://example.com/soap/definition.wsdl");
//functions are now available to be called
$result = $client->soapFunc("hello");
$result = $client->anotherSoapFunc(34234);
//SOAP Information
$client = new SoapClient("http://example.com/soap/definition.wsdl");
//list of SOAP types
print_r($client->__getTypes());
//list if SOAP Functions
print_r($client->__getFunctions());
?>
PureBasic
XIncludeFile "COMatePLUS.pbi"
Define.COMateObject soapObject = COMate_CreateObject("MSSOAP.SoapClient")
soapObject\Invoke("MSSoapInit('http://example.com/soap/wsdl')")
result = soapObject\Invoke("soapFunc('hello')")
result2 = soapObject\Invoke("anotherSoapFunc(34234)")
Python
from SOAPpy import WSDL
proxy = WSDL.Proxy("http://example.com/soap/wsdl")
result = proxy.soapFunc("hello")
result = proxy.anotherSoapFunc(34234)
Note: SOAPpy is a third-party module and can be found at Python Web Services
Raku
(formerly Perl 6)
# Reference:
# https://github.com/retupmoca/P6-SOAP
# http://wiki.dreamfactory.com/DreamFactory/Tutorials/Temp_Conversion_SOAP_API
use v6;
use SOAP::Client;
my $request = SOAP::Client.new('http://www.w3schools.com/xml/tempconvert.asmx?WSDL') or die;
say $request.call('CelsiusToFahrenheit', Celsius => 100 ) or die;
say $request.call('FahrenheitToCelsius', Fahrenheit => 212 ) or die;
- Output:
{CelsiusToFahrenheitResult => [212]} {FahrenheitToCelsiusResult => [100]}
Ruby
require 'soap/wsdlDriver'
wsdl = SOAP::WSDLDriverFactory.new("http://example.com/soap/wsdl")
soap = wsdl.create_rpc_driver
response1 = soap.soapFunc(:elementName => "value")
puts response1.soapFuncReturn
response2 = soap.anotherSoapFunc(:aNumber => 42)
puts response2.anotherSoapFuncReturn
Smalltalk
(not sure about Pharo and VW)
(assuming that the open source SOAPSpray package has been loaded.)
| service client response1 response2 |
service := SprayWSDLService onUrl: 'http://example.com/soap/wsdl'.
client := service createClient.
response1 := client send: 'soapFunc' withArguments:{ 'hello' }.
response2 := client send: 'anotherSoapFunc' withArguments:{ 34234 }.
Tcl
Uses the tclws
package.
package require WS::Client
# Grok the service, and generate stubs
::WS::Client::GetAndParseWsdl http://example.com/soap/wsdl
::WS::Client::CreateStubs ExampleService ;# Assume that's the service name...
# Do the calls
set result1 [ExampleService::soapFunc "hello"]
set result2 [ExampleService::anotherSoapFunc 34234]
Uniface
Assuming http://example.com/soap/wsdl has been imported into repository and, as result, exists a new component called "webservice"
variables
string result1, result2
endvariables
activate "webservice".soapFunc("hello", result1)
activate "webservice".anotherSoapFunc(34234, result2)
VBScript
Dim client
Dim result
Set client = CreateObject("MSSOAP.SoapClient")
client.MSSoapInit "http://example.com/soap/wsdl"
result = client.soapFunc("hello")
result = client.anotherSoapFunc(34234)
Visual Objects
LOCAL oSoapClient AS OBJECT //OLEAUTOOBJECT
LOCAL cUrl AS STRING
LOCAL uResult AS USUAL
oSoapClient := OLEAutoObject{"MSSOAP.SoapClient30"}
cUrl := "http://example.com/soap/wsdl"
IF oSoapClient:fInit
oSoapClient:mssoapinit(cUrl,"", "", "" )
uResult := oSoapClient:soapFunc("hello")
uResult := oSoapClient:anotherSoapFunc(34234)
ENDIF
Wren
An embedded program so we can ask the C host to communicate with libcurl for us.
/* SOAP.wren */
var CURLOPT_URL = 10002
var CURLOPT_POST = 47
var CURLOPT_READFUNCTION = 20012
var CURLOPT_READDATA = 10009
var CURLOPT_WRITEFUNCTION = 20011
var CURLOPT_WRITEDATA = 10001
var CURLOPT_HTTPHEADER = 10023
var CURLOPT_POSTFIELDSIZE_LARGE = 30120
var CURLOPT_VERBOSE = 41
foreign class File {
foreign static url
foreign static readFile
foreign static writeFile
construct open(filename, mode) {}
}
foreign class CurlSlist {
construct new() {}
foreign append(s)
}
foreign class Curl {
construct easyInit() {}
foreign easySetOpt(opt, param)
foreign easyPerform()
foreign easyCleanup()
}
var soap = Fn.new { |url, inFile, outFile|
var rfp = File.open(inFile, "r")
if (rfp == 0) Fiber.abort("Error opening read file.")
var wfp = File.open(outFile, "w+")
if (wfp == 0) Fiber.abort("Error opening write file.")
var header = CurlSlist.new()
header = header.append("Content-Type:text/xml")
header = header.append("SOAPAction: rsc")
header = header.append("Transfer-Encoding: chunked")
header = header.append("Expect:")
var curl = Curl.easyInit()
if (curl == 0) Fiber.abort("Error initializing cURL.")
curl.easySetOpt(CURLOPT_URL, url)
curl.easySetOpt(CURLOPT_POST, 1)
curl.easySetOpt(CURLOPT_READFUNCTION, 0) // read function to be supplied by C
curl.easySetOpt(CURLOPT_READDATA, rfp)
curl.easySetOpt(CURLOPT_WRITEFUNCTION, 0) // write function to be supplied by C
curl.easySetOpt(CURLOPT_WRITEDATA, wfp)
curl.easySetOpt(CURLOPT_HTTPHEADER, header)
curl.easySetOpt(CURLOPT_POSTFIELDSIZE_LARGE, -1)
curl.easySetOpt(CURLOPT_VERBOSE, 1)
curl.easyPerform()
curl.easyCleanup()
}
soap.call(File.url, File.readFile, File.writeFile)
We now embed this in the following C program, compile and run it.
/* gcc SOAP.c -o SOAP -lcurl -lwren -lm */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"
/* C <=> Wren interface functions */
char *url, *read_file, *write_file;
size_t write_data(void *ptr, size_t size, size_t nmeb, void *stream) {
return fwrite(ptr, size, nmeb, stream);
}
size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream) {
return fread(ptr, size, nmeb, stream);
}
void C_url(WrenVM* vm) {
wrenSetSlotString(vm, 0, url);
}
void C_readFile(WrenVM* vm) {
wrenSetSlotString(vm, 0, read_file);
}
void C_writeFile(WrenVM* vm) {
wrenSetSlotString(vm, 0, write_file);
}
void C_fileAllocate(WrenVM* vm) {
FILE** fp = (FILE**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(FILE*));
const char *filename = wrenGetSlotString(vm, 1);
const char *mode = wrenGetSlotString(vm, 2);
*fp = fopen(filename, mode);
}
void C_curlSlistAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct curl_slist*));
}
void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}
void C_append(WrenVM* vm) {
struct curl_slist** plist = (struct curl_slist**)wrenGetSlotForeign(vm, 0);
const char *s = wrenGetSlotString(vm, 1);
*plist = curl_slist_append(*plist, s);
}
void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_perform(curl);
}
void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}
void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
if (opt < 10000) {
long lparam = (long)wrenGetSlotDouble(vm, 2);
curl_easy_setopt(curl, opt, lparam);
} else if (opt < 20000) {
if (opt == CURLOPT_WRITEDATA || opt == CURLOPT_READDATA) {
FILE *fp = *(FILE**)wrenGetSlotForeign(vm, 2);
curl_easy_setopt(curl, opt, fp);
} else if (opt == CURLOPT_URL) {
const char *url = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, url);
} else if (opt == CURLOPT_HTTPHEADER) {
struct curl_slist* header = *(struct curl_slist**)wrenGetSlotForeign(vm, 2);
curl_easy_setopt(curl, opt, header);
}
} else if (opt < 30000) {
if (opt == CURLOPT_READFUNCTION) {
curl_easy_setopt(curl, opt, &read_data);
} else if (opt == CURLOPT_WRITEFUNCTION) {
curl_easy_setopt(curl, opt, &write_data);
}
} else {
curl_off_t cparam = (curl_off_t)wrenGetSlotDouble(vm, 2);
curl_easy_setopt(curl, opt, cparam);
}
}
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "File") == 0) {
methods.allocate = C_fileAllocate;
} else if (strcmp(className, "CurlSlist") == 0) {
methods.allocate = C_curlSlistAllocate;
} else if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "File") == 0) {
if (isStatic && strcmp(signature, "url") == 0) return C_url;
if (isStatic && strcmp(signature, "readFile") == 0) return C_readFile;
if (isStatic && strcmp(signature, "writeFile") == 0) return C_writeFile;
} else if (strcmp(className, "CurlSlist") == 0) {
if (!isStatic && strcmp(signature, "append(_)") == 0) return C_append;
} else if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
int main(int argc, char **argv) {
if (argc != 4 ) {
printf("Usage : %s <URL of WSDL> <Input file path> <Output file path>", argv[0]);
return 0;
}
url = argv[1];
read_file = argv[2];
write_file = argv[3];
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "SOAP.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}
- Programming Tasks
- Networking and Web Interaction
- Less Than 10 Examples
- Clarify task
- ActionScript
- AutoHotkey
- Ws4ahk
- C
- Libcurl
- Clojure
- ColdFusion
- Diego
- F Sharp
- FreeBASIC
- Go
- Go Soap
- Unicon
- Unicon Code Library
- Julia
- Kotlin
- Mathematica
- Wolfram Language
- Perl
- Phix
- Phix/libcurl
- PHP
- PureBasic
- Python
- Raku
- Ruby
- Smalltalk
- Tcl
- Uniface
- VBScript
- Visual Objects
- Wren
- Batch File/Omit
- Brainf***/Omit
- GUISS/Omit
- M4/Omit
- Maxima/Omit
- PARI/GP/Omit
- PostScript/Omit
- Retro/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Unlambda/Omit
- Yorick/Omit
- ZX Spectrum Basic/Omit