>>I do, that's why I'm biting the bullet and writing a web server. ;)
Eric,
Writing the web server might be good experience. These notes might
help (or not).
================================================================
I had a little bit of experience with this about a year ago after Carl
released the webserver.r
I wanted a rebol instance that would handle rebol scripts without
having to launch a new instance of rebol ala CGI approach.
This would give me faster response time in the mode that I was working in
then which
was the demonstration of some web prototypes. I wanted to be able to run
a webserver, the web applications, and all of the html pages and graphics
for a reasonable sized application prototype from a diskette. Hence REBOL.
I made a few changes to the webserver.r code which I think they are all in
the while block
with comments to indicate the goal. For me, these changes made sense 'cause
I was just trying to get the REBOL listener on port 80 to recognize that the
URL pointed
to a REBOL script - then knowing that, run it. So it this was fairly
intuitive.
====================================================================
while [on] [
http-port: first wait listen-port
request: first http-port
file: "index.html"
rebol: false ; turn this boolean off
mime: "text/plain"
parse request ["get" ["http" | "/ " | copy file to " "]]
parse file [thru "." [
"htm" (mime: "text/html") |
"html" (mime: "text/html") |
"gif" (mime: "image/gif") |
"jpg" (mime: "image/jpeg") |
"r" (rebol: true ; being asked to process a REBOL
script
mime: "text/html") ; assuming that want to emit html
from REBOL script
]
]
if not none? (parts: parse file "?") ; Look for GET arguments
[file: pick parts 1
; plug the GET arguments back into the query-string
; so that the REBOL script will be able to get them
system/options/cgi/query-string: pick parts 2]
print ["retrieving:" file]
any [
if not exists? web-dir/:file [send-error 404 file]
either rebol
; if the url points in the get points to a rebol script, then just
do it.
[data: copy ""
print: func [some_text] [append data some_text]
if error? try [do web-dir/:file] [send-error 400 file]
]
[if error? try [data: read/binary web-dir/:file] [send-error 400
file]]
send-page data mime
]
close http-port
]
============================================================================
=========
This did what I wanted and worked about an hour after I started it.
The howevers :
a. may not be what you want
b. only handles low usage
Cal Dixon ([EMAIL PROTECTED]) released a different version on the REBOL
List a few days later.
He updated it in January and February 2000.
Cal's would:
a. handle PUTs as well as GETs
b. handle concurrent access
but I did not run it since my few lines above met my needs.
I just checked the REBOL script site and could not find it.
The source that Cal produced was:
============================================================================
============
REBOL [
Title: "REBOL Web Server"
File: %webserv.r
Author: "Cal Dixon"
Email: [EMAIL PROTECTED]
Date: 26-Feb-2000
Purpose: { A Simple HTTP-Server that can run REBOL CGI scripts }
Notes:
{ 0.0.0.3: This version redirects all i/o to the web browser so 'read-io on
system/ports/input
can be used to get POSTed data, etc..
0.0.0.4: Now has better error checking and passes content-length as a
string like it should
0.0.0.5: Can now send multiple files at once
0.0.0.6: Now patches 'print and 'prin to work correctly and passes all
http headers to CGIs
also translates access to a folder to %index.html in that folder.
Also handles
the HTTP HEAD method in addition to GET and sends the
"Last-Modified" header
0.0.0.7: Added logging in Extended Common Log Format - but for CGI scripts
the number of
bytes sent is recorded as 1, due to current limitations of this
program }
Version: 0.0.0.7
Category: 'web
]
wwwpath: %www/ ; change this to where the files are...
port: 80 ; change this to whatever port the server should
listen to
logfile: %webserv.log ; the name of the logfile or set to none
secure none
system/options/quiet: false
e: {<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY>Page not
found.</BODY></HTML>}
cgi-obj: make system/options/cgi [ context: func [] [ return 'context ] ]
listen: open/lines/direct join tcp://: port
inport: system/ports/input
outport: system/ports/output
queue: []
; these replacements for 'print and 'prin should work better for CGI scripts
prin: func [ out /local data ] [
data: replace/all (reform out) newline "^M^J"
write-io system/ports/output data length? data
return
]
print: func [ out /local data ] [
data: replace/all (reform out) newline "^M^J"
data: append data "^M^J"
write-io system/ports/output data length? data
return
]
quit: halt: func [] [throw]
www-send: func [ conn data ] [ write-io conn data length? data ]
either logfile [
write-log: func [ entry ] [ write/append logfile join to-string entry
newline ]
][
write-log: func [ ignorethisvalue ] []
]
get-http-headers: func [ conn /local line buffer a b c ] [
buffer: copy []
while [ ((line: first conn) <> "") and not none? line ] [
a: copy/part line b: find line ":"
c: trim next b
insert buffer reduce [ a c ]
]
return buffer
]
handle-cgi: func [ conn request query headers /local cd ] [
system/options/cgi: make cgi-obj compose [
server-software: "REBOL Web Server"
server-name: (read dns://)
gateway-interface: "CGI/1.1"
server-protocol: "HTTP/1.0"
server-port: "80"
query-string: (query)
request-method: (pick request 1)
script-name: (first parse (pick request 2) "?")
Content-Type: (select headers "Content-Type")
Content-Length: (select headers "Content-Length")
other-headers: (headers)
]
cd: what-dir
system/ports/output: conn
system/ports/input: conn
www-send conn "HTTP/1.0 200 OK^/"
if error? try [ catch [ do file-path ] ] []
system/ports/input: inport
system/ports/output: outport
change-dir cd
close conn
]
content-type?: func [ filename [string! file!] ] [
switch/default next find/last to-string filename "." [
"txt" [ return "text/plain" ]
"gif" [ return "image/gif" ]
"jpg" [ return "image/jpeg" ]
"png" [ return "image/png" ]
"mov" [ return "video/quicktime" ]
"tif" [ return "image/tiff" ]
"tiff" [ return "image/tiff" ]
"wav" [ return "audio/wav" ]
"xml" [ return "text/xml" ]
"xsl" [ return "text/xml" ]
"mid" [ return "audio/midi" ]
"r" [ return none ]
] [ return "text/html" ]
]
process-queue: func [ /local connection data file conn newqueue ] [
newqueue: copy []
foreach connection queue [
set [ conn file ] connection
data: copy/part file 2048
file: skip file 2048
write-io conn data length? data
either tail? file [
close conn
] [
insert/only newqueue reduce [ conn file ]
]
]
queue: newqueue
]
send-header: func [ conn result content-type data-length ] [
www-send conn rejoin [ "HTTP/1.0 " result newline "Content-Type: "
content-type newline
"Content-Length: " data-length newline "Date: " to-idate now newline
"Last-Modified: " to-idate modified? file-path "^/^/" ]
]
translate-request-to-resource: func [ file /local file-path ] [
if (last file) = #"/" [ append file "index.html" ]
file-path: clean-path join wwwpath to-file next file
if none? find file-path clean-path wwwpath [
file-path: clean-path join wwwpath "index.html"
]
if dir? file-path [ append file-path "/index.html" ]
return file-path
]
http-log: func [ host request status bytes /extended headers /local when
agent referer] [
when: rejoin [ replace/all copy/part mold now 11 "-" "/" replace skip
mold now 11 "/" ":" ]
replace when "-" " -"
either (agent: select headers "User-Agent") [
agent: join {"} [ agent {"} ]
][
agent: "-"
]
either (referer: select headers "Referer") [
referer: join {"} [ referer {"} ]
][
referer: "-"
]
reform [
host
"- -"
rejoin [ "[" when "]" ]
mold form request
status
bytes
either extended [
reform [ referer agent ]
][ "" ]
]
]
handle-new-connections: func [ /local data conn http-headers ] [
if none? wait reduce [ listen 0 ] [ return ]
request: parse first (conn: first listen) none
if (length? queue) > 3000 [
insert conn "HTTP/1.0 503 Server Overloaded^/"
close conn return
] ; refuse connections if server is overloaded
request-method: pick request 1
set [ file urlquery ] parse (pick request 2) "?"
file-path: translate-request-to-resource file
http-headers: get-http-headers conn
either exists? file-path [
either none? content: content-type? file-path [
write-log http-log/extended conn/host request 200 1 http-headers
handle-cgi conn request urlquery http-headers
return
] [
write-log http-log/extended conn/host request 200 size? file-path
http-headers
set [ responce data ] reduce [ "200 OK" (data: read/binary
file-path) ]
]
] [
write-log http-log/extended conn/host request 404 0 http-headers
set [ responce content data file-path ] reduce [ "404 Not Found"
"text/html" e %. ]
]
send-header conn responce content length? data
if request-method = "HEAD" [ close conn return ]
insert/only queue reduce [ conn data ]
]
forever [
if ( zero? ( length? queue ) ) [ wait listen ]
handle-new-connections
process-queue
]
===================================================================