|
//-----------------------------------------------------------------------------
// REST example using basic authentication
// Sending a request to /test will return a response containing information
// about the request as JSON.
// The client must provide the username "user" and the password "pass" to
//
//-----------------------------------------------------------------------------
INCLUDE rtcu.inc
#DEFINE EP_AUTH 1
#DEFINE EP_CONTENT 2
#DEFINE EP_LOGOUT 3
// Authentication callback
// Validates the username and password.
// If called from /logout, it will just return Unauthorized
// to make the client forget its current authentication parameters.
FUNCTION CALLBACK devicesAuthCallback : INT;
VAR_INPUT
req : SYSHANDLE;
resp : SYSHANDLE;
arg : DINT; // User argument indicating endpoint.
END_VAR;
VAR
str, user, pass : STRING;
i : INT;
rc : INT;
END_VAR;
restReqClientAddressGet (req:=req, address:=str);
DebugFmt(message:="Auth Request from "+str);
// Enable basic authentication in the response
rc := restRespBasicAuthSet(resp:=resp);
DebugFmt(message:="restRespBasicAuthSet: \1", v1:=rc);
// Read current authentication
rc := restReqBasicAuthGet(req:=req, user:=user, pass:=pass);
DebugFmt(message:="restReqBasicAuthGet: \1, "+user+":"+pass, v1:=rc);
IF arg = EP_LOGOUT THEN
restRespBodySetString(resp:=resp, str := "Logged out");
// unauthorized, request basic authentication
devicesAuthCallback := -1;
ELSE
IF user = "user" AND pass = "pass" THEN
// Valid user, continue with content callback
devicesAuthCallback:=0;
ELSE
restRespBodySetString(resp:=resp, str := "Invalid user");
// unauthorized, request basic authentication
devicesAuthCallback := -1;
END_IF;
END_IF;
END_FUNCTION;
// Content callback
// Creates a response containing the request parameters converted into JSON
FUNCTION CALLBACK devicesGetCallback: INT;
VAR_INPUT
req : SYSHANDLE;
resp : SYSHANDLE;
arg : DINT;
END_VAR;
VAR
str, name : STRING;
rc, i : INT;
json, o, a : SYSHANDLE;
pos, sz, len : DINT;
buf : ARRAY [1..32] OF SINT;
END_VAR;
// Create main JSON object
jsonCreateObject(o:=json);
// Headers
jsonCreateObject(o:=o);
i := 0;
rc := restReqHeaderKey(req:=req, idx:=i, name:=name);
WHILE rc > 0 DO
str := "";
restReqHeaderGet(req:=req, name:=name, value := str);
jsonSetValueString(o:=o, key:=name, value:=str);
i := i + 1;
rc := restReqHeaderKey(req:=req, idx:=i, name:=name);
END_WHILE;
jsonSetValue(o:=json, key:="headers", value:=o);
jsonFree(o:=o);
// Queries
jsonCreateObject(o:=o);
i := 0;
rc := restReqQueryKey(req:=req, idx:=i, name:=name);
WHILE rc > 0 DO
restReqQueryGet(req:=req, name:=name, value := str);
jsonSetValueString(o:=o, key:=name, value:=str);
i := i + 1;
rc := restReqQueryKey(req:=req, idx:=i, name:=name);
END_WHILE;
jsonSetValue(o:=json, key:="queries", value:=o);
jsonFree(o:=o);
// Post parameters
jsonCreateObject(o:=o);
i := 0;
rc := restReqPostKey(req:=req, idx:=i, name:=name);
WHILE rc > 0 DO
restReqPostGet(req:=req, name:=name, value := str);
jsonSetValueString(o:=o, key:=name, value:=str);
i := i + 1;
rc := restReqPostKey(req:=req, idx:=i, name:=name);
END_WHILE;
jsonSetValue(o:=json, key:="posts", value:=o);
jsonFree(o:=o);
// Body size
sz := restReqBodySize(req:=req);
jsonSetValueInt(o:=json, key:="body-size", value:=sz);
// Body as text
str := "";
restReqBodyGetString(req:=req, str:=str);
jsonSetValueString(o:=json, key:="body-text", value:=str);
// Raw body, split into smaller hex-strings.
rc := jsonCreateArray(o:=a);
pos := 0;
WHILE pos < sz DO
len := restReqBodyGetRaw(req:=req, dst:=ADDR(buf), size := SIZEOF(buf), start := pos);
IF len <= 0 THEN
DebugFmt(message:="failed to get body: \4", v4:=len);
EXIT;
END_IF;
str := "";
FOR i := 1 TO len DO
str := str+sintToHex(v:=buf[i]);
END_FOR;
jsonAddValueString(o:=a, value:=str);
pos := pos + len;
END_WHILE;
jsonSetValue(o:=json, key:="body-raw", value:=a);
rc := jsonFree(o:=a);
// Set response
rc := restRespBodySetJSON(resp:=resp, json:=json);
DebugFmt(message:="restRespBodySetJSON: \1, ", v1:=rc);
rc := jsonFree(o:=json);
DebugFmt(message:="jsonFree: \1, ", v1:=rc);
devicesGetCallback := 200;
END_FUNCTION;
// Send a request to the local server and show the response.
FUNCTION SendRequest;
VAR
str, name : STRING;
req, resp : SYSHANDLE;
rc, i : INT;
pos, sz, len : DINT;
buf : ARRAY[1..16] OF SINT;
END_VAR;
DebugMsg(message:="--------");
rc := restReqCreate(req:=req, method := "POST",
url := "http://127.0.0.1/test");
rc := restReqQuerySet(req:=req, name := "query", value:="value 1");
rc := restReqBodySetString(req:=req, str:="{$"test$":42}");
rc := restReqHeaderSet(req:=req, name:="Accept", value:="application/json");
// Set authentication
rc := restReqBasicAuthSet(req:=req, user:="user", pass:="pass");
// Send request
rc := restClientRequest(req:=req, resp := resp);
DebugFmt(message:="Send request: \1", v1:=rc);
// Handle response
IF rc = 200 THEN
// success
// Print headers
i := 0;
rc := restRespHeaderKey(resp:=resp, idx:=i, name:=name);
WHILE rc > 0 DO
restRespHeaderGet(resp:=resp, name:=name, value := str);
DebugMsg(message:=" "+name+": "+str);
i := i + 1;
rc := restRespHeaderKey(resp:=resp, idx:=i, name:=name);
END_WHILE;
// Print body information
sz := restRespBodySize(resp:=resp);
DebugFmt(message:="body size: \4", v4:=sz);
rc := restRespBodyGetString(resp:=resp, str := str);
DebugFmt(message:="body: "+str);
// Print raw body
pos := 0;
WHILE pos < sz DO
len := restRespBodyGetRaw(resp:=resp, dst:=ADDR(buf), size := SIZEOF(buf), start := pos);
IF len <= 0 THEN
DebugFmt(message:="failed to get body: \4", v4:=len);
EXIT;
END_IF;
str := dintToHex(v:=pos)+": ";
FOR i := 1 TO len DO
str := str+sintToHex(v:=buf[i])+" ";
END_FOR;
DebugMsg(message:=str);
pos := pos + len;
END_WHILE;
rc := restRespFree(resp:=resp);
ELSIF rc > 0 THEN
rc := restRespBodyGetString(resp:=resp, str := str);
DebugFmt(message:="Request failed: "+str);
END_IF;
rc := restReqFree(req:=req);
END_FUNCTION;
PROGRAM auth;
// These are the local variables of the program block
VAR
rc : INT;
serv : SYSHANDLE;
port : DINT := 80;
END_VAR;
// Open LAN interface to provide access for external connections.
netOpen(iface:=2);
rc := restServerCreate(handle:=serv, port:=port);
DebugFmt(message:="restServerCreate: \1", v1:=rc);
// Add authentication endpoint with high priority
rc := restServerEndpointAdd(handle:=serv, url_prefix:="/test",
cb_func:=@devicesAuthCallback, cb_arg:=EP_AUTH);
DebugFmt(message:="restServerEndpointAdd: \1", v1:=rc);
// Add content endpoint with lower priority
rc := restServerEndpointAdd(handle:=serv, url_prefix:="/test",
cb_func:=@devicesGetCallback, cb_arg:=EP_CONTENT, prio:=1);
DebugFmt(message:="restServerEndpointAdd: \1", v1:=rc);
// Add logout endpoint, reusing authentication endpoint
rc := restServerEndpointAdd(handle:=serv, url_prefix:="/logout",
cb_func:=@devicesAuthCallback, cb_arg:=EP_LOGOUT);
DebugFmt(message:="restServerEndpointAdd: \1", v1:=rc);
// Start server
rc := restServerStart(handle:=serv);
DebugFmt(message:="restServerStart: \1", v1:=rc);
BEGIN
// send local request
SendRequest();
Sleep(delay:=30000);
END;
END_PROGRAM;
|