blob: 3f66f5a42223e8f1ac76010fed6c3ab81e527ea1 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_CLL_DsRestAPI_HTTPServer_Functions
//
// Purpose:
// This module contains functions of EPTF_CLL_DsRestAPI_HTTPServer.
//
// Module depends on:
// <EPTF_CLL_DsRestAPI_HTTPServer_Definitions>
// <EPTF_CLL_DsRestAPI_DSServer_Functions>
// <EPTF_CLL_Base_Functions>
// <IPL4asp_Types>
// <IPL4asp_PortType>
// <TCCConversion_Functions>
// <TCCFileIO_Functions>
// <EPTF_CLL_HashMapInt2Int_Functions>
// <EPTF_CLL_FBQ_Functions>
// <EPTF_CLL_Common_Definitions>
// <EPTF_CLL_Common_Functions>
// <HTTPmsg_MessageLen>
//
// Current Owner:
// Tamas Kis (ekistam)
//
// Last Review Date:
// -
//
// Detailed Comments:
// -
//
///////////////////////////////////////////////////////////////
module EPTF_CLL_DsRestAPI_HTTPServer_Functions {
//=========================================================================
// Import Part
//=========================================================================
import from EPTF_CLL_DsRestAPI_HTTPServer_Definitions all;
import from EPTF_CLL_DsRestAPI_DSServer_Functions all;
import from EPTF_CLL_Base_Functions all;
import from IPL4asp_Types all;
import from IPL4asp_PortType all;
import from TCCConversion_Functions all;
import from TCCFileIO_Functions all;
import from EPTF_CLL_HashMap_Functions all;
import from EPTF_CLL_HashMapInt2Int_Functions all;
import from EPTF_CLL_FBQ_Functions all;
import from EPTF_CLL_Common_Definitions all;
import from EPTF_CLL_Common_Functions all;
import from HTTPmsg_MessageLen all;
friend module EPTF_CLL_DsRestAPI_Functions;
private external function ef_DsRestAPI_enc_FileInfoList(in EPTF_DsRestAPI_HTTPServer_FileInfoList_Wrapper pl_par) return octetstring with { extension "prototype(convert) encode(JSON) errorbehavior(ALL:WARNING)" }
group FriendFunctions {
friend function f_EPTF_DsRestAPI_HTTPServer_init_CT(in charstring pl_selfName) runs on EPTF_DsRestAPI_HTTPServer_CT {
if (not v_DsRestAPI_HTTPServer_initialized) {
f_EPTF_HashMap_init_CT(f_EPTF_Base_selfName());
v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Hash := f_EPTF_int2int_HashMap_New(cg_EPTF_DsRestAPI_Browser_chunk_FromConnId_HashMapName);
f_EPTF_FBQ_init_CT(pl_selfName);
f_EPTF_FBQ_initFreeBusyQueue(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Queue);
f_EPTF_FBQ_initFreeBusyQueue(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
f_EPTF_Base_init_CT(pl_selfName);
f_EPTF_DsRestAPI_DSServer_init_CT(pl_selfName);
f_EPTF_Base_registerCleanup(refers(f_EPTF_DsRestAPI_HTTPServer_cleanup_CT));
v_EPTF_DsRestAPI_HTTPServer_directory := "";
v_EPTF_DsRestAPI_HTTPServer_path := "";
map(self:v_DsRestAPI_HTTPServer_IPL4_PCO_PT, system:v_DsRestAPI_HTTPServer_IPL4_PCO_PT);
var f_IPL4_getMsgLen v_getMsg_Func := refers(f_EPTF_DsRestAPI_HTTPServer_GetMsgLen);
f_IPL4_setGetMsgLen(v_DsRestAPI_HTTPServer_IPL4_PCO_PT,-1, v_getMsg_Func, {});
t_bufferTimer.start;
v_DsRestAPI_HTTPServer_mainHandler := activate(as_EPTF_DsRestAPI_HTTPServer_mainHandler());
v_DsRestAPI_HTTPServer_initialized := true;
}
}
friend function f_EPTF_DsRestAPI_HTTPServer_listen(in charstring pl_hostIPAddress, in integer pl_hostPort) runs on EPTF_DsRestAPI_HTTPServer_CT return integer{
var integer vl_result := -1;
f_EPTF_Common_user("DsRestAPI HTTP Server is trying to listen on " & pl_hostIPAddress & ":" & int2str(pl_hostPort));
var Result vl_res := f_IPL4_listen(v_DsRestAPI_HTTPServer_IPL4_PCO_PT, pl_hostIPAddress, pl_hostPort, { tcp := {} }, { {reuseAddress := { enable := true } } });
if (vl_res.errorCode == omit) {
vl_result := 0;
v_EPTF_DsRestAPI_HTTPServer_connId := vl_res.connId;
}
return vl_result;
}
friend function f_EPTF_DsRestAPI_HTTPServer_close() runs on EPTF_DsRestAPI_HTTPServer_CT return integer{
var integer vl_result := -1;
if (v_EPTF_DsRestAPI_HTTPServer_connId != -1) {
var Result vl_res := f_IPL4_close(v_DsRestAPI_HTTPServer_IPL4_PCO_PT, v_EPTF_DsRestAPI_HTTPServer_connId);
if (vl_res.errorCode == omit) {
vl_result := 0;
}
}
return vl_result;
}
friend function f_EPTF_DsRestAPI_HTTPServer_setDir(in charstring pl_HTTPServerDir) runs on EPTF_DsRestAPI_HTTPServer_CT {
if(lengthof(pl_HTTPServerDir) > 0 and pl_HTTPServerDir[lengthof(pl_HTTPServerDir)-1] != cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash){
pl_HTTPServerDir := pl_HTTPServerDir & cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash;
}
v_EPTF_DsRestAPI_HTTPServer_directory := pl_HTTPServerDir;
if(lengthof(pl_HTTPServerDir) == 0) {
v_EPTF_DsRestAPI_HTTPServer_path := "";
} else {
v_EPTF_DsRestAPI_HTTPServer_path := f_EPTF_DsRestAPI_HTTPServer_directory();
}
}
friend external function ef_EPTF_DsRestAPI_FIO_deleteResource(in charstring pl_path) return integer;
} // ~ group FriendFunctions
group PrivateFunction {
private function f_EPTF_DsRestAPI_HTTPServer_cleanup_CT() runs on EPTF_DsRestAPI_HTTPServer_CT {
if (v_DsRestAPI_HTTPServer_initialized) {
deactivate(v_DsRestAPI_HTTPServer_mainHandler);
unmap(self:v_DsRestAPI_HTTPServer_IPL4_PCO_PT, system:v_DsRestAPI_HTTPServer_IPL4_PCO_PT);
f_EPTF_FBQ_deleteFreeBusyQueue(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Queue);
f_EPTF_int2int_HashMap_Delete(cg_EPTF_DsRestAPI_Browser_chunk_FromConnId_HashMapName);
f_EPTF_FBQ_deleteFreeBusyQueue(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
v_EPTF_DsRestAPI_Browser_Buffer_Messages := {};
v_DsRestAPI_HTTPServer_initialized := false;
}
}
private function f_EPTF_DsRestAPI_HTTPServer_GetMsgLen(
in octetstring stream,
inout ro_integer args)
return integer {
return f_HTTPMessage_len(stream);
};
private function f_EPTF_DsRestAPI_HTTPServer_getExtension(in charstring pl_inputStr) return charstring {
var integer vl_extensionStarts := -1;
var integer vl_searchOffset := 0;
do {
var integer vl_extensionStartsL := f_strstr(pl_inputStr, cg_EPTF_DsRestAPI_HTTPServer_HTTP_Dot, vl_searchOffset);
if (vl_extensionStartsL > 0) {
vl_extensionStarts := vl_extensionStartsL;
vl_searchOffset := vl_extensionStartsL + 1;
} else {
break;
}
} while (true);
var charstring vl_result := "";
if(vl_extensionStarts > 0) {
vl_result := substr(pl_inputStr, vl_extensionStarts + 1, lengthof(pl_inputStr) - vl_extensionStarts - 1);
}
return f_putInLowercase(vl_result);
}
// f_EPTF_DsRestAPI_HTTPServer_assembleHTTPResponseHeaders: Generate Response headers and the body separator.
private function f_EPTF_DsRestAPI_HTTPServer_assembleHTTPResponseHeaders(in integer pl_contentLength := 0, in charstring pl_contentType := "text/html", in charstring pl_statusText := "OK", in charstring pl_statusCode := "200") return octetstring {
var charstring vl_result := cg_EPTF_DsRestAPI_HTTPHeaderChunk01
& pl_statusCode
& cg_EPTF_DsRestAPI_HTTPServer_HTTP_SP
& pl_statusText
& cg_EPTF_DsRestAPI_HTTPHeaderChunk02
& int2str(pl_contentLength)
& cg_EPTF_DsRestAPI_HTTPHeaderChunk03
& pl_contentType
& cg_EPTF_DsRestAPI_HTTPHeaderChunk04
return char2oct(vl_result);
}
private function f_EPTF_DsRestAPI_HTTPServer_encodeHTTP(in charstring pl_message, in charstring pl_contentType := "text/html", in charstring pl_statusText := "OK", in charstring pl_statusCode := "200") return octetstring {
var octetstring vl_headers := f_EPTF_DsRestAPI_HTTPServer_assembleHTTPResponseHeaders(lengthof(pl_message), pl_contentType, pl_statusText, pl_statusCode);
return vl_headers & char2oct(pl_message);
}
private function f_EPTF_DsRestAPI_HTTPServer_encodeHTTP_oct(in octetstring pl_message, in charstring pl_contentType := "text/html", in charstring pl_statusText := "OK", in charstring pl_statusCode := "200") return octetstring {
var octetstring vl_headers := f_EPTF_DsRestAPI_HTTPServer_assembleHTTPResponseHeaders(lengthof(pl_message), pl_contentType, pl_statusText, pl_statusCode);
return vl_headers & pl_message;
}
private function f_EPTF_DsRestAPI_HTTPServer_getToken(in octetstring pl_src, in integer pl_offset, in octetstring pl_separator := '20'O) return octetstring {
var octetstring vl_token := ''O;
var integer vl_sepPosition := f_strstr_oct(pl_src, pl_separator, pl_offset);
if (lengthof(pl_src) > pl_offset) {
if (vl_sepPosition > 0) {
vl_token := substr(pl_src, pl_offset, vl_sepPosition - pl_offset);
} else { // last token
vl_token := substr(pl_src, pl_offset, lengthof(pl_src) - pl_offset);
}
}
return vl_token;
}
private function f_EPTF_DsRestAPI_HTTPServer_decodeHTTP(in octetstring pl_msg, out charstring pl_method, out charstring pl_uri, out integer pl_bodyLength, out octetstring pl_body, out charstring pl_queryString, in HostName pl_remoteHost) return integer {
var integer vl_result := -1;
var integer vl_bodyOffset := f_strstr_oct(pl_msg, cg_EPTF_DsRestAPI_HTTPServer_HTTP_CRLFCRLF_oct);
var charstring vl_tmp;
/* // Commented out as it could be the end of a really screwed up TCP chunk.
if (lengthof(pl_msg) < 16) { // Smaller than shortest possible request line.
f_EPTF_Common_user("Suspicious HTTP Request: '" & oct2str(pl_msg) & "'O");
}
*/
pl_body := ''O;
if (lengthof(pl_msg) != 0 and f_oct2char_safe(pl_msg, vl_tmp) and f_strstr_oct(pl_msg, cg_EPTF_DsRestAPI_HTTPServer_HTTP_CRLF_oct) >= 0) {
var octetstring vl_requestLine := substr(pl_msg, 0, f_strstr_oct(pl_msg, cg_EPTF_DsRestAPI_HTTPServer_HTTP_CRLF_oct));
pl_bodyLength := 0;
pl_queryString := "";
pl_method := oct2char(f_EPTF_DsRestAPI_HTTPServer_getToken(vl_requestLine, 0));
var charstring vl_uri := oct2char(f_EPTF_DsRestAPI_HTTPServer_getToken(vl_requestLine, lengthof(pl_method) + 1));
var charstring vl_version := oct2char(f_EPTF_DsRestAPI_HTTPServer_getToken(vl_requestLine, lengthof(pl_method) + lengthof(vl_uri) + 2));
var integer vl_sepPosition := f_strstr(vl_uri, "?", 0);
if (vl_sepPosition > 0) {
pl_uri := substr(vl_uri, 0, vl_sepPosition);
pl_queryString := substr(vl_uri, vl_sepPosition+1, lengthof(vl_uri)-vl_sepPosition-1);
} else {
pl_uri := vl_uri;
}
if (lengthof(pl_method) == 0 or lengthof(pl_uri) == 0 or lengthof(vl_version) == 0) { // Doublecheck
vl_result := 400; // 400 Bad Request. It is empty.
} else if (lengthof(pl_uri) > 2000) {
vl_result := 414; // Sanity check. Use POST for sending a lot of data.
} else {
if (vl_version == cg_EPTF_DsRestAPI_HTTPServer_HTTP_HTTP10VER or vl_version == cg_EPTF_DsRestAPI_HTTPServer_HTTP_HTTP11VER) {
if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_HEAD
or pl_method == cg_EPTF_DsRestAPI_HTTPServer_GET
or pl_method == cg_EPTF_DsRestAPI_HTTPServer_LSDIR // comment this out to allow listing everywhere
or pl_method == cg_EPTF_DsRestAPI_HTTPServer_MKDIR
or pl_method == cg_EPTF_DsRestAPI_HTTPServer_RMDIR
or pl_method == cg_EPTF_DsRestAPI_HTTPServer_OPTIONS
) {
vl_result := 200;
} else if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_PUT or pl_method == cg_EPTF_DsRestAPI_HTTPServer_POST) { //to allow listing everything: or pl_method == cg_EPTF_DsRestAPI_HTTPServer_LSDIR
if(vl_bodyOffset > 0) {
var integer vl_contentLength := -1;
var integer vl_contentLengthOffset := f_strstr_oct(pl_msg, cg_EPTF_DsRestAPI_HTTPServer_HTTP_ContentLength_Name_oct);
if (vl_contentLengthOffset != -1) {
vl_contentLengthOffset := vl_contentLengthOffset + lengthof(cg_EPTF_DsRestAPI_HTTPServer_HTTP_ContentLength_Name) + 2;
vl_contentLength := str2int(oct2char(f_EPTF_DsRestAPI_HTTPServer_getToken(pl_msg, vl_contentLengthOffset, cg_EPTF_DsRestAPI_HTTPServer_HTTP_CRLF_oct)));
}
pl_body := substr(pl_msg, vl_bodyOffset + 4, lengthof(pl_msg) - vl_bodyOffset - 4);
if (lengthof(pl_body) != vl_contentLength) {
vl_result := -1; // It is the first chunk. Wait for the rest.
} else {
vl_result := 200;
}
}
} else {
f_EPTF_Common_user("HTTP Request contains unknown or not implemented method: '" & pl_method & "'; Offender: " & pl_remoteHost);
vl_result := 501; // Unknown or not implemented method. Maybe a typo. Method is case sensitive!
}
} else {
f_EPTF_Common_user("HTTP Request contains unknown HTTP version: '" & vl_version & "'; Offender: " & pl_remoteHost);
vl_result := 400; // Bad Request, as we do support http 1.0 and 1.1. Protocol is case sensitive!
}
}
} else { // Nonparseable request, maybe a chunk, let it be buffered.
vl_result := -1;
}
return vl_result;
}
// f_EPTF_DsRestAPI_HTTPServer_readFile: returns true if succeeded
private function f_EPTF_DsRestAPI_HTTPServer_readFile(in charstring pl_fileName, out octetstring pl_result) return boolean {
var integer vl_retval:=-1;
pl_result := ''O;
if(pl_fileName != "") {
var integer vl_file := f_FIO_open_rdonly(pl_fileName);
if(vl_file!=-1) {
var integer vl_from:=f_FIO_seek_home(vl_file);
var integer vl_to:=f_FIO_seek_end(vl_file);
if(vl_to>vl_from and f_FIO_seek_home(vl_file)!=-1) {
vl_retval := f_FIO_read_data(vl_file, pl_result, vl_to-vl_from);
}
vl_retval := f_FIO_close(vl_file);
}
}
return (vl_retval != -1);
}
// f_EPTF_DsRestAPI_HTTPServer_saveFile: returns true if succeeded
private function f_EPTF_DsRestAPI_HTTPServer_saveFile(in charstring pl_fileName, in octetstring pl_data) return boolean {
// TODO check if dir is outside the Setups dir ?(we might want to edit the config file)
var integer vl_retval:=-1;
if(pl_fileName != "") {
var integer vl_file := f_FIO_open_trunc_wronly(pl_fileName);
if(vl_file!=-1) {
vl_retval := f_FIO_write_data(vl_file, pl_data);
if (vl_retval != -1) {
vl_retval := f_FIO_close(vl_file);
}
}
}
return (vl_retval != -1);
}
private function f_EPTF_DsRestAPI_HTTPServer_directory() runs on EPTF_DsRestAPI_HTTPServer_CT return charstring {
var charstring vl_result := ".";
if(lengthof(v_EPTF_DsRestAPI_HTTPServer_directory) > 0) {
if(substr(v_EPTF_DsRestAPI_HTTPServer_directory, lengthof(v_EPTF_DsRestAPI_HTTPServer_directory)-1 ,1) == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
v_EPTF_DsRestAPI_HTTPServer_directory := substr(v_EPTF_DsRestAPI_HTTPServer_directory, 0, lengthof(v_EPTF_DsRestAPI_HTTPServer_directory)-1);
}
if (f_FIO_fileOrDirExists(v_EPTF_DsRestAPI_HTTPServer_directory & cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash)) {
vl_result := v_EPTF_DsRestAPI_HTTPServer_directory;
}
}
return vl_result;
}
private external function ef_EPTF_DsRestAPI_HTTPServer_FIO_listDir(in charstring pl_dirName) return EPTF_CharstringList;
type record EPTF_DsRestAPI_CharstringListWrapper {
EPTF_CharstringList contentList
} with { variant(contentList) "JSON: name as contentList"; }
external function ef_EPTF_CharstringList_enc_JSON(in EPTF_DsRestAPI_CharstringListWrapper pl_par) return octetstring with { extension "prototype(convert) encode(JSON) errorbehavior(ALL:WARNING)" }
private external function ef_EPTF_DsRestAPI_HTTPServer_FIO_listDirWithStat(in charstring pl_dirName) return EPTF_DsRestAPI_HTTPServer_FileInfoList;
private function f_EPTF_DsRestAPI_HTTPServer_listDirectory(in charstring pl_dirName) runs on EPTF_DsRestAPI_HTTPServer_CT return octetstring {
var charstring vl_dirName := pl_dirName;
var EPTF_DsRestAPI_HTTPServer_FileInfoList vl_dirContent := {};
var octetstring vl_result := cg_EPTF_DsRestAPI_HTTPServer_HTTP_Dot_oct;
// insert "/" at the end if it is not there:
if (lengthof(vl_dirName) > 0 and vl_dirName[lengthof(vl_dirName)-1] != cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
vl_dirName := vl_dirName & cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash;
}
// truncate the first "/":
if (lengthof(vl_dirName) > 1 and vl_dirName[0] == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
vl_dirName := substr(vl_dirName, 1, lengthof(vl_dirName)-1);
}
if(lengthof(v_EPTF_DsRestAPI_HTTPServer_directory) > 0) {
if(substr(v_EPTF_DsRestAPI_HTTPServer_directory, lengthof(v_EPTF_DsRestAPI_HTTPServer_directory)-1 ,1) == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
vl_dirName := v_EPTF_DsRestAPI_HTTPServer_directory & vl_dirName;
} else {
vl_dirName := v_EPTF_DsRestAPI_HTTPServer_directory & cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash & vl_dirName;
}
} else {
vl_dirName := cg_EPTF_DsRestAPI_HTTPServer_HTTP_Dot & cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash & vl_dirName;
}
vl_dirContent := ef_EPTF_DsRestAPI_HTTPServer_FIO_listDirWithStat(vl_dirName);
// cut server dir from the beginning:
var integer vl_serverDirLength := lengthof(v_EPTF_DsRestAPI_HTTPServer_directory);
for(var integer vl_i:=0; vl_i<sizeof(vl_dirContent); vl_i:=vl_i+1) {
vl_dirContent[vl_i].fileName := substr(vl_dirContent[vl_i].fileName, vl_serverDirLength, lengthof(vl_dirContent[vl_i].fileName)-vl_serverDirLength);
if (lengthof(vl_dirContent[vl_i].fileName) > 1 and vl_dirContent[vl_i].fileName[0] == "/") {
vl_dirContent[vl_i].fileName := substr(vl_dirContent[vl_i].fileName, 1, lengthof(vl_dirContent[vl_i].fileName) - 1);
}
}
vl_result := ef_DsRestAPI_enc_FileInfoList({fileList := vl_dirContent});
return vl_result;
}
private function f_EPTF_DsRestAPI_HTTPServer_createDirectory(in charstring pl_dirName) runs on EPTF_DsRestAPI_HTTPServer_CT return boolean {
// TODO check if dir is outside the Setups dir
var charstring vl_dirName;
if (pl_dirName[lengthof(pl_dirName) - 1] == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
vl_dirName := substr(pl_dirName, 0, lengthof(pl_dirName) - 1);
} else {
vl_dirName := pl_dirName;
}
return f_FIO_mkdir(vl_dirName);
}
private function f_EPTF_DsRestAPI_HTTPServer_deleteDirectory(in charstring pl_dirName) runs on EPTF_DsRestAPI_HTTPServer_CT return boolean {
// TODO check if dir is outside the Setups dir
var charstring vl_dirName;
if (pl_dirName[lengthof(pl_dirName) - 1] == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
vl_dirName := substr(pl_dirName, 0, lengthof(pl_dirName) - 1);
} else {
vl_dirName := pl_dirName;
}
return ef_EPTF_DsRestAPI_FIO_deleteResource(vl_dirName) == 0;
}
private function f_EPTF_DsRestAPI_HTTPServer_handleFileRequest(in charstring pl_uri, in charstring pl_method, in charstring pl_extension, out charstring pl_contentType, in octetstring pl_body, out charstring pl_code, out charstring pl_msg) runs on EPTF_DsRestAPI_HTTPServer_CT return octetstring {
var octetstring vl_fileContent;
var charstring vl_responseText := "";
pl_contentType := "text/html";
pl_code := "200";
pl_msg := "OK";
if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_GET) {
if (pl_uri == cg_EPTF_DsRestAPI_HTTPServer_HTTP_Slash) {
pl_uri := v_EPTF_DsRestAPI_HTTPServer_mainHtml;
pl_extension := "html";
}
var boolean vl_fileExists := f_EPTF_DsRestAPI_HTTPServer_readFile(v_EPTF_DsRestAPI_HTTPServer_path & pl_uri, vl_fileContent);
if (not vl_fileExists) {
vl_fileExists := f_EPTF_DsRestAPI_HTTPServer_readFile(pl_uri, vl_fileContent);
}
if (vl_fileExists) {
if (pl_extension == "html") {
pl_contentType := "text/html; charset=UTF-8";
} else if (pl_extension == "css") {
pl_contentType := "text/css";
} else if (pl_extension == "js") {
pl_contentType := "text/javascript";
} else if (pl_extension == "json") {
pl_contentType := "application/json";
} else if ((pl_extension == "jpg") or
(pl_extension == "jpeg")) {
pl_contentType := "image/jpeg";
} else if (pl_extension == "ico") {
pl_contentType := "image/x-icon";
} else if ((pl_extension == "gif") or
(pl_extension == "bmp") or
(pl_extension == "png")) {
pl_contentType := "image/" & pl_extension;
}
} else {
vl_responseText := "Unhandled request: '" & pl_uri & "' in directory: '" & v_EPTF_DsRestAPI_HTTPServer_path & "'";
pl_code := "404";
pl_msg := "Not Found";
pl_contentType := "text/plain";
}
} else if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_PUT) {
if (f_EPTF_DsRestAPI_HTTPServer_saveFile(v_EPTF_DsRestAPI_HTTPServer_path & pl_uri, pl_body)) {
vl_responseText := "File saved";
} else {
vl_responseText := "File not saved";
pl_code := "500";
pl_msg := "Internal Server Error";
}
} else if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_LSDIR) {
vl_fileContent := f_EPTF_DsRestAPI_HTTPServer_listDirectory(pl_uri);
//to allow listing everything: vl_fileContent := f_EPTF_DsRestAPI_HTTPServer_listDirectory(oct2char(pl_body));
} else if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_MKDIR) {
if (f_EPTF_DsRestAPI_HTTPServer_createDirectory(v_EPTF_DsRestAPI_HTTPServer_path & pl_uri)) {
vl_responseText := "Directory created";
} else {
vl_responseText := "Error creating directory";
pl_code := "500";
pl_msg := "Internal Server Error";
}
} else if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_RMDIR) {
if (f_EPTF_DsRestAPI_HTTPServer_deleteDirectory(v_EPTF_DsRestAPI_HTTPServer_path & pl_uri)) {
vl_responseText := "Directory deleted";
} else {
vl_responseText := "Error deleting directory";
pl_code := "500";
pl_msg := "Internal Server Error";
}
}
if (lengthof(vl_responseText) > 0) { // Direct textual response was fabricated.
vl_fileContent := char2oct(vl_responseText);
}
if (not isbound(vl_fileContent)) {
vl_fileContent := char2oct("error serving " & pl_uri);
}
return vl_fileContent;
}
private function f_EPTF_DsRestAPI_HTTPServer_handleJSONRequest(in integer pl_connId, in octetstring pl_body) runs on EPTF_DsRestAPI_HTTPServer_CT {
if (f_EPTF_FBQ_getLengthOfBusyChain(v_EPTF_DsRestAPI_Browser_Buffer_FBQ) > v_EPTF_DsRestAPI_Browser_Buffer_maxSize) {
if (v_EPTF_DsRestAPI_Browser_Buffer_dropAll) {
f_EPTF_FBQ_deleteFreeBusyQueue(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
f_EPTF_FBQ_initFreeBusyQueue(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
v_EPTF_DsRestAPI_Browser_Buffer_Messages := {};
} else {
var integer vl_indexToDrop;
if(f_EPTF_FBQ_getBusyTailIdx(vl_indexToDrop, v_EPTF_DsRestAPI_Browser_Buffer_FBQ)) {
f_EPTF_FBQ_moveFromBusyToFreeHead(vl_indexToDrop, v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
}
}
}
var integer vl_nextItem := f_EPTF_FBQ_getOrCreateFreeSlot(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
v_EPTF_DsRestAPI_Browser_Buffer_Messages[vl_nextItem] := {pl_body, pl_connId};
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
}
private function f_EPTF_DsRestAPI_HTTPServer_processMessage(in integer pl_connId, in charstring pl_uri, in charstring pl_method, in charstring pl_extension, in octetstring pl_body) runs on EPTF_DsRestAPI_HTTPServer_CT {
var octetstring vl_resultContent := ''O;
var charstring vl_contentType := "text/plain";
var charstring vl_code := "200";
var charstring vl_msg := "OK";
var charstring vl_actionExt := "dsapi";
if (pl_extension == vl_actionExt) {
f_EPTF_DsRestAPI_HTTPServer_handleJSONRequest(pl_connId, pl_body);
} else {
vl_resultContent := f_EPTF_DsRestAPI_HTTPServer_handleFileRequest(pl_uri, pl_method, pl_extension, vl_contentType, pl_body, vl_code, vl_msg);
if (pl_method == cg_EPTF_DsRestAPI_HTTPServer_HEAD) {
vl_resultContent := ''O;
}
vl_resultContent := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP_oct(vl_resultContent, vl_contentType, vl_msg, vl_code);
var ASP_Send vl_responseMsg := { pl_connId, {tcp := {}}, vl_resultContent };
v_DsRestAPI_HTTPServer_IPL4_PCO_PT.send(vl_responseMsg);
}
}
private function f_EPTF_DsRestAPI_HTTPServer_processHTTPMessage(in integer pl_connId, in octetstring pl_msg, out octetstring pl_parsed, in HostName pl_remoteHost) runs on EPTF_DsRestAPI_HTTPServer_CT return boolean {
var charstring vl_method := "";
var charstring vl_uri := "";
var charstring vl_queryString := "";
var integer vl_bodyLength := 0;
var octetstring vl_body := ''O;
var boolean vl_result := true;
var integer vl_decodingResult := f_EPTF_DsRestAPI_HTTPServer_decodeHTTP(pl_msg, vl_method, vl_uri, vl_bodyLength, vl_body, vl_queryString, pl_remoteHost);
pl_parsed := ''O;
if (vl_decodingResult != -1)
{
if (vl_decodingResult == 0 or vl_decodingResult == 200) {
f_EPTF_DsRestAPI_HTTPServer_processMessage(pl_connId, vl_uri, vl_method, f_EPTF_DsRestAPI_HTTPServer_getExtension(vl_uri), vl_body);
} else if (vl_decodingResult == 501) {
pl_parsed := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP("Unknown HTTP Method\r\n", "text/plain", "Not Implemented", "501");
} else if (vl_decodingResult == 400) {
pl_parsed := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP("Not supported transport type and/or version, or malformed request.\r\n", "text/plain", "Bad Request", "400");
} else if (vl_decodingResult == 414) {
pl_parsed := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP("Request-URI Too Long. Limit: 2000 octets; was: " & int2str(lengthof(vl_uri)) & " octets. Please convert your logic to a POST request.\r\n", "text/plain", "Request-URI Too Long", "414");
} else {
pl_parsed := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP("Cannot process the request.\r\n", "text/plain", "Internal Server Error", "500");
}
} else {
vl_result := false;
}
return vl_result;
}
private altstep as_EPTF_DsRestAPI_HTTPServer_mainHandler () runs on EPTF_DsRestAPI_HTTPServer_CT {
var ASP_RecvFrom vl_ASP_RecvFrom;
var ASP_Event vl_ASP_Event;
[] v_DsRestAPI_HTTPServer_IPL4_PCO_PT.receive(ASP_RecvFrom:?) -> value vl_ASP_RecvFrom {
var integer vl_chunkId := -1;
var octetstring vl_responseStr;
var boolean vl_msgParsed := f_EPTF_DsRestAPI_HTTPServer_processHTTPMessage(vl_ASP_RecvFrom.connId, vl_ASP_RecvFrom.msg, vl_responseStr, vl_ASP_RecvFrom.remName);
if(not vl_msgParsed){
if(f_EPTF_int2int_HashMap_Find(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Hash, vl_ASP_RecvFrom.connId, vl_chunkId)) {
vl_msgParsed := f_EPTF_DsRestAPI_HTTPServer_processHTTPMessage(vl_ASP_RecvFrom.connId, v_EPTF_DsRestAPI_Browser_chunk[vl_chunkId] & vl_ASP_RecvFrom.msg, vl_responseStr, vl_ASP_RecvFrom.remName);
}
}
if(vl_msgParsed) {
if(vl_chunkId!=-1) {
v_EPTF_DsRestAPI_Browser_chunk[vl_chunkId] := ''O;
f_EPTF_FBQ_moveFromBusyToFreeHead(vl_chunkId, v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Queue);
f_EPTF_int2int_HashMap_Erase(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Hash, vl_ASP_RecvFrom.connId);
}
} else {
vl_chunkId := -1;
if(f_EPTF_int2int_HashMap_Find(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Hash, vl_ASP_RecvFrom.connId, vl_chunkId)) {
v_EPTF_DsRestAPI_Browser_chunk[vl_chunkId] := v_EPTF_DsRestAPI_Browser_chunk[vl_chunkId] & vl_ASP_RecvFrom.msg;
} else {
vl_chunkId := f_EPTF_FBQ_getOrCreateFreeSlot(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Queue);
v_EPTF_DsRestAPI_Browser_chunk[vl_chunkId] := vl_ASP_RecvFrom.msg;
f_EPTF_FBQ_moveFromFreeHeadToBusyTail(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Queue);
f_EPTF_int2int_HashMap_Insert(v_EPTF_DsRestAPI_Browser_chunk_FromConnId_Hash, vl_ASP_RecvFrom.connId, vl_chunkId);
}
}
repeat;
}
[] v_DsRestAPI_HTTPServer_IPL4_PCO_PT.receive(ASP_Event:?) -> value vl_ASP_Event {
repeat;
}
[] v_DsRestAPI_HTTPServer_IPL4_PCO_PT.receive {
repeat;
}
[] as_EPTF_DsRestAPI_HTTPServer_bufferHandler() {
repeat;
}
}
private altstep as_EPTF_DsRestAPI_HTTPServer_bufferHandler () runs on EPTF_DsRestAPI_HTTPServer_CT {
[f_EPTF_FBQ_getLengthOfBusyChain(v_EPTF_DsRestAPI_Browser_Buffer_FBQ) != 0] t_bufferTimer.timeout {
var integer vl_nextItem;
if (f_EPTF_FBQ_getBusyHeadIdx(vl_nextItem, v_EPTF_DsRestAPI_Browser_Buffer_FBQ)) {
var EPTF_DsRestAPI_HTTPServer_BufferItem vl_bufferedItem := v_EPTF_DsRestAPI_Browser_Buffer_Messages[vl_nextItem];
f_EPTF_FBQ_moveFromBusyToFreeHead(vl_nextItem, v_EPTF_DsRestAPI_Browser_Buffer_FBQ);
var charstring vl_contentType := "application/json";
var octetstring vl_resultContent := f_EPTF_DsRestAPI_DSServer_processJSONRequest(vl_bufferedItem.request);
vl_resultContent := f_EPTF_DsRestAPI_HTTPServer_encodeHTTP_oct(vl_resultContent, vl_contentType, "OK", "200");
var ASP_Send vl_responseMsg := { vl_bufferedItem.connId, {tcp := {}}, vl_resultContent };
v_DsRestAPI_HTTPServer_IPL4_PCO_PT.send(vl_responseMsg);
}
t_bufferTimer.start;
repeat;
}
}
} // ~ group PrivateFunctions
} // ~ module EPTF_CLL_DsRestAPI_HTTPServer_Functions