[REBOL] Slightly newer HTTP Server Object
Just created (and attached) a newer version of my HTTP server object. Instead of directly overriding the method handlers during object creation you can put a handler in a %handlers directory. Upon start-up the server scans that directory looking for %init.r, %get.r, %post.r, %head.r, and %put.r files. It will replace its default handlers with the appropriate files. I'm attaching the new object along with a sample get.r file. This get.r serves html files, images, etc. from a %www directory, i.e. it behaves like a normal webserver. As one can see, it didn't take much code to implement that functionality on top of the base server object. The HTTP server object itself is meant to be sort of a black box. Any code to extend the server should go in the handlers. (get.r probably being the most common one folks would want to change, probably followed by post.r) The HTTP server object handles multiple connections and has separate queues for reading and writing to those connections. Incidentally, you can change the handlers on the fly while the server is running by visiting the /refresh url. It causes the get.r etc. handlers to be reloaded. /shutdown causes the server to shutdown and cleanup. These both cause 404s to be returned by the above get.r. I'll probably fix that in the next rev. One the server object has solidified, I'm going to start adding some layers on top to facilitate the creation of web application servers. XML- RPC support is somewhat high on the list of features I'd like to implement. Some comments would be welcome :) :Eric get.r httpobject.r
[REBOL] Horribly Busy, but Woohoo! a Web Server Object :)
I'm in the process of moving to a new apartment this weekend, so I don't have the time to properly upload this to the script libraries, so I'm just appending it this email. Hopefully nothing will get goofed up... At least it's somewhat commented. :) This is a generic self-contained HTTP server object. It handles multiple connections and has rudimentary cookie support. It currently handles GET, PUT, POST, and HEAD requests. To make good use of this object, you should at least override the get- handler method and possibly the post-handler, put-handler, and head- handler methods. It all depends on what you want to do. Fortunately, you should only have to override these four methods. And odds are you'll only need to override the get-handler and post-handler methods, since HEAD and PUT requests are pretty rare. You'll probably want to change the listen port from the default of 80 if you plan on running other servers. As presented, It does *not* serve files from disk or run CGI scripts. The default handlers merely display the headers and data that the client sent over. (Good for debugging, and an interesting learning experience...) The purpose of this object was to facillitate the creation of special purpose servers that use the HTTP protocol. All of the normal functionality one expects in a traditional web server can be easily layered on top. XML-RPCers should love this, and once I'm done with the move, I'll join in the effort to get a Rebol XML-RPC server up and going. It should be a night's work with this object to get a rudimentary server up and running. All of the HTTP stuff is handled, you can just concentrate on the meat, i.e. parsing the request XML, handling the method invocation, and generating the response XML. I haven't done any substantial benchmarking, but under Mac OS 8.6 and using the experimental Rebol 2.4 PPC build, this server seems to be able to send data at ~150 - 200k/s. (It depends on where and how you're generating the data.) To give this thing a try, do something like this: s: make http-server [] s/run Thanks to everyone on the list who have answered questions that have indirectly helped me with this. Enjoy! :Eric ;Start of code Rebol [ Title: "Rebol HTTP Server Object" Date: 25-Aug-2000 Author: "Eric King" ] ; ; Random notes: ; If the debug attribute is set to true (which it is by default) ; Attempting to read (GET) from /shutdown will cause the web server ; to clean up and shutdown. ; ; As presented here, this web server does *not* serve pages from disk. ; Why? Because, I wanted a very general and flexible HTTP protocol server. ; That is, I did not necessarily want URIs to map directly to files. ; That said, getting this to serve pages, images, sounds, etc is ; really easy. In your get-handler method, convert the Target-URI: ; header to a path and put the resulting file in the entity field of your ; handler-response object. Also set the code, cookie, hdrs, and mime fields ; to something appropriate. ; e.g. response/code: "200" response/mime: "text/plain" response/cookie: "" ; response/hdrs: copy [] ; ; response/entity: open %target-file.txt ; or ; response/entity: read %target-file.txt (This seems faster under MacOS 9) ; http-server: make object! [ ; ; HTML Templates ; default-template: copy {!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN" html titleRebol HTTP Server Object/title style type="text/css" !-- a:link ^{ text-decoration: none; color: #6D4D4D ^} a:visited ^{ text-decoration: none; color: #4D4D6D ^} text {font-family: Arial, Sans-serif; font-size: 12px;} -- /style meta name="generator" content="Reblog 3.0" body bgcolor = "#FF" div class = "text" !--content-- /div /body /html} ; ; Attributes ; port: 80 connections:0 listener: none ;Queues to hold the state of multiple connections read-q: copy[] write-q:copy[] ;Create a 4k buffer for headers header-buffer: make string! 4096 ;Send/Receive data in 8k chunks read-chunk-size: 8192 write-chunk-size: 8192 ;Limit size of PUT or POSTed data max-entity: 32768 debug: true ;Copy this object and set the appropriate fields in the ;get-handler, put-handler, post-handler, and head-handler methods. handler-response: make object! [ code: copy "200" mime: copy "text/html" cookie: copy "value=nothing" entity: copy "" hdrs: copy [] ] ; ; Utility Methods ; cmt-insert: function [str [string!] tag [string!] con [string!] /dup /every] [ s t c d] [ s: rejoin [ copy "!--" copy tag "--" ] c: copy con
[REBOL] Extending Webserver.r Re:(4)
On Sun, Aug 13, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: 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). Thanks, lots of good code in there. My next set of questions was going to revolve around handling multiple connections. :Eric
[REBOL] Extending Webserver.r
I'm trying to extend the Webserver.r script to handle POSTed data, but I'm getting very confused as to what can and can't be done with ports. How should the loop to fetch the POSTed data be constructed, i.e. which commands should I be using to gather the data and what things should I be testing to see when I've gathered all of the data sent by a browser? Is this sort of stuff covered in the Official Guide to Rebol? :Eric (Just a hapless graphics geek trying to learn a little networking)
[REBOL] Extending Webserver.r Re:(2)
On Sat, Aug 12, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: Hi Eric: I'm somewhat of a rebol newbie myself, but have done quite a bit of CGI programming. I have only looked briefly at Webserver.r, but I believe it is configured to handle http request specifically (that is, to be a server). If you are not fairly well appraised of CGI issues, there are a number of sites where you can get that information. I should clarify things, I don't want to deal with CGI issues. All I've been doing at work for the last 3 months is writing CGI scripts in Rebol. It's gotten to the point where some of the things I'd like to do would be best accomplished with a small custom HTTP server. I think I solved my problem. I went digging around in the system/ schemes/http and looked at how it read in the http headers: while [(line: pick port/sub-port 1) ""] [append headers join line "^/"] I put in a line like that, and then extracted the content-length. I used the content-length in a read-io loop to get the form data. I have to say that this is most assuredly non-intuitive. I would never have thought to use pick like that. I'd kill for a really good tutorial on the ins and outs of ports and networking in Rebol. have a good grasp of CGI issues. I do, that's why I'm biting the bullet and writing a web server. ;) :Eric
[REBOL] Trying to get Rebol to work as a CGI on Apache 1.3.x on a Cobalt Raq3 with CGIWRAP Re:
On Sun, Aug 6, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: Trying to get Rebol to work as a CGI on Apache 1.3.x on a Cobalt Raq3 with CGIWRAP Um. Any ideas? I tried a bunch of things even tried putting rebol in cgi-bin itself and no dice. It's working just peachy on our Raq3i. Just stick the Rebol binary some place convenient, make it executable chmod, and make sure the first line of your CGI script points to the directory where you placed the Rebol binary. Don't forget to make your script executable with chmod. Someone posted a link to a more detailed set of instructions for installing Rebol on a Linux a while back. You could go digging through the archives for it. There's nothing particularly weird about setting Rebol up on a Raq with CGIwrap vs. a normal Linux box. As long as the binary and script are okay, CGIwrap will just work. (Though it does eat path info) :Eric
[REBOL] Multithreaded rebol commands? Re:
On Sun, May 7, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: :I am wondering if there is a way to "multithread" a rebol command in the :background. Not yet. :More questions: Is there a way to launch another instance of rebol within a :rebol script? Not directly, but if there's a local web server floating around, you could have one instance of Rebol start up another instance by having the webserver invoke a Rebol CGI script. CGI also enables some fairly simple ways of passing data between the scripts. Path-info, query-strings, POSTed data, etc. .:Eric
[REBOL] Limit on data in CGI Post? Re:(3)
On Wed, Apr 19, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: :CGI POST calls will send the data you want to the CGI process. When :yo uare handling it yo umay need multiple reads to get it all... it :may not all be there when you do your first read. You'll notice that :with POST you also get some headers and one of them should tell you :how much data to expect. Therefore you can write a read loop to get :it all. : :You would most likely need to check to make sure that the port is :still open as well as read from it (copy) to deal with data transfer :delays and all. :Also, decode-cgi is only for the GET request and not for POST. Yo :uwill find that POST data has a more complex structure... almost like :an email with attachments. You will have to deal with that data :yourself. Thanks, this has been driving me nuts. :) I don't have to worry about uploads yet, everything's being submitted with url-encoding. .:Eric
[REBOL] Limit on data in CGI Post?
This may or may not be directly related to Rebol. Is there a limit on the maximum amount of data a browser can send to a CGI script via a Post? Weird things are happening when I try to send more than ~5k or so of data in a form to a Rebol CGI script I'm writing. .:Eric
[REBOL] Limit on data in CGI Post? Re:
On Wed, Apr 19, 2000, [EMAIL PROTECTED] [EMAIL PROTECTED] wrote: I've done some more digging, and it looks like Rebol isn't reading enough data from the standard input. I'm getting my posted data using the following: stdin: make string! 128000 read-io system/ports/input stdin 128000 raw-cgi: decode-cgi stdin cgi-obj: make object! raw-cgi Oddly different browsers send different amounts of text. With Internet Explorer 5.0 only the first 4096 bytes are read. With Netscape 4.7 only 2920 bytes are read. With Netscape 6 only 2847 bytes are read. And with iCab only 3688 bytes are read. Since read-io doesn't seem to be documented anywhere, I'm not quite sure how to go about fixing this problem. I tried submitting this same hunk of text on a form on another website (my weblog on www.editthispage.com) and it went through just fine. So I'm assuming that this is an issue with my Rebol code. .:Eric
[REBOL] RFC: Split-Path Re:
On Wed, Apr 5, 2000, [EMAIL PROTECTED] wrote: Request for Comments on Split-Path Revision --- Issue: Should split-path be changed? Discussion: Split-path currently returns the last element of a path, regardless of whether it is a file or directory. That is: split-path %a/b/c == [%a/b/ %c] split-path %a/b/c/ == [%a/b/ %c/] This allows writing iterative code like: path: %/a/b/c/d == %/a/b/c/d while [path %/] [set [path file] split-path path print file] d c/ b/ a/ (Note, this example also shows another problem with split-path... in that it has no regular iterative termination condition. If you provided a path of %a/b/c/d this code would loop forever, because the path would reduce to %./ not %/ ) However, you would normally think that a split path type of function would separate the directory path from the file name itself. This would take %a/b/c/ and return a directory path of %a/b/c/ and a file of none (not a file of %"", which is a file with no name). However, you loose the iterative "peeling" shown above. Since split-path has other issues that we will be fixing very soon, I would like to get your comments on this issue soon. Do not consider legacy with existing code base. It is better to correct this problem today, rather than when the child is 20. Isn't this a good case for refinements? While, I'm not sure what the best default behavior should be, split-path/file and split-path/dir refinements seem like reasonable extensions to add. .:Eric Sneak a peek... http://www.smallandmighty.com/reblog/
[REBOL] B2 Status Re:
On Thu, Mar 30, 2000, [EMAIL PROTECTED] wrote: Just wanted to give you a quick update on REBOL/View Beta 2 status: We're still cranking away, but getting much closer now. MANY changes that you'll like -- things like multiple windows, better view/event handling, aspect fit effect, cross effect (for checkboxes), circle effect (for radio buttons), clipboard cut and paste, windows with no-border/no-title, resizing of windows, getting window size/offset, setting window size/offset, minimize window, faster text scrolling, standard font words, right/middle mouse buttons, 256 chars, control chars, spanky new help, help with pattern matching, help datatype patterns, componentized model, load/markup, read-thru, fixed load-thru, many other changes and fixes etc. etc. What's not in B2 that we promised? The new CID. Sorry, just not going to make it in time. But, we'll be adding it quite soon. -RT While /View certainly sounds like an exciting product, are any of the new datatypes and functions in it going to make their way back into /Core? Specifically, I'd like to be able to manipulate (scale, crop, composite, add text, etc.) JPEGs in CGI scripts. .:Eric
[REBOL] Using REBOL for CGI's - no need for Apache module? Re:
On Thu, Mar 30, 2000, [EMAIL PROTECTED] wrote: There tech support admitted that they had'nt heard of REBOL and they were'nt sure if it would be ok on the system as they dont allow new Apache modules (cobalt servers, it would go against the warranty apparently). There's a version for Cobalt Qubes. I'm not sure about the Raqs. Some use MIPS processors others x86. I think that the x86-based Raqs would work with the Linux x86 Rebol binary. Could I just do my scripts like this: #!/path/to/rebol --cgi REBOL [ Title: "CGI Test Script" ] where the first line would tell where the rebol interpreter was (my cgi-bin I guess) ? Yep. I didn't even tell my hosting service I was installing Rebol. I figured if they were giving me access to gcc, which is potentially far more dangerous, then they shouldn't care if I run Rebol, which is pretty innocuous. REBOL on quite a lot of platforms enough so hopefully it will run on whatever they use! Pretty much anything that can run Apache can run Rebol. Incidentally, are there any other MachTen users out there? It would be nice to have a version of Rebol for MachTen. That way I could test my Rebol CGI scripts locally with Apache while still running the Mac OS and using BBEdit, Golive, Photoshop, etc. MachTen is BSD 4.4ish. So as long as it doesn't do weird things with the VM subsystem, I'd imagine a port would be rather straightforward. Also, I've seen some perl scripts which use "sendmail". Can you execute other programs in REBOL (I would'nt think so due to probs with cross platform). Would I have to find out their SMTP server and configure rebol to use it via set-net ? Yep, that's what I did. My Rebol CGI scripts can send email without using sendmail. .:Eric
[REBOL] Put rebol script em html pages Re:(4)
On Mon, Mar 27, 2000, [EMAIL PROTECTED] wrote: Hello: I need to test the rebol interpreter, which has been recently installed on the server for my domain. Where can I get a the minimum code (like hello.r) to test it. Server is linux redhat 6.1 thanks Tim The following is pretty minimal. It will print out any path info found in the url that invokes it. e.g. http://www.yourdomain.com/cgi-bin/pathinfo.cgi/panfriedpancreas/ will return a page containing "/panfriedpancreas" Just change the "path/to" in " #!path/to/rebol -cs" to the real path to Rebol on your server, chmod +x the script to make it executable, and put it in the appropriate place. Some servers require cgi scripts to be in a special cgi-bin directory. Others don't. .:Eric Copy the following starting with the #! and save it to a file, such as pathinfo.cgi #!/path/to/rebol -cs REBOL [ Title: "Simple CGI" Date: 27-Mar-2000 ] html-header: reduce ["Content-type: text/html" newline] page: copy {!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd" html head meta http-equiv="content-type" content="text/html;charset=iso-8859-1" /head body bgcolor="white" text="black" !--path-info-- /body /html} path-info: copy "" ;Is there any path info? if error? try [ path-info: copy system/options/cgi/path-info ] [ path-info: "No path info" ] page: replace page "!--path-info--" path-info print html-header print page quit
[REBOL] JPEG, GIF, and PNG dimensions
Out of curiosity, has anyone written any Rebol/Core code that will extract the dimensions of JPEG, GIF, and PNG files? I know this is more the realm of Rebol/View, but it would be useful for Rebol/Core CGI scripts too. .:Eric
[REBOL] getting rebol OK Re:
On Thu, Mar 9, 2000, [EMAIL PROTECTED] wrote: I am searching for a new web hosting service and I figure it is a good business practice to ask the hosting service if it is "OK" to use scripting languages other than perl for CGI. The response is usually, "what scripting languages are you thinking about?" When I tell them REBOL and point them to the REBOL web page, they tell me (all of them so far) that REBOL is not a language that can be used on their servers. What does a person do besides installing and using the binary first and asking for forgiveness later? I don't know, because I did that exact thing. ;) I did mention that I was using Rebol during an email to their tech. support, and they (http://www.dreamhost.com) didn't seem to care. I think most services won't care as long as you don't do evil things with Rebol and as long as you don't need to involve their tech. support crew. Also, any hosting service that gives you access to C compilers as part of their plan should be pretty permissive, since you could do far more evil with that than Rebol/Core. .:Eric
[REBOL] Rebol/Command and the kitchen sink Re:(3)
On Fri, Mar 3, 2000, [EMAIL PROTECTED] wrote: If I remember, MySQL has a TCP/IP interface. So it would be possible to create a mysql protocol scheme for REBOL. I've been hunting around for some documentation on the TCP/IP interface, but haven't had much luck. From what I've been able to gather, the preferred way of accessing mySQL via TCP is by using the C interface library. There doesn't seem to be any documentation of the protocol that the C library uses anywhere. .:Eric
[REBOL] Why doesn't this work? Re:(4)
On Tue, Mar 7, 2000, [EMAIL PROTECTED] wrote: when Make encounters a word 'Obj as its first argument, it thinks that you are asking it to create a word specified by the second argument. It can't create a word from a Block! type value and tries to tell you that. (the problem here is, that the computer cannot guess your intent correctly - no intuition so far) If the second argument were a string or another datatype compatible with word, make would simply create the appropriate word. Ah, I see. That makes some sense. The documentation could use some updating with regards to subtleties like this. Is anyone maintaining a Rebol FAQ? .:Eric
[REBOL] Why doesn't this work? Re:(2)
On Sat, Mar 4, 2000, [EMAIL PROTECTED] wrote: Hi, two possibilities, the first looks better: 1) obj: make object! [a: "" b: ""] t: obj new-obj: make t [] 2) obj: make object! [a: "" b: ""] t: 'obj new-obj: make get t [] Thanks for the help. The error message I received seems pretty odd though. .:Eric ** Script Error: Expected one of: word! - not: block!. ** Where: new-obj: make t []
[REBOL] Why doesn't this work?
obj: make object! [a: "" b: ""] t: 'obj new-obj: make t [] When I try it, I get the following response: obj: make object! [a: "" b: ""] t: 'obj == obj new-obj: make t [] ** Script Error: Expected one of: word! - not: block!. ** Where: new-obj: make t [] How does one make a derived object using a variable to specify the parent object? .:Eric
[REBOL] Rebol/Command and the kitchen sink Re:(2)
On Thu, Mar 2, 2000, [EMAIL PROTECTED] wrote: Having done something similar with ASP and MS-SQL Server 7, using ASP to fetch pages to a server, and then using ASP to parse them (by requesting the asp page with the file name as the parameter) and spit back a success/fail message, and then having Rebol take the appropriate action (deleting the file because it was inserted successfully, or emailing the admin about a failure, and leaving the file in the queue to be reprocessed the next time around) I can say it works. It's ugly, but it gets the job done. On the other hand - what [EMAIL PROTECTED] is trying to accomplish is just better done in PHP alone. First, I've never really said what I'm trying to accomplish. ;) I just said I'm probably going to need a database. For instance, one thing I'd like to implement on the site I'm working on are simple discussion forums. Nothing really fancy, and certainly nothing that would contain more than a couple of hundred messages. A MySQL database certainly would do the job, but seems a little like overkill. But what's the simplest way to serialize modifications to the forum file/database by Rebol CGI scripts? I've thought about using a temporary file as a crude sort of semaphore. (Hence, one of the needs for a unique ID...) Another possibility might be to make a 'simple' little Rebol server daemon to serialize or synchronize file/database accesses by CGI scripts. Still another possibility is to somehow integrate just enough PHP to cover Rebol/Core's deficiencies. Why bother to add another layer on top of it? Just to use Rebol? That kind of solution flies in the face of the Rebol phillosophy. K I S S Keep it Simple, Stupid. That's what I'm trying to do. I don't think reading a PHP page to get the time with millisecond resolution is a particularly complex task. Reading PHP pages to access a database might very well be too hairy to try. I haven't attempted it yet, so I don't know. But for the real meat of what I want to do, Rebol's flexible syntax really seems like a boon, i.e. what I want will probably take a lot more PHP code to implement than Rebol code. The simple solution is usually the best, and most correct one. When Rebol/Command comes out, and you can access deeper functionality using Well, that's what I'm wondering about. I can definitely run Rebol/Core on the site I'm working on, but I don't know what the requirements for installing Rebol/Command are and I'm pretty sure my hosting provider won't install the Rebol/Apache module when it comes out. Incidentally, does anyone know what new capabilities the Rebol/Apache module provides? Is it like PHP where you can embed arbitrary chunks of Rebol code in HTML? Or is it just something that speeds up Rebol CGI execution? Rebol - then will be the time to give it a whirl to provide dynamic web pages with a database back-end. Remember, just because you can do something doesn't mean you should. You know, for now, I'd be happy with some simple and robust ways to synchronize multiple active Rebol CGI processes and a really simple flat-file database. This sort of thing should be possible in Core. .:Eric P.S. Here's a function which should generate a unique hexadecimal ID and the associated html for the mstime.phtml file. This isn't too funky is it? unique-id: function [] [ s r text] [ r: read http://www.smallandmighty.com/mstime.phtml parse r [thru "body" copy text to "/body"] text: trim skip text 6 s: to-decimal text s: s * 10 s: to-string to-hex to-integer s return s ] HTML HEAD /HEAD BODY ? $mtime = microtime(); $mtime = explode(" ",$mtime); $mtime = $mtime[1] + $mtime[0]; print $mtime; ? /BODY /HTML
[REBOL] Rebol/Command and the kitchen sink Re:(2)
On Fri, Mar 3, 2000, [EMAIL PROTECTED] wrote: Er, can you use PHP to gateway between Rebol and MySql? ( a Rebol script to read a PHP page, and post to a PHP form? While I haven't tried it, it certainly looks feasible. If you fetch a page from Apache, any embedded PHP script will be executed, and the results could be passed to a Rebol cgi program in a variety of different ways. Another option is to have a PHP script launch an instance of Rebol from the command line and pipe stuff to it and from it. As others have mentioned, too much mixing of Rebol and PHP scripts is bound to be hard to maintain. But if some rudimentary database facilities and other misc. functions could be provided with a few pages of short PHP scripts, it might be worthwhile to give it a go, especially since PHP is so widely installed. .:Eric
[REBOL] Session ID?
What's the best way to generate a unique session identifier in Rebol? .:Eric