1480 lines
68 KiB
Text
1480 lines
68 KiB
Text
;********************************
|
|
;*
|
|
;* 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
|
|
|
|
Structure s_header_functions
|
|
header_name.s
|
|
call.i
|
|
type.i
|
|
library.s
|
|
perm.i
|
|
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
|
|
|
|
;TODO: Header Handler
|
|
; ex. Cookie: #http_head_cookie
|
|
|
|
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)
|
|
;TODO: Verify it's a file or a configuration ...
|
|
If Header(#http_head_redirect) = "configuration\errorfile404"
|
|
ldl::Logging("Error 404 : ["+configuration\status("404")\content+"]")
|
|
Header(#http_head_redirect) = ""
|
|
EndIf
|
|
|
|
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))
|
|
;Erledigt: 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
|
|
If lsocket::IsClientSocket(thread_cli_id)
|
|
sent = lsocket::WriteSocket(thread_cli_id, thread_buffer , sent_length)
|
|
Else
|
|
thread_alive=#False
|
|
Break 2
|
|
EndIf
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|