Mini web server for serving static web pages.
Supported in QuikCode versions 2.35 and later. Not the free DOS version.
************************************************************************
* Program: WebServer.q *
* Purpose: Mini web server for serving static web pages. *
* Written: 12/21/2005 *
* Updated: 06/03/2006 - Modify program documentation. *
* Version: 0.90 *
* To Run.: QuikCode WebServer.q (Press Enter) *
* Notes..: - No information is sent out to the internet if the *
* IPADDRESS equate is set to the internal loopback address, *
* 127.0.0.1. *
* - To test, type the IP address/domain name of the server *
* using your favorite internet browser. A simple test page *
* should appear if it exists in the home directory. *
* Example: http://localhost *
* - Processes over 1500 requests per second using a typical *
* desktop PC running Windows 2000 on a 100Mbps/Half Duplex *
* connection. *
* - This program passes all Nikto version 1.35 vulnerability *
* tests. *
* - Runs unmodified under SUSE Linux 10.0 and DSL Linux 2.4 *
* using Wine, but with a decrease in performance. *
* To run under Linux, enter the following: *
* wineconsole quikcode.exe WebServer.q (Press Enter) *
* *
* Equates: LOCALHOST - Loopback address, 127.0.0.1. Not used. *
* IPADDRESS - IP address to use. Specifying "ANY" informs *
* QuikCode to use the IP address of the computer *
* that is running this program. *
* PORT - Port number to run on. Internet browsers *
* typically use port 80. *
* HOMEDIR - Relative directory name under the current *
* directory where this server is running. It *
* contains the client accessible data such as *
* *.html, *.gif, and *.jpg files. *
* HOMEPAGE - File name of the web site home page. *
* LOGFILE - Name of the activity log file. This file is *
* not automatically deleted and will increase in *
* size as client requests are processed. *
* SHUTDOWN - Shut down command. Allows the server to be *
* gracefully stopped by a internet browser, but *
* only from the computer running this program. *
* This command is case-sensitive and will not be *
* written to the log file. *
* Examples: http://127.0.0.1/STOPME! *
* or: http://localhost/STOPME! *
* or: localhost/STOPME! *
* TIMEOUT - Number of milliseconds the server will wait *
* before displaying a "no socket activity" *
* message. Also serves as the maximum amount of *
* time to allow a client to complete an HTTP *
* request. *
* MAXSOCKETS - Maximum allowable number of simultaneous *
* client connections. *
* MAXSSASIZE - Maximum record size in bytes to allocate to *
* the Server Socket A (SSA) record. Larger size *
* can increase server performance. *
* MAXIFASIZE - Maximum size in bytes to allocate to the IFA *
* file record. Larger size can increase server *
* performance. *
* MAXOFASIZE - Maximum size in bytes to allocate to the OFA *
* file record. Larger size can increase server *
* performance. *
* MAXWSTSIZE - Maximum size in bytes to allocate to the WST *
* (Working Storage) record. *
* BELL - Rings bell when displayed on the console. *
* *
* To Do..: - Support URL Decoding. *
* - Port QuikCode to Linux to run with winelib. *
************************************************************************
* Configurable equates.
equate LOCALHOST to '127.0.0.1'
equate IPADDRESS to 'ANY'
equate PORT to '80'
equate HOMEDIR to 'home'
equate HOMEPAGE to 'index.html'
equate LOGFILE to 'webserver.log'
equate SHUTDOWN to 'STOPME!'
equate SSATIMEOUT to 60000
equate MAXSOCKETS to 400
equate MAXSSASIZE to 20000
equate MAXIFASIZE to 20000
equate MAXOFASIZE to 500
equate MAXWSTSIZE to 1000
* Miscellaneous equates - Leave these intact.
equate VERSION to 'QuikCode/0.90'
equate CRLF to x'0D0A'
equate BELL to X'07'
equate SVRID to 'Server: ' VERSION CRLF
equate SVRIDSIZE to 23
equate HTTP200 to 'HTTP/1.1 200 OK' CRLF
equate HTTP200SIZE to 17
equate HTTP400 to 'HTTP/1.1 400 Bad Request' CRLF
equate HTTP400SIZE to 26
equate HTTP404 to 'HTTP/1.1 404 Not Found' CRLF
equate HTTP404SIZE to 24
equate HTTP408 to 'HTTP/1.1 408 Request Timeout' CRLF
equate HTTP408SIZE to 30
equate HTTP501 to 'HTTP/1.1 501 Not Implemented' CRLF
equate HTTP501SIZE to 30
equate CONNCLOSE to 'Connection: Close' CRLF
equate CONNCLOSESIZE to 19
equate HTMLTYPE to 'Content-Type: text/html' CRLF
equate HTMLTYPESIZE to 25
equate GIFTYPE to 'Content-Type: image/gif' CRLF
equate GIFTYPESIZE to 25
equate JPEGTYPE to 'Content-Type: image/jpeg' CRLF
equate JPEGTYPESIZE to 26
equate TEXTTYPE to 'Content-Type: Text/Plain' CRLF
equate TEXTTYPESIZE to 26
equate ZIPTYPE to 'Content-Type: application/zip' CRLF
equate ZIPTYPESIZE to 31
equate CONTENT0 to 'Content-Length: 0' CRLF
equate CONTENT0SIZE to 19
equate CONTENTN to 'Content-Length: xxxxxxx' CRLF
equate CONTENTNLEN to ssa17-23-n
equate CONTENTNSIZE to 25
option ssasize = MAXSSASIZE
option ifasize = MAXIFASIZE
option ofasize = MAXOFASIZE
option wstsize = MAXWSTSIZE
equate sub1 to wst1-2-i
equate sub2 to wst3-4-i
equate sub2-1 to wst3
equate sub2-2 to wst4
equate find-sub to wst5-6-i
equate filetype-sub to wst7-8-i
equate NOT-USED to wst9-10
equate close-client-sw to wst11
equate host-id-sw to wst12
equate last-client-addr to wst15-29
equate last-client-addr-1 to wst15
equate method to wst30
equate curdate to wst31-40 * GMT date
equate curdate-mm to wst31-32
equate curdate-dd to wst34-35
equate curdate-yyyy to wst37-40
equate activity-sw to wst41 * Socket activity switch 'Y'/'N'
equate filename to wst101-280
equate filename-1 to wst101
equate filetype to wst281-285
equate filetype-1 to wst281
* Start Web Server
perform 0100 * Initialization
perform 1000 * Handle Client HTTP Requests
perform 3000 * Termination
end
* Initialization
0100 set windowsize to 40 80
cls
set windowtitle to VERSION ' Web Server - Address ' "'" IPADDRESS "'" ', Port ' PORT
set windowBufSize to 1200 120
move MAXSOCKETS to ssa-maxsockets * Set simultaneous client connections. Default is 50.
move SSATIMEOUT to ssa-timeout * Set socket timeout milliseconds. Default is blocking.
move 'N' to activity-sw * Init socket activity switch
if HOMEPAGE = spaces
display 'StartUp Error - HOMEPAGE equate is undefined' BELL
go to 190.
if HOMEDIR = spaces
display 'StartUp Error - HOMEDIR equate is undefined' BELL
go to 190.
open ofa LOGFILE binaryappend MAXOFASIZE 80000 * Open Web Server log file
if ofa is not open
display 'StartUp Error - Unable to open log file ' LOGFILE
go to 190.
move 2 to ofa-recsize
move CRLF to ofa
write ofa
move 31 to ofa-recsize
move 'Started :' to ofa1-10
move date to ofa11-20
move time1-8 to ofa22-29
move CRLF to ofa30-31
write ofa
set path to HOMEDIR
open ifa HOMEPAGE
if ifa is not open
display 'StartUp Error - Home page file ' HOMEPAGE ' not found!' BELL
go to 190.
close ifa
open ssa IPADDRESS ':' PORT TCPHTTP MAXSSASIZE 100000 * Open Listener socket
if val-error-cd = 0
display VERSION ' Web Server started. Address ' "'" IPADDRESS "'" ', port ' PORT '.'
exit.
if val-error-cd = 10048
display 'A server is already running on port ' Port Bell
else
display 'Unable to start server - ' noskip
perform 9900.
0190 system 'pause'
end
0199 exit
* Handle Client HTTP Requests
* The following 'READ' will not return until at least one complete http
* request is obtained by a connected client, a timeout (EOF), or socket
* error is detected.
1000 read ssa * Read record from a client.
if ssa is eof * No socket activity
display date ' ' time1-8 ' - No socket activity'
if activity-sw = 'Y' * Did we just have socket activity?
flush ofa * Flush LOGFILE buffer so we can view it
move 'N' to activity-sw
go to 1000
else
go to 1000.
if val-error-cd <> 0
perform 9700 * Report Socket Read Error
go to 1000.
move 'Y' to activity-sw
*** display 'ssa = ' ssa
if ssa-clientaddr <> last-client-addr
display date ' ' time1-8 ' - Connected to client on IP address ' ssa-clientaddr
move ssa-clientaddr to last-client-addr.
perform 1100 * Get Method/Resource/HTTP version
if filename-1 = SHUTDOWN * Client issued shutdown command?
if last-client-addr-1 = LOCALHOST * Command entered on this computer?
exit * Yes, Shut down the server.
else
move 46 to ofa-recsize
move spaces to ofa1-10
move 'Remote shutdown attempt to server!' to ofa11
move CRLF to ofa45-46
write ofa
display date ' ' time1-8 ' - Remote server shutdown attempt on IP address ' ssa-clientaddr BELL
go to 1010
.
perform 8900 * Log Client Request
1010 read ssa client at eof 1020 * Read another record from client's socket buffer until empty (EOF)
if ssa1-2 = CRLF * End of client request
go to 1020.
*** display 'ssa = ' ssa
toupper ssa * Convert SSA record to UPPER case
if ssa1 = 'HOST:' * Client identified host?
move 'Y' to host-id-sw.
if ssa1 = 'CONNECTION: '
move 13 to find-sub
find <> space in ssa by find-sub * Find next non-space character
if find-sub > 0
if ssa1(find-sub) = 'CLOSE' * Close client after response is sent?
move 'Y' to close-client-sw.
go to 1010
1020 if host-id-sw <> 'Y' * Host identified?
perform 9000 * No, Return 400 Bad Request response
else
if method = 'G' * 'GET' request from client?
perform 1200 * Yes, Return response to 'GET' request
else
if method = 'H' * 'HEAD' request from client?
perform 1300 * Yes, Return response to 'HEAD' request
else
perform 9300. * 501 Not Implemented Error response
if close-client-sw = 'Y' * Did client request socket to be closed?
close ssa client. * Yes, then close client connection.
go to 1000
1099 exit
* Get Method/Resource/HTTP version
* Careful! Modifying this code could invite a security breach.
1100 move 'Y' to host-id-sw
move 'Y' to close-client-sw
move 0 to filetype-sub
move ssa1 to method * Save 1st char of method
if ssa1-4 = 'GET ' * 'GET' request?
move 5 to find-sub
else
if ssa1-5 = 'HEAD ' * 'HEAD' request?
move 6 to find-sub
else
move '?' to method * Unsupported request
move 1 to find-sub.
find <> space in ssa by find-sub * Find next non-space character
if find-sub = 0
move HOMEPAGE to filename
exit.
move find-sub to sub1
move 1 to sub2
move spaces to filename
if ssa1(sub1) = '/'
add 1 to sub1
if ssa1(sub1) = ' '
move HOMEPAGE to filename
go to 1130.
1110 if sub1 > ssa-recsize
or sub2 > 180 * Limit file paths to 180 bytes
move '?' to filename * Return an invalid file name!
exit.
if ssa1-2(sub1) = '..' * Don't allow traversal above home directory
or ssa1(sub1) = ':' * Don't allow possible reference to a hard drive
move '?' to filename * Return an invalid file name!
move 45 to ofa-recsize
move spaces to ofa1-10
move 'Possible security breach attempt!' CRLF to ofa11
write ofa
display date ' ' time1-8 ' - Possible security breach attempt on IP address ' ssa-clientaddr BELL
go to 1130.
if ssa1(sub1) = ' '
or ssa1(sub1) = '?'
go to 1120.
move ssa1(sub1) to filename-1(sub2)
if ssa1(sub1) = '.'
if sub2 = 1
move '?' to filename
add 1 to sub2
go to 1120
else
move sub2 to filetype-sub
add 1 to filetype-sub.
add 1 to sub1
add 1 to sub2
go to 1110
1120 subtract 1 from sub2
if filename-1(sub2) = '/'
add 1 to sub2
move HOMEPAGE to filename-1(sub2).
1130 if ssa-recsize < 10
exit.
move ssa-recsize to find-sub
subtract 10 from find-sub * HTTP/1.1 + CRLF
find <> space in ssa by find-sub * Find next non-space character
if find-sub = 0
exit.
if ssa1(find-sub) = 'HTTP/1.1' * Client reporting HTTP/1.1?
move 'N' to host-id-sw * Client should report host:
move 'N' to close-client-sw * Allow connection to stay-alive
exit.
1199 exit
* Return response to 'GET' request
1200 open ifa filename binary MAXIFASIZE 40000 * Open input file requested by client.
if ifa is not open * Unable to find Requested File
perform 9100 * 404 Not Found Error response
exit.
move HTTP200SIZE to ssa-recsize
move HTTP200 to ssa
move 8 to ofa-recsize
move ' - ' to ofa
move ssa10-12 to ofa4-6
move CRLF to ofa7-8
write ofa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
perform 8300 * GMT Time
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
move SVRIDSIZE to ssa-recsize
move SVRID to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
perform 8200 * Content-type: ?
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
move CONTENTNSIZE to ssa-recsize
move CONTENTN to ssa
move ifa-filesize to CONTENTNLEN
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
if close-client-sw = 'Y'
move CONNCLOSESIZE to ssa-recsize
move CONNCLOSE to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
move 2 to ssa-recsize
move CRLF to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
1220 read ifa at eof 1230 * Read record from input file
move ifa-recsize to ssa-recsize
move ifa to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
go to 1230.
go to 1220
1230 close ifa
1299 exit
* Return response to 'HEAD' request.
1300 move HTTP200SIZE to ssa-recsize
move HTTP200 to ssa
move 8 to ofa-recsize
move ' - ' to ofa
move ssa10-12 to ofa4-6
move CRLF to ofa7-8
write ofa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
perform 8300 * GMT Time
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move SVRIDSIZE to ssa-recsize
move SVRID to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
if close-client-sw = 'Y'
move CONNCLOSESIZE to ssa-recsize
move CONNCLOSE to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move 2 to ssa-recsize
move CRLF to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
1399 exit
* Termination
3000 display VERSION ' Web Server shutting down' BELL
close ssa
move 31 to ofa-recsize
move 'Ended :' to ofa
move date to ofa11-20
move time1-8 to ofa22-29
move CRLF to ofa30-31
write ofa
move 2 to ofa-recsize
move CRLF to ofa1-2
write ofa
close ofa
3999 exit
8000 * Not used
8099 exit
8100 * Not used
8199 exit
* Content-Type: Return just the more common ones...
* More at link: http://www.iana.org/assignments/media-types/
8200 if filetype-sub = 0
move HTMLTYPESIZE to ssa-recsize
move HTMLTYPE to ssa
write ssa
exit.
move 1 to sub1
move spaces to filetype
8210 move filename-1(filetype-sub) to filetype-1(sub1)
add 1 to filetype-sub
add 1 to sub1
if filetype-sub <= 180
if filename-1(filetype-sub) <> ' '
if sub1 < 6
go to 8210.
toupper filetype * Convert filetype to upper case
if filetype-1 = 'HTM '
or filetype-1 = 'HTML '
move HTMLTYPESIZE to ssa-recsize
move HTMLTYPE to ssa
write ssa
exit.
if filetype-1 = 'GIF '
move GIFTYPESIZE to ssa-recsize
move GIFTYPE to ssa
write ssa
exit.
if filetype-1 = 'JPG '
or filetype-1 = 'JPEG '
move JPEGTYPESIZE to ssa-recsize
move JPEGTYPE to ssa
write ssa
exit.
if filetype-1 = 'ZIP '
move ZIPTYPESIZE to ssa-recsize
move ZIPTYPE to ssa
write ssa
exit.
if filetype-1 = 'TXT '
move TEXTTYPESIZE to ssa-recsize
move TEXTTYPE to ssa
write ssa
exit.
8299 exit
* GMT Format -> Date: Sun, 01 Jan 2006 12:34:56 GMT
8300 move 37 to ssa-recsize
move spaces to ssa
move gmtdate to curdate
move 'Date:' to ssa1
move gmtday1-3 to ssa7-9
move ',' to ssa10
move curdate-dd to ssa12-13
move gmtmonth1-3 to ssa15-17
move curdate-yyyy to ssa19-22
move gmttime1-8 to ssa24-31
move 'GMT' CRLF to ssa33
write ssa
8399 exit
* Log Client Activity
8900 move 50 to ofa-recsize
move 'Request :' to ofa1-10
move date to ofa11-21
move time1-8 to ofa22-29
move ' - ' to ofa30-32
move ssa-clientaddr to ofa33-47
move ' - ' to ofa48-50
write ofa
subtract 2 from ssa-recsize
if ssa-recsize <= 0
exit.
if ssa-recsize <= MAXOFASIZE
move ssa-recsize to ofa-recsize
move ssa to ofa
else
* Truncate request from client
move MAXOFASIZE to ofa-recsize
move ssa to ofa.
write ofa
8999 exit
* 400 Bad Request Error response
9000 move HTTP400SIZE to ssa-recsize
move HTTP400 to ssa
perform 9400 * Generic Error Response
9099 exit
* 404 Not Found Error response
9100 move HTTP404SIZE to ssa-recsize
move HTTP404 to ssa
perform 9400 * Generic Error Response
9199 exit
* 408 Request Timeout
9200 move HTTP408SIZE to ssa-recsize
move HTTP408 to ssa
perform 9400 * Generic Error Response
9299 exit
* 501 Not Implemented Error response
9300 move HTTP501SIZE to ssa-recsize
move HTTP501 to ssa
perform 9400 * Generic Error Response
9399 exit
* Generic Error Response
9400 move 8 to ofa-recsize
move ' - ' to ofa
move ssa10-12 to ofa4-6
move CRLF to ofa7-8
write ofa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
perform 8300 * GMT Time
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move SVRIDSIZE to ssa-recsize
move SVRID to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move CONTENT0SIZE to ssa-recsize
move CONTENT0 to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move CONNCLOSESIZE to ssa-recsize
move CONNCLOSE to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move 2 to ssa-recsize
move CRLF to ssa
write ssa
if val-error-cd <> 0
perform 9800 * Report Socket Write Error
exit.
move 'Y' to close-client-sw
9499 exit
* Report Socket Read Error
9700 if val-error-cd <> 10054 * Don't report Connection resets by peer
display date ' ' time1-8 ' - Socket Read error - ' noskip
perform 9900.
9799 exit
* Report Socket Write Error
9800 display date ' ' time1-8 ' - Socket Write error - ' noskip
perform 9900
9899 exit
* Display Socket Error Description
9900 if val-error-cd = 10054
display 'Connection reset by peer' noskip
else
if val-error-cd = 10060
display 'Connection timed out' noskip
else
if val-error-cd = 10004
display 'Interrupted function call' noskip
else
if val-error-cd = 10013
display 'Permission denied' noskip
else
if val-error-cd = 10014
display 'Bad address' noskip
else
if val-error-cd = 10022
display 'Invalid argument' noskip
else
if val-error-cd = 10024
display 'Too many open files' noskip
else
if val-error-cd = 10035
display 'Resource temporarily unavailable' noskip
else
if val-error-cd = 10036
display 'Operation now in progress' noskip
else
if val-error-cd = 10037
display 'Operation already in progress' noskip
else
if val-error-cd = 10038
display 'Socket operation on nonsocket' noskip
else
if val-error-cd = 10039
display 'Destination address required' noskip
else
if val-error-cd = 10040
display 'Message too long' noskip
else
if val-error-cd = 10041
display 'Protocol wrong type for socket' noskip
else
if val-error-cd = 10042
display 'Bad protocol option' noskip
else
if val-error-cd = 10043
display 'Protocol not supported' noskip
else
if val-error-cd = 10044
display 'Socket type not supported' noskip
else
if val-error-cd = 10045
display 'Operation not supported' noskip
else
if val-error-cd = 10046
display 'Protocol family not supported' noskip
else
if val-error-cd = 10047
display 'Address family not supported by protocol family' noskip
else
if val-error-cd = 10048
display 'Address already in use' noskip
else
if val-error-cd = 10049
display 'Cannot assign requested address' noskip
else
if val-error-cd = 10050
display 'Network is down'
else
if val-error-cd = 10051
display 'Network is unreachable' noskip
else
if val-error-cd = 10052
display 'Network dropped connection on reset' noskip
else
if val-error-cd = 10053
display 'Software caused connection abort' noskip
else
if val-error-cd = 10055
display 'No buffer space available' noskip
else
if val-error-cd = 10056
display 'Socket is already connected' noskip
else
if val-error-cd = 10057
display 'Socket is not connected' noskip
else
if val-error-cd = 10058
display 'Cannot send after socket shutdown' noskip
else
if val-error-cd = 10061
display 'Connection refused' noskip
else
if val-error-cd = 10064
display 'Host is down' noskip
else
if val-error-cd = 10065
display 'No route to host' noskip
else
if val-error-cd = 10067
display 'Too many processes' noskip
else
if val-error-cd = 10091
display 'Network subsystem is unavailable' noskip
else
if val-error-cd = 10092
display 'Winsock dll version out of range' noskip
else
if val-error-cd = 10093
display 'Successful WSAStartup not yet performed' noskip
else
if val-error-cd = 10101
display 'Graceful shutdown in progress' noskip
else
if val-error-cd = 10109
display 'Class type not found' noskip
else
if val-error-cd = 11001
display 'Host not found' noskip
else
if val-error-cd = 11002
display 'Nonauthoritative host not found' noskip
else
if val-error-cd = 11003
display 'This is a nonrecoverable error' noskip
else
if val-error-cd = 11004
display 'Valid name, no data record of requested type' noskip
else
if val-error-cd = 0
display 'Successful' noskip
exit
else
display 'Unknown socket error' noskip
.
display ' (' val-error-cd ')'
9999 exit