;******************************** ;* ;* lweb.pbi ;* ;* LiHaSo Webserver Main module. ;* ;* It is usable as standalone Webserver, look at lwebd.pb ;* XIncludeFile "lhs_lib/NET/lhs_net_tls.pbi" XIncludeFile "lhs_lib/NET/lhs_net_socket.pbi" XIncludeFile "inc/lweb_http_post_decoder.pbi" Module lhs_web ;******************************** ;* ;* WebServer Variabeln / Parameter ;* ;{ ;* ;* Configuration Structures ;* ;{ XIncludeFile "inc/lweb_header_privat.pbi" ;} ;* ;* ;* Identifikation des Servers. ;* Global configuration.server configuration\version = "V0.9" configuration\identifikation = "LiHaSo Webserver " + configuration\version configuration\config_file("status_xml")\name = "cfg/default_http_status_codes.xml" configuration\config_file("status_xml")\type = "file" configuration\config_file("hosts_dir")\name = "cfg/server/" configuration\config_file("hosts_dir")\type = "dir" ;* ;* Diese Parameter müssen entsprechend angepasst sein. ;* Später ausgelagert in ein nicht synchronisiertes lweb-cfg.pbi ;* Folgende Parameter müssen im Hauptprogramm definiert sein. configuration\type = 0 configuration\global_max_cli_memory = 0 ; Unlimited configuration\global_max_cli_threads = 0 ; Unlimited Enumeration s_client_do ;client_do_cli #CLI_DO_NOP ;Keine Arbeit #CLI_DO_DataWorking ;Datenverarbeitung #CLI_DO_DataToSend ;Daten zum Senden vorhanden #CLI_DO_WaitDataReceive ;Wartet auf Datenempfang #CLI_DO_WaitDataSend ;Wartet auf gesendete Daten EndEnumeration Enumeration s_server_do ;client_do_srv #SRV_DO_NOP ;Keine Arbeit #SRV_DO_NewDatainBuffer ;Neue Daten im incoming Buffer zur bearbeitung. #SRV_DO_MoreDatainBuffer ;Weitere Daten im incoming Buffer #SRV_DO_DataReceive ;Datem Empfangen Client Thread muss sich darum Kümmern #SRV_DO_DataReceiveCompleted ;Empfang der Daten Abgeschlossen #SRV_DO_DataReceiveFailes ;Beim Empfangen der Daten ist ein fehler passiert. #SRV_DO_DataSendOK ;Daten erfolgreich gesendet, Thread kann weiterarbeiten. #SRV_DO_DataSendNOK ;Daten nicht erfolgreich gesendet. #SRV_DO_ClientDisconnect ;Beenden des Threads Client hat verbindung getrennt. EndEnumeration Enumeration e_type_client 1 #client_HTTP #client_HTTPS EndEnumeration #client_add = 1 #client_remove = -1 #http_method_get = "GET" #http_method_post = "POST" #http_method_put = "PUT" #http_method_connect = "CONNECT" #http_method_delete = "DELETE" #http_method_options = "OPTIONS" #http_method_trace = "TRACE" #http_method_patch = "PATCH" ;*********************** ;* s_lweb_client Struktur Jeder Clientthread muss in die Liste eingetragen werden.: ;* ;* client_id = Client ID von EventClient() ;* client_mutex = Client Thread Blockierer für den Hauptthread um gefahrenlos Daten in den Buffer Speichern zu können. (Vorsichtshalber drinn) ;* client_datenbuffer = 128KByte Speicherblock in diesen Speicher Schreibt nur der Hauptthread. ;* client_output_datenbuffer = 128KByte Speicherblock in diesen Speicher Schreibt nur der Clientthread. ;* client_datenbuffer = 128KByte Speicherblock für die Module achtung dieser Speicherblock wird unter umständen von den Modulen ;* vergrössert wird nach abgeschlossener Arbeit wieder auf Default gesetzt. ;* Structure s_client_memory *Buffer Initialized.b Size.i EndStructure Structure s_file_cache *Buffer Size.i Timer.i Is.i EndStructure Structure PORT_used UUID.s EndStructure Structure IP_used Map PortS.PORT_used() EndStructure Structure s_clients client_id.i client_do_cli.i client_do_srv.i client_type.i ;What type of Client. client_mutex.i client_thread.i List datenbuffer.s_client_memory() client_test_cli.i client_test_srv.i client_cctx.i server_uuid.s ;On which Server it is received. host_id.s client_timeout.i ;Individual timeout per Server to cleanup Client connections EndStructure Structure s_request_handler call.i type.i routetype.i host.s route.s library.s perm.i EndStructure Structure s_server_runs server_connection_id.i UUID.s configuration_map_id.s EndStructure Enumeration cli_handler_infos 1 #get_handler_procedure ;Funktion die Aufgerufen werden muss #get_handler_prototype ;Welcher Prototype #get_handler_library ;Library to open #get_handler_library_perm ;Library permanent in memory? EndEnumeration Global.i count_HTTP_client Global.i count_HTTPS_client Global.i server_HTTP_id Global.i server_HTTPS_id Global.i server_mutex = CreateMutex() ;Dieser Mutex dient zu der Sicherheit der Element Liste. Global.i server_start_semaphore = CreateSemaphore() Global.i count_HTTP_mutex = CreateMutex() Global.i count_HTTPS_mutex = CreateMutex() Global.i file_cache_mutex = CreateMutex() Global.i file_cache_semaphore = CreateSemaphore() Global.i file_cache_semaphore_thread = CreateSemaphore() Global NewMap m_file_cache_map.i() Global NewMap m_file_cache.s_file_cache() Global NewMap m_clients.s_clients() Global NewMap m_request.s_request_handler() Global NewMap server_used.IP_used() Global NewMap m_server_running.s_server_runs() ;} ;******************************** ;* ;* Handler Prototypen ;* PrototypeC WebHandler_Get(handler_Map_JSON.s) PrototypeC WebHandler_Post(handler_Map_JSON.s, ContentString.s) PrototypeC WebHandler_Universal(handler_Map_JSON.s, ContentString.s) PrototypeC.s WebHandler_i_Get(handler_Map_JSON.s) PrototypeC.s WebHandler_i_Post(handler_Map_JSON.s, ContentString.s) PrototypeC.s WebHandler_i_Universal(handler_Map_JSON.s, ContentString.s) PrototypeC WebSocket_Handler_String(handler_Map_JSON.s, Back_Semaphore.i) ;******************************** ;* ;* Used Librarys ;* XIncludeFile "inc/lweb_http_header.pbi" ;XIncludeFile "inc/lweb_file_cache_header.pbi" XIncludeFile "inc/lweb_config_header.pbi" ;******************************** ;* ;* Proceduren Deklarierung ;* Declare server_HTTP(network_server_id.i) Declare server_HTTPS(network_server_id.i) Declare client(network_client_id.i) Declare.s file_check(thread_requested.s, hostid.s) Declare.s call_request_string(RequestString.s, Info.i=#get_handler_procedure) Declare call_request(RequestString.s, Info.i=#get_handler_procedure) Declare.s call_function(ToCallType.i, ToCall.i, Map Header.s(), PostMapString.s ="") Declare advanced_register_handler(RequesterString.s, Permament.i = 0, Library.s = "", Host.s = "") ;Declare.s Work_Post_ToJSON_multipart_form_data(ContentLength.i, MemorSize.i, Memory.i) ;Declare.s Work_Post_ToJSON_x_www_form_urlencoded(ContentLength.i, MemorSize.i, Memory.i) Declare count_client(Type.i, Countchange.i) XIncludeFile "inc/lweb_IP.pbi" XIncludeFile "inc/lweb_http.pbi" XIncludeFile "inc/lweb_helper.pbi" ;XIncludeFile "inc/lweb_file_cache.pbi" Currently in dev. XIncludeFile "inc/lweb_config.pbi" IncludeFile "lhs_lib/SYS/lhs_uuid.pbi" ;It is needed as local function. XIncludeFile "inc/lweb_server_cfg.pbi" ;XIncludeFile "inc/lweb_dynamic.pbi" Procedure server_reload(UUID.s) ProcedureReturn #True EndProcedure IncludeFile "inc/lweb_http_status.pbi" Procedure.s http_server_prepare(http_port.i = 8080, http_binding.s = "127.0.0.1", https_port.i=8443, https_binding.s="127.0.0.1", https_enabled.b = #False) ;CreateUUID Protected UUID.s UUID = CreateUUID() configuration\hosts(UUID)\defaultfile = "index.html" configuration\hosts(UUID)\basedir = "/srv/lweb-srv/" configuration\hosts(UUID)\http\max_clients = 10 ; Max sametime HTTP connections. configuration\hosts(UUID)\http\port = 8080 configuration\hosts(UUID)\http\binding = "127.0.0.1" configuration\hosts(UUID)\https\max_clients = 100 configuration\hosts(UUID)\https\port = 8443 configuration\hosts(UUID)\https\binding = "127.0.0.1" configuration\hosts(UUID)\https\enabled = 0 configuration\hosts(UUID)\https\CA = "" configuration\hosts(UUID)\https\Certs = "" configuration\hosts(UUID)\https\key = "" configuration\hosts(UUID)\https\key_pass = "" configuration\hosts(UUID)\cache\enable = 0 ; Enable / Disable Cached Server configuration\hosts(UUID)\cache\time = 120 ; TTL of cached files configuration\hosts(UUID)\cache\maxsize = 1 ; Max Cache configuration\hosts(UUID)\cache\current = 0 ; configuration\hosts(UUID)\mem\MaxFileSize = 524288 ; Default 512 KiB configuration\hosts(UUID)\mem\DefaultBlockSize = 65536 ; Default Blocksize 64 KiB ProcedureReturn UUID EndProcedure Procedure main_server(id.i) ldl::Logging("main Server Loading") status_defaults() EndProcedure Procedure server_start() Protected server_id_HTTP Protected server_id_HTTPS Protected server_UUID_HTTP.s Protected server_UUID_HTTPS.s Protected counter.i, id.i Global NewMap m_clients.s_clients(configuration\global_max_cli_threads) ;configuration\http\max_clients+configuration\https\max_clients Protected tlsresponse.i Protected current_lib.i Protected current_lib_function.i, current_lib_perm.i Protected current_lib_close.i Protected current_register_type.i Protected current_register_react.s Protected current_register_proto.i ;Initialize all Servers in configuration\hosts() ResetMap(configuration\hosts()) While NextMapElement(configuration\hosts()) server_id_HTTP = lsocket::CreateSocket(configuration\hosts()\http\port, configuration\hosts()\http\max_clients, lsocket::#SOCK_STREAM, lsocket::#AF_INET, configuration\hosts()\http\binding) If server_id_HTTP ;Check for HTTPS If configuration\hosts()\https\enabled = 1 server_id_HTTPS = lsocket::CreateSocket(configuration\hosts()\https\port, configuration\hosts()\https\max_clients, lsocket::#SOCK_STREAM, lsocket::#AF_INET, configuration\hosts()\https\binding) If server_id_HTTPS ;Now Create TLS Socket tlsresponse = tls::InitSimpleTLS(configuration\hosts()\https\CA,configuration\hosts()\https\Certs, configuration\hosts()\https\key, configuration\hosts()\https\key_pass) If tlsresponse > 0 m_server_running(Str(server_id_HTTPS))\configuration_map_id = MapKey(configuration\hosts()) configuration\hosts()\https\thread_id = CreateThread(@server_HTTPS(), server_id_HTTPS) counter + 1 Else ldl::Logging("HTTPS Socket configuration failed with error:"+Str(tlsresponse)) End EndIf Else ldl::Logging("HTTPS Socket ["+configuration\hosts()\https\port+"] could Not opened.") End EndIf EndIf ;HTTP server start m_server_running(Str(server_id_HTTP))\configuration_map_id = MapKey(configuration\hosts()) configuration\hosts()\http\thread_id = CreateThread(@server_HTTP(), server_id_HTTP) counter + 1 configuration\hosts()\log\AccesslogUUID = lhs_log_ext::Create("Accesslog "+configuration\hosts()\description) configuration\hosts()\log\ErrorlogUUID = lhs_log_ext::Create("Errorlog "+configuration\hosts()\description) lhs_log_ext::SetLogFile(configuration\hosts()\log\AccesslogUUID, configuration\hosts()\log\AccesslogFile) lhs_log_ext::SetLogFile(configuration\hosts()\log\ErrorlogUUID, configuration\hosts()\log\ErrorlogFile) lhs_log_ext::Init(configuration\hosts()\log\AccesslogUUID) lhs_log_ext::Init(configuration\hosts()\log\ErrorlogUUID) ldl::Register(lhs_log_ext::@Out(), configuration\hosts()\log\AccesslogUUID, 0,configuration\hosts()\log\AccesslogUUID ,ldl::#AdvancedLog) ldl::Register(lhs_log_ext::@Out(), configuration\hosts()\log\ErrorlogUUID, 0,configuration\hosts()\log\ErrorlogUUID ,ldl::#AdvancedLog) ldl::Logging("Accesslog UUID:"+configuration\hosts()\log\AccesslogUUID) ldl::Logging("Errorlog UUID:"+configuration\hosts()\log\ErrorlogUUID) ;Register Handlers ResetMap(configuration\hosts()\dynamichandler()) While NextMapElement(configuration\hosts()\dynamichandler()) ldl::Logging("Register Handler:"+MapKey(configuration\hosts()\dynamichandler())) ldl::Logging("Parameters library:"+configuration\hosts()\dynamichandler()\file+" Type:"+configuration\hosts()\dynamichandler()\functiontype+" uri:"+configuration\hosts()\dynamichandler()\url+" extension:"+configuration\hosts()\dynamichandler()\extension) If FindMapElement(configuration\hosts()\usedlibs(), configuration\hosts()\dynamichandler()\file) current_lib = configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\lib_id Else current_lib = OpenLibrary(#PB_Any, configuration\hosts()\dynamichandler()\file) EndIf If current_lib current_lib_function = GetFunction(current_lib, configuration\hosts()\dynamichandler()\proc) If current_lib_function ldl::Logging("Function "+configuration\hosts()\dynamichandler()\proc+" found") If FindMapElement(configuration\hosts()\usedlibs(), configuration\hosts()\dynamichandler()\file) If configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\permlib = "false" And configuration\hosts()\dynamichandler()\permlib = "false" current_lib_close = 1 current_lib_perm = 0 ElseIf configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\permlib = "false" And configuration\hosts()\dynamichandler()\permlib = "true" configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\permlib = configuration\hosts()\dynamichandler()\permlib configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\lib_id = current_lib current_lib_close = 0 current_lib_perm = 1 EndIf Else configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\permlib = configuration\hosts()\dynamichandler()\permlib If configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\permlib = "false" current_lib_close = 1 current_lib_perm = 0 Else configuration\hosts()\usedlibs(configuration\hosts()\dynamichandler()\file)\lib_id = current_lib current_lib_close = 0 current_lib_perm = 1 EndIf EndIf ;Now register the function Select configuration\hosts()\dynamichandler()\routetype Case "handler_only" current_register_type = #handler_only current_register_react = configuration\hosts()\dynamichandler()\url Case "handler_sub" current_register_type = #handler_sub current_register_react = configuration\hosts()\dynamichandler()\url Case "handler_type" current_register_type = #handler_type current_register_react = configuration\hosts()\dynamichandler()\extension EndSelect Select configuration\hosts()\dynamichandler()\functiontype Case "GET" current_register_proto = #handler_proto_get Case "POST" current_register_proto = #handler_proto_post Case "Universal" current_register_proto = #handler_proto_universal Case "GET_int" current_register_proto = #handler_proto_i_get Case "POST_int" current_register_proto = #handler_proto_i_post Case "Universal_int" current_register_proto = #handler_proto_i_universal EndSelect ldl::Logging("react:"+current_register_react+" file:"+configuration\hosts()\dynamichandler()\file+" Host ID:"+MapKey(configuration\hosts())) If FindString(configuration\hosts()\dynamichandler()\functiontype, "_int") register_client_handler(current_register_react, current_lib_function, current_register_proto, current_register_type, MapKey(configuration\hosts())) Else register_client_handler(current_register_react, current_lib_function, current_register_proto, current_register_type, MapKey(configuration\hosts())) advanced_register_handler(current_register_react, current_lib_perm, configuration\hosts()\dynamichandler()\file, MapKey(configuration\hosts())) EndIf If current_lib_close = 1 CloseLibrary(current_lib) EndIf current_lib_close = 0 Else ldl::Logging("Error: Function "+configuration\hosts()\dynamichandler()\proc+" not found") If configuration\hosts()\dynamichandler()\permlib = "false" CloseLibrary(current_lib) EndIf EndIf Else ldl::Logging("Error: Library "+configuration\hosts()\dynamichandler()\file+" could not be opened") EndIf Wend Else ldl::Logging("HTTP Socket ["+configuration\hosts()\http\port+"] could Not be opened.") End EndIf Wend ;Initalize Loggers: For id = 1 To counter SignalSemaphore(server_start_semaphore) Next ProcedureReturn #True EndProcedure Procedure server_stop(UUID.s = "all") ;Current easy kill HTTP and HTTPS thread. ;Must be changed if Caching is active ! ; If configuration\https\enabled = 1 And configuration\https\thread_id <> 0 ; KillThread(configuration\https\thread_id) ; EndIf ; If configuration\http\thread_id <> 0 ; KillThread(configuration\http\thread_id) ; EndIf EndProcedure Procedure server_HTTPS(network_server_id.i) ;************************** ;* ;* Main thread for HTTPS networksocket management. Create the Client Threads. ;* Protected.i client_id Protected.i server_host.s = m_server_running(Str(network_server_id))\configuration_map_id thread_alive = #True WaitSemaphore(server_start_semaphore) ldl::Logging("HTTPS Server Started.") Repeat client_id = tls::WaitTLSSocket(network_server_id) ldl::Logging("New HTTPS Client:"+Str(client_id)) If client_id > 0 If m_clients(Str(client_id))\client_id = client_id ldl::Logging("Client Thread for socket already exist :"+Str(client_id)) Else If count_HTTPS_client < 128 m_clients(Str(client_id))\client_id = client_id m_clients(Str(client_id))\client_do_cli = #CLI_DO_WaitDataReceive m_clients(Str(client_id))\client_do_srv = #SRV_DO_DataReceive m_clients(Str(client_id))\client_type = #client_HTTPS m_clients(Str(client_id))\host_id = server_host ;Thread erstellen m_clients(Str(client_id))\client_thread = CreateThread(@client(), client_id) count_client(#client_HTTPS, #client_add) Else ldl::Logging("Max HTTPS Clients reached...") tls::CloseTLSSocket(client_id) EndIf EndIf Else Break EndIf ForEver tls::CloseTLS(network_server_id) EndProcedure Procedure server_HTTP(network_server_id.i) ;************************** ;* ;* Main thread for HTTP networksocket management. Create the Client Threads. ;* Protected.i client_id Protected.i server_host.s = m_server_running(Str(network_server_id))\configuration_map_id thread_alive = #True WaitSemaphore(server_start_semaphore) ldl::Logging("HTTP Server Started.") Repeat client_id = lsocket::WaitSocket(network_server_id) ldl::Logging("New HTTP Client:"+Str(client_id)) If client_id > 0 If m_clients(Str(client_id))\client_id = client_id ldl::Logging("Client Thread for socket already exist :"+Str(client_id)) Else If count_HTTP_client < 128 m_clients(Str(client_id))\client_id = client_id m_clients(Str(client_id))\client_do_cli = #CLI_DO_WaitDataReceive m_clients(Str(client_id))\client_do_srv = #SRV_DO_DataReceive m_clients(Str(client_id))\client_type = #client_HTTP m_clients(Str(client_id))\host_id = server_host ;Thread erstellen m_clients(Str(client_id))\client_thread = CreateThread(@client(), client_id) count_client(#client_HTTP, #client_add) Else ldl::Logging("Max HTTP Clients reached...") lsocket::CloseSocket(client_id) EndIf EndIf Else Break EndIf ForEver EndProcedure Procedure server_WebSocket(network_client_id) Protected Quit = 1 Protected.i thread_cli_id = network_client_id Repeat ; Check if we get data from client If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS temp_receivelength = tls::ReadTLSSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) Else temp_receivelength = lsocket::ReadSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) EndIf ; Check if Library has data to send Until Quit = 1 EndProcedure Procedure client(network_client_id.i) Protected thread_cli_id = network_client_id, sent Protected MyThreadJSON, ToCall, ToCallType Protected thread_temp_cache.s, thread_temp_cache_memory, temp_receivelength, thread_temp_decode_memory Protected thread_reasign, thread_oversized_file.b, thread_data_to_read.i, thread_data_readed.i Protected thread_data_size, thread_file_handle, Handle_Response_Address Protected.s thread_requested, thread_type, thread_date, thread_header, thread_work, JSONStringToMap, Handler_Response, response_status, PostMapString Protected thread_buffer, thread_buffer_offset, thread_buffer_length, buffer_sent Protected sent_length, sent_buffer_address, sent_total Protected.b thread_alive = #True, error_message = #False, thread_redirect = #False Protected.s default_file = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\defaultfile Protected.s home_dir = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\basedir Protected.s AccessLog = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\log\AccesslogUUID Protected.s ErrorLog = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\log\ErrorlogUUID Protected.s Host_ID = m_clients(Str(thread_cli_id))\host_id Protected.s Host_call = "SpecServer:["+Host_ID+"]" Protected.s Header_string = "" Protected Library_ID, LibraryToCall.s Define NewMap Header.s() Define NewMap Response.s() Define NewMap Post.s() ldl::Logging("Client Thread Started. ID:" + Str(network_client_id)) Repeat ;Prüfen ob der Thread was zu tun hat. ;{ Main Server Triggered Things Select m_clients(Str(thread_cli_id))\client_do_srv Case #SRV_DO_NOP ;Ressourcen freigeben und Threadzeit reduzieren Delay(1) Case #SRV_DO_DataReceive LastElement(m_clients(Str(thread_cli_id))\datenbuffer()) AddElement(m_clients(Str(thread_cli_id))\datenbuffer()) m_clients(Str(thread_cli_id))\datenbuffer()\Buffer = AllocateMemory(131072) If m_clients(Str(thread_cli_id))\datenbuffer()\Buffer m_clients(Str(thread_cli_id))\datenbuffer()\Initialized = #True Else ldl::Logging("Buffer Initialisierung fehlgeschlagen.") Break EndIf If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS temp_receivelength = tls::ReadTLSSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) Else temp_receivelength = lsocket::ReadSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) EndIf If temp_receivelength = -1 ldl::Logging("Empfangsfehler.") Break ElseIf temp_receivelength = 65536 m_clients(Str(thread_cli_id))\datenbuffer()\Size = temp_receivelength counter_mem_buffers = 2 Repeat AddElement(m_clients(Str(thread_cli_id))\datenbuffer()) m_clients(Str(thread_cli_id))\datenbuffer()\Buffer = AllocateMemory(131072) If m_clients(Str(thread_cli_id))\datenbuffer()\Buffer m_clients(Str(thread_cli_id))\datenbuffer()\Initialized = #True Else ldl::Logging("Buffer Initialisierung fehlgeschlagen.") Break 2 EndIf If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS temp_receivelength = tls::ReadTLSSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) Else temp_receivelength = lsocket::ReadSocket(thread_cli_id, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, 65536) EndIf m_clients(Str(thread_cli_id))\datenbuffer()\Size = temp_receivelength counter_mem_buffers + 1 If temp_receivelength = -1 Break 2 EndIf Until temp_receivelength < 65536 Else m_clients(Str(thread_cli_id))\datenbuffer()\Size = temp_receivelength EndIf ;Alle Daten empfangen. ldl::Logging("Anzahl Buffer:" + Str(ListSize(m_clients(Str(thread_cli_id))\datenbuffer()))) m_clients(Str(thread_cli_id))\client_do_srv = #SRV_DO_NOP m_clients(Str(thread_cli_id))\client_do_cli = #CLI_DO_DataWorking Case #SRV_DO_ClientDisconnect ;Thread beenden ldl::Logging("#SRV_DO_ClientDisconnect") thread_alive = #False ;* Alles IO Default ;Ressourcen freigeben und Threadzeit reduzieren Delay(1) ldl::Logging("--------------------------------------------------------- FAILING ???") EndSelect ;} ;{ Client Side Triggered Things If thread_alive = #True Select m_clients(Str(thread_cli_id))\client_do_cli Case #CLI_DO_DataWorking ;Receive done. ;Do Buffer work ;Change Thread to Work mode. ;{ ldl::Logging("Data received, working...") m_clients(Str(thread_cli_id))\client_do_cli = #CLI_DO_DataWorking ;Work on Answer. ResetList(m_clients(Str(thread_cli_id))\datenbuffer()) ;TODO: Only first Buffer have a Header. While NextElement(m_clients(Str(thread_cli_id))\datenbuffer()) thread_work = PeekS(m_clients(Str(thread_cli_id))\datenbuffer()\Buffer, m_clients(Str(thread_cli_id))\datenbuffer()\Size, #PB_Ascii) ;Move Header to Map ldl::Logging("Preheaderwork:"+ thread_work) JSONStringToMap = Work_Header_to_JSONMap(thread_work) If JSONStringToMap <> #error_string MyThreadJSON = ParseJSON(#PB_Any, JSONStringToMap) If MyThreadJSON ClearMap(Header()) ExtractJSONMap(JSONValue(MyThreadJSON), Header()) FreeJSON(MyThreadJSON) Else ;Should not be a case. Break 2 ; Kill Thread. EndIf Else error_message = #True EndIf ;TODO: Url with GET Parameter (Also by POST/PUT & Co.) ;? Wen da abschneiden ldl::Logging("JSONString:"+ JSONStringToMap) thread_type = "" If AccessLog <> "" If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS ldl::Logging("Connect:"+lsocket::GetSocketIP(tls::GetSocket(thread_cli_id)) + " " + Header(#http_head_method) + " " + Header(#http_head_request), AccessLog) ldl::Logging("Connect:"+lsocket::GetSocketIP(tls::GetSocket(thread_cli_id)) + " " + Header(#http_head_method) + " " + Header(#http_head_request)) Else ldl::Logging("Connect:"+lsocket::GetSocketIP(thread_cli_id) + " " + Header(#http_head_method) + " " + Header(#http_head_request), AccessLog) ldl::Logging("Connect:"+lsocket::GetSocketIP(thread_cli_id) + " " + Header(#http_head_method) + " " + Header(#http_head_request)) EndIf Else ldl::Logging("Empty accesslog:["+AccessLog+"]") EndIf Select Header(#http_head_method) Case #http_method_get ;******************************** ;* ;* Default GET ;* ;{ ldl::Logging(#http_method_get) ;* ;* Detect websocket upgrade request ;* If LCase(Header(lhs_web_helper::#http_head_connection)) = lhs_web_helper::#http_connection_upgrade ;Whe have a Upgrade Request. ;Current Disconnect it with not supported response_status = lhs_web_helper::#http_state_501 thread_type = lhs_web_helper::mimetype("html") thread_temp_cache_memory = AllocateMemory(StringByteLength("Unsuported")) PokeS(thread_temp_cache_memory, "Unsuported") thread_data_size = StringByteLength("Unsuported") If response_status = "" ;Remove if finished... ;detect a route to there. If Left(Header(#http_head_request),2) = "ws" ;Whe have a websocket request. ;Detect if whe have a library who react to there: ToCallType = call_request(Host_call + thread_requested, #get_handler_prototype) If ToCallType = #handler_proto_i_get Or ToCallType = #handler_proto_get ;Call Websocket EndIf EndIf EndIf Else If Header(#http_head_request) = "/" thread_requested = default_file Else thread_requested = Header(#http_head_request) EndIf ldl::Logging("Requested:"+thread_requested) ToCallType = call_request(Host_call + thread_requested, #get_handler_prototype) If ToCallType = #handler_proto_universal Or ToCallType = #handler_proto_get Or ToCallType = #handler_proto_i_universal Or ToCallType = #handler_proto_i_get ToCall = call_request(Host_call + thread_requested) If call_request(Host_call + thread_requested, #get_handler_library_perm) = 0 LibraryToCall = call_request_string(Host_call + thread_requested, #get_handler_library_perm) If Len(LibraryToCall) > 0 Library_ID = OpenLibrary(#PB_Any, LibraryToCall) If Library_ID ldl::Logging("Library is opened:"+LibraryToCall) Else ldl::Logging("Library could not be opened") EndIf EndIf EndIf Else ToCall = 0 EndIf If ToCall = 0 If Right(thread_requested,1) = "/" thread_requested = default_file Else thread_requested = thread_requested EndIf EndIf If ToCall > 0 ;Dann ist eine Funktion hinterlegt und zulässig aufgerufen zu werden. ;{ Dynamischer WebHandler Handler_Response = call_function(ToCallType, ToCall, Header()) If call_request(Host_call + thread_requested, #get_handler_library_perm) = 0 And Library_ID <> 0 CloseLibrary(Library_ID) EndIf ldl::Logging("Main Client Response :"+Handler_Response) MyThreadJSON = ParseJSON(#PB_Any, Handler_Response) If MyThreadJSON ClearMap(Response()) ExtractJSONMap(JSONValue(MyThreadJSON), Response()) FreeJSON(MyThreadJSON) Else ;WTF ??? ldl::Logging("Fehler Absturz") Break 2 ; Thread abschiessen EndIf ldl::Logging("Response Content:"+Response(#cha_R_ResponseContentType)) Select Response(#cha_R_ResponseContentType) Case #response_Memory ldl::Logging("Response Memory") thread_data_size = Val(Response(#cha_R_MemorySize)) thread_temp_cache_memory = Val(Response(#cha_R_MemoryAdress)) thread_type = Response(#cha_R_ResponseType) Case #response_string ldl::Logging("Response String") thread_temp_decode_memory = AllocateMemory(StringByteLength(Response(#cha_R_StringBase64))) thread_data_size = Base64Decoder(Response(#cha_R_StringBase64), thread_temp_decode_memory, StringByteLength(Response(#cha_R_StringBase64))) thread_temp_cache_memory = AllocateMemory(thread_data_size) CopyMemory(thread_temp_decode_memory, thread_temp_cache_memory, thread_data_size) FreeMemory(thread_temp_decode_memory) thread_type = Response(#cha_R_ResponseType) Default ;Solte ja nicht passieren. EndSelect ldl::Logging("Content Finished") ;} ; ElseIf configuration\cache\enable = 1 ; ;{ Cached File Handling BUGGY!!!!!!! ; thread_temp_cache_memory = AllocateMemory(1024) ; thread_temp_cache = GetFileFromCache(thread_requested, thread_temp_cache_memory) ; If thread_temp_cache = #error_string ; thread_file_handle = ReadFile(#PB_Any, configuration\basedir + thread_requested,#PB_File_SharedRead) ; ; If thread_file_handle ; ;Alles Ok ; Else ; thread_file_handle = ReadFile(#PB_Any, configuration\basedir + configuration\defaultfile,#PB_File_SharedRead) ; ldl::Logging("FileDir:" + configuration\basedir + configuration\defaultfile) ; If Not thread_file_handle ; thread_file_handle = ReadFile(#PB_Any, "error.html") ; EndIf ; ; EndIf ; thread_data_size = Lof(thread_file_handle) ; thread_temp_cache_memory = ReAllocateMemory(thread_temp_cache_memory, thread_data_size) ; ReadData(thread_file_handle, thread_temp_cache_memory, thread_data_size) ; CloseFile(thread_file_handle) ; AddFileToCache(thread_temp_cache_memory, thread_requested, thread_data_size) ; ; Else ; thread_data_size = Val(StringField(thread_temp_cache, 1, ":")) ; thread_temp_cache_memory = Val(StringField(thread_temp_cache, 2, ":")) ; EndIf ; ;} Else ;{ Uncached file sems to be stable tested up to 200 clients and 100 requests. If file_check(thread_requested, m_clients(Str(thread_cli_id))\host_id) = thread_requested thread_file_handle = ReadFile(#PB_Any, home_dir + thread_requested,#PB_File_SharedRead) If Not thread_file_handle thread_file_handle = ReadFile(#PB_Any, home_dir + default_file ,#PB_File_SharedRead) ldl::Logging("FileDir:" + home_dir + default_file, ErrorLog) If Not thread_file_handle ldl::Logging("Error file set", ErrorLog) thread_file_handle = ReadFile(#PB_Any, "error.html") EndIf EndIf thread_data_size = Lof(thread_file_handle) ; Is File bigger than MaxFileSize in Memory allowed ? If thread_data_size >= configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\MaxFileSize ;Do Handle the File another way. thread_temp_cache_memory = AllocateMemory(configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\MaxFileSize) thread_temp_file_readed = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\DefaultBlockSize thread_data_readed = ReadData(thread_file_handle, thread_temp_cache_memory, thread_temp_file_readed) thread_data_to_read = thread_data_size - thread_data_readed thread_oversized_file = #True Else thread_temp_cache_memory = AllocateMemory(thread_data_size) ReadData(thread_file_handle, thread_temp_cache_memory, thread_data_size) CloseFile(thread_file_handle) thread_oversized_file = #False EndIf Else thread_redirect = #True EndIf ;} EndIf EndIf ;} Case #http_method_post ;******************************** ;* ;* POST ;* ;* Current Finaly Implementet is only application/x-www-form-urlencoded ;* Error Handling must be Optimized. ;* ldl::Logging(#http_method_post) ;{ POST Content Type Decoder If LCase(Header(#http_head_content_type)) = #http_content_type_application_x_www_form_urlencoded PostMapString = lhs_web_post::mem_x_www_form_urlencoded(Val(Header(#http_head_content_length)), m_clients(Str(thread_cli_id))\datenbuffer()\Size, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer) MyThreadJSON = ParseJSON(#PB_Any, PostMapString) If MyThreadJSON ClearMap(Post()) ExtractJSONMap(JSONValue(MyThreadJSON), Post()) FreeJSON(MyThreadJSON) Else ;Should not be possible. ldl::Logging("Error in thread, JSON Convert didn't Work") Break 2 ; Kill Thread EndIf ElseIf Left(LCase(Header(#http_head_content_type)), Len(#http_content_type_multipart_form_data)) = #http_content_type_multipart_form_data PostMapString = lhs_web_post::mem_x_www_form_urlencoded(Val(Header(#http_head_content_length)), m_clients(Str(thread_cli_id))\datenbuffer()\Size, m_clients(Str(thread_cli_id))\datenbuffer()\Buffer) MyThreadJSON = ParseJSON(#PB_Any, PostMapString) If MyThreadJSON ClearMap(Post()) ExtractJSONMap(JSONValue(MyThreadJSON), Post()) FreeJSON(MyThreadJSON) Else ;Someting wrong in the POST ldl::Logging("Error with Content. JSON Convert didn't Work") Break 2; Kill Thread EndIf EndIf ;} If Header(#http_head_request) = "/" thread_requested = default_file Else thread_requested = Header(#http_head_request) EndIf ldl::Logging("Requested:"+thread_requested) ToCallType = call_request(Host_call+thread_requested, #get_handler_prototype) If ToCallType = #handler_proto_universal Or ToCallType = #handler_proto_post Or ToCallType = #handler_proto_i_universal Or ToCallType = #handler_proto_i_post ToCall = call_request(Host_call + thread_requested) ldl::Logging("A To Call is found:"+Str(ToCall)) If call_request(Host_call + thread_requested, #get_handler_library_perm) = 0 LibraryToCall = call_request_string(Host_call + thread_requested, #get_handler_library) If Len(LibraryToCall) > 0 Library_ID = OpenLibrary(#PB_Any, LibraryToCall) If Library_ID Else ldl::Logging("Library could not be opened") EndIf EndIf EndIf Else ToCall = 0 EndIf If ToCall > 0 ;A dynamic webhandler is available, call. ;{ Dynamic webhandler. Handler_Response = call_function(ToCallType, ToCall, Header(), PostMapString) If call_request(Host_call + thread_requested, #get_handler_library_perm) = 0 And Library_ID <> 0 CloseLibrary(Library_ID) EndIf ldl::Logging("Main Client Response :"+Handler_Response) MyThreadJSON = ParseJSON(#PB_Any, Handler_Response) If MyThreadJSON ClearMap(Response()) ExtractJSONMap(JSONValue(MyThreadJSON), Response()) FreeJSON(MyThreadJSON) Else ;WTF ??? ldl::Logging("Fehler Absturz") Break 2 ; Thread abschiessen EndIf ldl::Logging("Response Content:"+Response(#cha_R_ResponseContentType)) Select Response(#cha_R_ResponseContentType) Case #response_Memory thread_data_size = Val(Response(#cha_R_MemorySize)) thread_temp_cache_memory = Val(Response(#cha_R_MemoryAdress)) thread_type = Response(#cha_R_ResponseType) Case #response_string thread_temp_decode_memory = AllocateMemory(StringByteLength(Response(#cha_R_StringBase64))) thread_data_size = Base64Decoder(Response(#cha_R_StringBase64), thread_temp_decode_memory, StringByteLength(Response(#cha_R_StringBase64))) thread_temp_cache_memory = AllocateMemory(thread_data_size) CopyMemory(thread_temp_decode_memory, thread_temp_cache_memory, thread_data_size) FreeMemory(thread_temp_decode_memory) thread_type = Response(#cha_R_ResponseType) Default ;Solte ja nicht passieren. EndSelect ldl::Logging("Content Finished") ;} ElseIf conf_cache_enable = 1 ; ;{ Cached File Handling BUGGY!!!!!!! ; thread_temp_cache_memory = AllocateMemory(1024) ; thread_temp_cache = GetFileFromCache(thread_requested, thread_temp_cache_memory) ; If thread_temp_cache = #error_string ; thread_file_handle = ReadFile(#PB_Any, "srv/www" + thread_requested,#PB_File_SharedRead) ; ; If thread_file_handle ; ;Alles Ok ; Else ; thread_file_handle = ReadFile(#PB_Any, "srv/www" + "index.html",#PB_File_SharedRead) ; ldl::Logging("FileDir:" + "srv/www" + "index.html") ; If Not thread_file_handle ; thread_file_handle = ReadFile(#PB_Any, "error.html") ; EndIf ; ; EndIf ; thread_data_size = Lof(thread_file_handle) ; thread_temp_cache_memory = ReAllocateMemory(thread_temp_cache_memory, thread_data_size) ; ReadData(thread_file_handle, thread_temp_cache_memory, thread_data_size) ; CloseFile(thread_file_handle) ; AddFileToCache(thread_temp_cache_memory, thread_requested, thread_data_size) ; ; Else ; thread_data_size = Val(StringField(thread_temp_cache, 1, ":")) ; thread_temp_cache_memory = Val(StringField(thread_temp_cache, 2, ":")) ; EndIf ; ;} Else ;{ Uncached file sems to be stable tested up to 200 clients and 100 requests. If file_check(thread_requested, m_clients(Str(thread_cli_id))\host_id) = thread_requested thread_file_handle = ReadFile(#PB_Any, home_dir+ thread_requested,#PB_File_SharedRead) If Not thread_file_handle thread_file_handle = ReadFile(#PB_Any, home_dir + default_file ,#PB_File_SharedRead) ldl::Logging("FileDir:" + home_dir + default_file) If Not thread_file_handle ldl::Logging("Error file set") thread_file_handle = ReadFile(#PB_Any, "error.html") EndIf EndIf thread_data_size = Lof(thread_file_handle) ; Is File bigger than MaxFileSize in Memory allowed ? If thread_data_size >= configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\MaxFileSize ;Do Handle the File another way. thread_temp_cache_memory = AllocateMemory(configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\MaxFileSize) thread_temp_file_readed = configuration\hosts(m_clients(Str(thread_cli_id))\host_id)\mem\DefaultBlockSize thread_data_readed = ReadData(thread_file_handle, thread_temp_cache_memory, thread_temp_file_readed) thread_data_to_read = thread_data_size - thread_data_readed thread_oversized_file = #True Else thread_temp_cache_memory = AllocateMemory(thread_data_size) ReadData(thread_file_handle, thread_temp_cache_memory, thread_data_size) CloseFile(thread_file_handle) thread_oversized_file = 0 EndIf Else ;Send Redirect: thread_redirect = #True EndIf ;} EndIf Default ;************************************ ;* ;* Not a supported Command in HTTP Header Cleanup. ;* ;* Read Buffer to Memory and Clear Buffer to Zero until the complete Networkbuffer from this Client is Cleaned. ;* EndSelect If thread_data_size Or thread_redirect = #True If thread_type = "" thread_type = mimetype(GetExtensionPart(thread_requested)) EndIf thread_date = http_day(DayOfWeek(Date())) + Str(Day(Date())) + http_month(Month(Date())) + Str(Year(Date())) + " " + FormatDate("%hh:%ii:%ss GMT+1", Date()) ClearMap(Header()) If Response(#cha_R_http_head_status) <> "" Header(#http_head_status) = Response(#cha_R_http_head_status) ElseIf response_status <> "" Header(#http_head_status) = response_status Else Header(#http_head_status) = status_get_header("200") EndIf If Response(#http_head_set_cookie) <> "" Header(#http_head_set_cookie) = Response(#http_head_set_cookie) EndIf If thread_redirect = #True Header(#http_head_redirect) = file_check(thread_requested, m_clients(Str(thread_cli_id))\host_id) Header(#http_head_status) = status_get_header("303") Else Header(#http_head_content_length) = Str(thread_data_size) Header(#http_head_content_type) = thread_type EndIf Header(#http_head_connection) = "Keep-Alive" Header(#http_head_keep_alive) = "timeout=15, max=1000" thread_header = http_header_generate(Header()) ldl::Logging("Header:"+thread_header) ;large File Handling If thread_redirect = #True thread_buffer = AllocateMemory(StringByteLength(thread_header)+12) ElseIf thread_oversized_file = #False thread_buffer = AllocateMemory(thread_data_size+StringByteLength(thread_header)+12) Else thread_buffer = AllocateMemory(thread_temp_file_readed+StringByteLength(thread_header)+12) EndIf thread_buffer_offset = thread_buffer thread_buffer_length = PokeS(thread_buffer_offset, thread_header,-1, #PB_UTF8|#PB_String_NoZero) : thread_buffer_offset + thread_buffer_length ldl::Logging("Header Finished") EndIf ;Copy temporary File Buffer to normal Buffer. If thread_temp_cache_memory <> 0 And thread_buffer_offset <> 0 And thread_data_size <> 0 And thread_oversized_file = #False And thread_redirect = #False CopyMemory(thread_temp_cache_memory, thread_buffer_offset, thread_data_size) ldl::Logging("Cache Address Memory:"+Str(thread_temp_cache_memory)) FreeMemory(thread_temp_cache_memory) thread_temp_cache_memory = 0 ElseIf thread_temp_cache_memory <> 0 And thread_buffer_offset <> 0 And thread_data_size <> 0 And thread_temp_file_readed <> 0 And thread_oversized_file = #True And thread_redirect = #False CopyMemory(thread_temp_cache_memory, thread_buffer_offset, thread_temp_file_readed) ldl::Logging("Oversized Cache Address Memory:"+Str(thread_temp_cache_memory)) FreeMemory(thread_temp_cache_memory) thread_temp_cache_memory = 0 ElseIf thread_redirect = #True thread_redirect = #False Else ldl::Logging("File Buffer Troubles.") If thread_temp_cache_memory = 0 : ldl::Logging("thread_temp_cache_memory = 0") : EndIf If thread_buffer_offset = 0 : ldl::Logging("thread_buffer_offset = 0") : EndIf If thread_data_size = 0 : ldl::Logging("thread_data_size = 0") : EndIf thread_alive = #False Break 2 EndIf ; EndIf ldl::Logging("HTTP File Buffer Cleaned.") ;Löschen des eingang Speichers. If m_clients(Str(thread_cli_id))\datenbuffer()\Buffer > 0 FreeMemory(m_clients(Str(thread_cli_id))\datenbuffer()\Buffer) EndIf DeleteElement(m_clients(Str(thread_cli_id))\datenbuffer()) ;Send the data in memory to client. If thread_redirect = #True sent_total = thread_buffer_offset - thread_buffer ElseIf thread_oversized_file = #False sent_total = thread_data_size+(thread_buffer_offset-thread_buffer) Else sent_total = thread_temp_file_readed+(thread_buffer_offset-thread_buffer) EndIf ldl::Logging("Memory send_total:"+Str(sent_total)) ;TODO: Stoped download kill server... If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS sent_length = sent_total sent_buffer_address = thread_buffer sent_total = 0 Repeat sent = tls::WriteTLSSocket(thread_cli_id, sent_buffer_address , sent_length) If sent <> -1 ldl::Logging("ClientID:" + Str(thread_cli_id) + " HTTPS Sent:"+Str(sent)+" bytes") sent_length - sent If thread_oversized_file = #False sent_buffer_address + sent Else ;Read next Block to Memory If sent_length <= 0 And IsFile(thread_file_handle) sent_readed = ReadData(thread_file_handle, thread_buffer, thread_temp_file_readed) ldl::Logging("ClientID:" + Str(thread_cli_id) + " HTTPS Large File -> Read Next:"+Str(sent_readed)+" bytes") If sent_readed < thread_temp_file_readed CloseFile(thread_file_handle) EndIf sent_buffer_address = thread_buffer sent_length = sent_readed Else ldl::Logging("ClientID:" + Str(thread_cli_id) + " HTTPS Large File -> to Send:"+Str(sent_length)+" bytes") sent_buffer_address + sent EndIf EndIf sent_total + sent Else If IsFile(thread_file_handle) CloseFile(thread_file_handle) EndIf ldl::Logging("HTTPS Sent error:"+tls::ErrorTLSCli(thread_cli_id)) thread_alive = #False Break 2 EndIf Until sent_length <= 0 sent = sent_total Else sent_length = sent_total sent_buffer_address = thread_buffer sent_total = 0 Repeat sent = lsocket::WriteSocket(thread_cli_id, thread_buffer , sent_length) If sent <> -1 ldl::Logging("HTTP Sent:"+Str(sent)+" bytes") sent_length - sent If thread_oversized_file = 0 sent_buffer_address + sent Else ;Read next Block to Memory If sent_length <= 0 And IsFile(thread_file_handle) sent_readed = ReadData(thread_file_handle, thread_buffer, thread_temp_file_readed) If sent_readed < thread_temp_file_readed CloseFile(thread_file_handle) EndIf sent_buffer_address = thread_buffer sent_length = sent_readed Else sent_buffer_address + sent EndIf EndIf sent_total + sent Else If IsFile(thread_file_handle) CloseFile(thread_file_handle) EndIf ldl::Logging("HTTP Sent error:"+Str(sent)) thread_alive = #False Break 2 EndIf Until sent_length <= 0 sent = sent_total EndIf If sent = thread_data_size+(thread_buffer_offset-thread_buffer) ;Ok ;ldl::Logging("Gesendet:" + PeekS(thread_buffer,thread_buffer_length, #PB_Ascii)) If thread_buffer > 0 FreeMemory(thread_buffer) EndIf m_clients(Str(thread_cli_id))\client_do_cli = #CLI_DO_WaitDataReceive m_clients(Str(thread_cli_id))\client_do_srv = #SRV_DO_DataReceive Else ;Fehler beim Senden ... Thread beenden. ldl::Logging("Fehler:" + Str(Sent)) thread_alive = #False EndIf ; Wend ;} m_clients(Str(thread_cli_id))\client_do_cli = #CLI_DO_WaitDataReceive EndSelect EndIf ;} Until thread_alive = #False ldl::Logging("Thread should now die...") ResetList(m_clients(Str(thread_cli_id))\datenbuffer()) ldl::Logging("Thread kill all Initialized Memory buffers:") While NextElement(m_clients(Str(thread_cli_id))\datenbuffer()) If m_clients(Str(thread_cli_id))\datenbuffer()\Initialized ldl::Logging("Kill:"+Str(m_clients(Str(thread_cli_id))\datenbuffer()\Buffer)+ " ...") FreeMemory(m_clients(Str(thread_cli_id))\datenbuffer()\Buffer) DeleteElement(m_clients(Str(thread_cli_id))\datenbuffer()) ldl::Logging("Freed and removed") Else ldl::Logging("Remove element from List with uninitialized Memory ID: "+Str(m_clients(Str(thread_cli_id))\datenbuffer()\Buffer)) DeleteElement(m_clients(Str(thread_cli_id))\datenbuffer()) ldl::Logging("Removed") EndIf Wend If m_clients(Str(thread_cli_id))\client_type = #client_HTTPS ldl::Logging("Kill HTTPS Socket:" + Str(thread_cli_id)) ;tls::CloseTLSSocket(thread_cli_id) count_client(#client_HTTPS, #client_remove) ldl::Logging("Killed.") Else ldl::Logging("Kill HTTP Socket:" + Str(thread_cli_id)) lsocket::CloseSocket(thread_cli_id) count_client(#client_HTTP, #client_remove) ldl::Logging("Killed.") EndIf ldl::Logging("Remove Client from map...") DeleteMapElement(m_clients(), Str(thread_cli_id)) ldl::Logging("Removed and thread now died.") EndProcedure Procedure.s call_request_string(RequestString.s, Info.i = #get_handler_procedure) Protected CurrPos, Count, Counter, PartString.s ;"SpecServer:["+Host_ID+"]" Protected.s Host_ID = "" Protected HF_Count, HF_Pos If Left(RequestString,12) = "SpecServer:[" ;Whe have host specific HF_Pos = FindString(RequestString, "]",12) Host_ID = Left(RequestString, HF_Pos) EndIf ldl::Logging("call_request: "+RequestString) If m_request(GetExtensionPart(RequestString))\routetype = #handler_type Select Info Case #get_handler_procedure ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\call) Case #get_handler_prototype ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\type) Case #get_handler_library ProcedureReturn m_request(Host_ID+GetExtensionPart(RequestString))\library Case #get_handler_library_perm ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\perm) Default ProcedureReturn "0" EndSelect EndIf ldl::Logging("call_request: "+RequestString + " Routetype :["+Str(m_request(RequestString)\routetype)+"]") If m_request(RequestString)\routetype = #handler_only Or m_request(RequestString)\routetype = #handler_sub Select Info Case #get_handler_procedure ProcedureReturn Str(m_request(RequestString)\call) Case #get_handler_prototype ProcedureReturn Str(m_request(RequestString)\type) Case #get_handler_library ProcedureReturn m_request(RequestString)\library Case #get_handler_library_perm ProcedureReturn Str(m_request(RequestString)\perm) Default ProcedureReturn "0" EndSelect ElseIf m_request(GetExtensionPart(RequestString))\routetype = #handler_sub Select Info Case #get_handler_procedure ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\call) Case #get_handler_prototype ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\type) Case #get_handler_library ProcedureReturn m_request(Host_ID+GetExtensionPart(RequestString))\library Case #get_handler_library_perm ProcedureReturn Str(m_request(Host_ID+GetExtensionPart(RequestString))\perm) Default ProcedureReturn "0" EndSelect EndIf ldl::Logging("call_request now on sub check: "+RequestString + " Routetype :["+Str(m_request(RequestString)\routetype)+"]") ;Check auf Sub Counter = CountString(RequestString, "/") Count = 0 CurrPos = 0 While Count < Counter CurrPos = FindString(RequestString, "/", 2 + CurrPos ) PartString = Mid(RequestString, 1, CurrPos) If m_request(PartString)\routetype = #handler_sub Select Info Case #get_handler_procedure ProcedureReturn Str(m_request(PartString)\call) Case #get_handler_prototype ProcedureReturn Str(m_request(PartString)\type) Case #get_handler_library ProcedureReturn m_request(PartString)\library Case #get_handler_library_perm ProcedureReturn Str(m_request(PartString)\type) Default ProcedureReturn "0" EndSelect EndIf Count + 1 Wend ldl::Logging("call_request Not found !!!!!!!!! : "+RequestString + "Routetype :["+Str(m_request(RequestString)\routetype)+"]") ProcedureReturn "0" EndProcedure Procedure call_request(RequestString.s, Info.i = #get_handler_procedure) ProcedureReturn Val(call_request_string(RequestString.s, Info.i)) EndProcedure Procedure.s register_client_handler(Route.s, Callback.i, AppPrototype.i = #handler_proto_get, RouteType.i = #handler_sub, Host.s = "") If Len(Host) > 0 Host = "SpecServer:["+Host+"]" EndIf m_request(Host+Route)\type = AppPrototype m_request(Host+Route)\call = Callback m_request(Host+Route)\routetype = RouteType m_request(Host+Route)\route = Route m_request(Host+Route)\host = Host ldl::Logging("Handler Registriert:"+Route+ " at Host:["+Host+"]") EndProcedure Procedure advanced_register_handler(Route.s, Permament.i = 0, Library.s = "", Host.s="") If Len(Host) > 0 Host = "SpecServer:["+Host+"]" EndIf m_request(Host+Route)\perm = Permament m_request(Host+Route)\library = Library EndProcedure Procedure.s call_function(ToCallType.i, ToCall.i, Map Header.s(), PostMapString.s ="") Define.i Handler_Response_Adress Define.s Handler_Response, Header_string Header_string = MapToJSONString(Header()) Select ToCallType Case #handler_proto_universal Define.WebHandler_Universal ToCallProcedure_Universal = ToCall Handler_Response_Adress = ToCallProcedure_Universal(Header_string, PostMapString ) ldl::Logging("Response Address:"+Str(Handler_Response_Adress)) Handler_Response = PeekS(Handler_Response_Adress) Case #handler_proto_get Define.WebHandler_Get ToCallProcedureGet = ToCall Handler_Response_Adress = ToCallProcedureGet(Header_string) Handler_Response = PeekS(Handler_Response_Adress) Case #handler_proto_post Define.WebHandler_Post ToCallProcedure_Post = ToCall Handler_Response_Adress = ToCallProcedure_Post(Header_string, PostMapString) Handler_Response = PeekS(Handler_Response_Adress) Case #handler_proto_i_universal Define.WebHandler_i_Universal ToCallProcedure_i_Universal = ToCall Handler_Response = ToCallProcedure_i_Universal(Header_string, PostMapString ) Case #handler_proto_i_get Define.WebHandler_i_get ToCallProcedure_i_get = ToCall Handler_Response = ToCallProcedure_i_get(Header_string) Case #handler_proto_i_post Define.WebHandler_i_Universal ToCallProcedure_i_post = ToCall Handler_Response = ToCallProcedure_i_post(Header_string, PostMapString ) EndSelect ProcedureReturn Handler_Response EndProcedure Procedure count_client(Type.i, Countchange.i) Select Type Case #client_HTTP LockMutex(count_HTTP_mutex) count_HTTP_client + Countchange UnlockMutex(count_HTTP_mutex) Case #client_HTTPS LockMutex(count_HTTPS_mutex) count_HTTPS_client + Countchange UnlockMutex(count_HTTPS_mutex) EndSelect EndProcedure Procedure.s file_check(thread_requested.s, hostid.s) Protected file_type.i Debug thread_requested file_type = FileSize(configuration\hosts(hostid)\basedir + thread_requested) If file_type = -1 thread_requested = "configuration\errorfile404" ElseIf file_type = -2 ;Is a Directory If Right(thread_requested,1) = "/" thread_requested = thread_requested + "index.html" Else thread_requested = thread_requested + "/" + "index.html" EndIf EndIf Debug "Final:"+thread_requested ProcedureReturn thread_requested.s EndProcedure EndModule