WebServer.EXE written by Mike Ghan, Logix Industrial Control Systems. Use WebServer at your own risk. It is provided as is without any warranty or guaranty of any kind. 01/21/2008 Updated to SwiftForth V3.1 11/26/2007 Increased maximum input line length to 1000. 10/04/2007 Added Support (limited) for FPMATH (needs testing - anyone?) 10/04/2007 Added error trapping and logging during inclusion of files from the command line. Previous behavior was crash on error. Log file is named Compile.Log 12/01/2008 Added scripted XML support. See below. 12/06/2008 Updated to Winsock2. Enhanced status display. 12/06/2008 Added Copy Display to clipboard in the View Menu. 12/07/2008 Documented (this file). 12/07/2008 Released Version 1.02 06/30/2009 More descriptive Start error messages 06/30/2009 Released Version 1.03 based on latest SwiftForth. ------------------------------------------------------------------------------ This WebServer is written entirely in SwiftForth and derived from the built-in web server of our industrial automation operator interface we call Clarity. The WebServer will serve up simple HTML pages as well as Forth script files. The zip file contains the WebServer with a few samples. Create a suitable directory and unzip (be sure to retain the relative directory structure in the zip file). All web files must reside in the WEB subdirectory tree of the server executable (assuming WebServer.EXE resides in C:\SERVER\, all web pages would be in C:\SERVER\WEB\). I do test for malformed URLs and buffer overflows so a user *should* *not* be able to access other directories or crash this server. *Please* let me know otherwise. Forth script files have the .FS extension (ex. Primes.FS) but are accessed as .SHTML (Script HTML) files from a client browser (ex. http://www.yada.com/Primes.shtml). When a script file is served up, the Forth script file is interpreted (just as in INCLUDE). It is possible to define Forth definitions and execute them. See Primes.FS for an example. Launch the WebServer and point your browser to http://localhost for a few examples. NOTE! The Forth script engine provides NO safeguards restricting disk access, malicious code etc. WebServer obviously is suitable for deployment in tightly controlled environments only - where a user can not alter the script FS files. The WebServer also has support for the POST method and Cookies. My examples are a bit rough (not realistic and contain much test code): point your browser at FormTest.html, fill in the fields and submit the form. RecvForm.FS will process the POSTed form and write a file named COMMENT.TXT with the contents of the form's Comment field. The First and Last names are concatenated and saved as a cookie named Name. Likewise, the email field is saved as a cookie named Email. Since our test HTML form contains a "success=RecvForm.SHTML" page reference (more typically a simple ThankYou.HTML page). the script RecvForm.FS is then served as a response to the browser. Subsequent browser access to RecvForm.SHTML will display the cookies. ------------------------------------------------------------------------------ Extending WebServer Execution of WebServer.EXE will allow command line parameters just as SwiftForth does. This will allow you to extend the server by including Forth source. This capability was allowed by express permission granted by Forth Incorporated. For example, typing: WebServer INCLUDE CUSTOM.F from the command line would INCLUDE the CUSTOM.F example file and start the server. This is resident code as opposed to any Forth compiled during a script which is transient. There are no restrictions on the content of the startup include file other than all output is redirected to the Compile.Log file and you can not use PROGRAM to save a new executable image. See the example batch file StartServer.Bat Defining Alternate HTTP Port Place the following in the INCLUDEd startup file or simply modify this setting in WebServer's configuration dialog. The setting is stored in the registry. 81 WEB-MASTER TCP-PORT ! \ Set alternate HTTP Port Registry Entries WebServer stores numerous options in the following registry keys: HKEY_CURRENT_USER\Software\Logix\Clarity\Web Server [Web Server] HKEY_LOCAL_MACHINE\SOFTWARE\Logix\Clarity\Web Server [Web Server] Many of the values relate to our Clarity product and have no affect on WebServer. ------------------------------------------------------------------------------ Script File Restrictions Including Files SwiftForth standard words INCLUDE and INCLUDED both add definitions to the FILES-WORDLIST vocabulary for use by the LOCATE facility. Unfortunately, if INCLUDE is used inside a script, each time a script is run SwiftForth will grow in size ultimately leading to an excessively large memory footprint. WebServer has the following words which overcome this obstacle: WEB-INCLUDED ( filename cnt -- ) ex S" FOOBAR.F" WEB-INCLUDED WEB-INCLUDE ( -- ) ex WEB-INCLUDE FOOBAR.F These simply include the referenced file without any entry in the FILES-WORDLIST vocabulary. Note that the startup INCLUDE file, if any, may contain either INCLUDE or WEB-INCLUDE (see Extending WebServer above). Maximum Script Dictionary Space Whenever a script is loaded, memory is allocated to hold the transient definitions and /or data structure. This allows the script to compile Forth code or build data structures. The dictionary is forgotten (simple) at the end and the memory space FREEed. Important: Do *NOT* chain or vector into lower structures such as with [+SWITCH, GILD, EMPTY or IS etc. The temporary dictionary size is determined by the VALUE /SCRIPT-DICT which by default is 50,000 bytes. This can be altered when WebServer first loads by simply changing the value in the startup included file (see Extending WebServer above). For example 100000 TO /SCRIPT-DICT will set the maximum script dictionary size to 100,000 bytes. ------------------------------------------------------------------------------ Default Index Files If a URL does not explicitly identify a page (ex http://www.logix-controls.com) an attempt to send default index file will be made in the following order INDEX.shtml \ We'll try INDEX.FS first INDEX.HTM INDEX.HTML All subdirectories must have explicit URLs. For example http://www.logix-controls.com/contact/index.html will work but http://www.logix-controls.com/contact/ will not (returns a 404 page not found page). ------------------------------------------------------------------------------ MIME Types Here are the existing supported content types. All except shtml and xml are simply sent "as is" to the client browser. S" text/html" MIME: html S" text/html" MIME: htm S" image/gif" MIME: gif S" image/jpeg" MIME: jpg S" image/png" MIME: png S" application/x-javascript" MIME: js \ javascript S" application/pdf" MIME: pdf S" application/zip" MIME: zip S" text/plain" MIME: txt \ our default You can add more (place in a .F file included from the command line when the server is launched, see Extending WebServer above). For example: ALSO MIMES DEFINITIONS \ Mime type for browser URL extension S" application/foobar" MIME: foo /FORTH ------------------------------------------------------------------------------ Scripted XML The mime type XML now runs a Forth .FS script too. The FS file format for XML is similar to the html format. See the XML-Test.FS file for a simple example. Note the first line of the script should begin with To revert back to non scripted XML behavior, simply redefine XML as a simple mime type. See the example in Custom.F ------------------------------------------------------------------------------ Some additional "documentation": \ Get the entire content received from the Client form. GET-CLIENT-CONTENT ( -- addr count ) \ Get the Content Value from Name=Value pair received from the Client form. GET-CLIENT-CONTENT-VALUE ( NameAddr count -- ValueAddr count ) \ Cookie Template: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure \ Example: MeLove=Cookie%20Monster; expires=Thursday, 01-Jan-98 12:00:00 GMT" \ Define a Cookie to be Sent to the Client, Usually Name=Value pair. SET-CLIENT-COOKIE-NAME ( addr count -- ) \ Append a Value to the Client's Cookie SET-CLIENT-COOKIE-VALUE ( addr count -- ) \ If Expiration is not set, the cookie is valid during the current session only. SET-CLIENT-COOKIE-EXPIRE ( secondsOffset daysOffset -- ) \ Get All the Cookie Name=Value Pair(s) received from the Client. GET-CLIENT-RAW-COOKIE ( -- addr count ) \ Get the Cookie Value from Name=Value Pair received from the Client. \ ex S" PhoneNumber" GET-CLIENT-COOKIE-VALUE GET-CLIENT-COOKIE-VALUE ( NameAddr count -- ValueAddr count ) \ Get the Value from Name=Value Pair received from the Client (POST or GET). GET-CLIENT-ARG-VALUE ( NameAddr count -- ValueAddr count ) GET-HTML-ARGS ( -- Addr Cnt ) GET-HTML-URL ( -- Addr Cnt ) SET-REFRESH ( #secs -- ) \ Most browsers will reload the pages after #secs GET-CLIENT-IP-NAME ( -- Addr Cnt ) \ ------------------------------------------------------------------------------ \ ------------------------------------------------------------------------------ \ Here are a few code snippets \ ------------------------------------------------------------------------------ \ ------------------------------------------------------------------------------ \ ------- Start Time/Date --------------- ... BOOT-STIMER @ .STIMES/DATE \ Type Time/Date WebServer started ... BOOT-STIMER @ STIMER>HMS ( -- sec min hour ) ... BOOT-STIMER @ STIMER>YMD >YMD ( -- year month day ) \ yyyy mm dd ... STIMER @ BOOT-STIMER @ - >SECONDS ( -- secs ) \ #seconds runtime \ --------Totals ----------------------------- ... WEB-MASTER TOTAL#WRITE @ . \ Show totals ... WEB-MASTER TOTAL#READ @ . ... WEB-MASTER TOTAL#REQUESTS @ . \ -------- Capture Running Totals --------------- \ This must be defined in the startup (ie Custom.F) file \ You will probably want to make these double variables VARIABLE RUNNING-TOTAL#WRITE VARIABLE RUNNING-TOTAL#READ VARIABLE RUNNING-TOTAL#REQUESTS \ This will execute every day at midnight just before the totals are cleared C: 1/DAY ( Chain into 1/Day ) WEB-MASTER TOTAL#WRITE @ RUNNING-TOTAL#WRITE +! WEB-MASTER TOTAL#READ @ RUNNING-TOTAL#READ +! WEB-MASTER TOTAL#REQUESTS @ RUNNING-TOTAL#REQUESTS +! C; ( End Chain ) ------------------------------------------------------------------------------ I would appreciate any feedback or suggestions you have to offer. Best regards, Mike Ghan mikeghan@logix-controls.com