From bfd7df7f6dffcf905c4694d6482c50a3506bd9bd Mon Sep 17 00:00:00 2001
From: John Malmberg To run it, do this: \ Details of HTTP come from:Hello, world
"
- Len = length(Hello) + length(ORS)
- print "HTTP/1.0 200 OK" |& HttpService
- print "Content-Length: " Len ORS |& HttpService
- print Hello |& HttpService
- while ((HttpService |& getline) > 0)
- continue;
- close(HttpService)
- }
-
- Now, on the same machine, start your favorite browser and let it
-point to \
- Do you prefer your date human or \
- POSIXed?
" ORS ORS
- TopFooter = ""
- }
-
- On the first run through the main loop, the default line terminators
-are set and the default home page is copied to the actual home page.
-Since this is the first run, 'GETARG["Method"]' is not initialized yet,
-hence the case selection over the method does nothing. Now that the
-home page is initialized, the server can start communicating to a client
-browser.
-
- It does so by printing the HTTP header into the network connection
-('print ... |& HttpService'). This command blocks execution of the
-server script until a client connects. If this server script is
-compared with the primitive one we wrote before, you will notice two
-additional lines in the header. The first instructs the browser to
-close the connection after each request. The second tells the browser
-that it should never try to _remember_ earlier requests that had
-identical web addresses (no caching). Otherwise, it could happen that
-the browser retrieves the time of day in the previous example just once,
-and later it takes the web page from the cache, always displaying the
-same time of day although time advances each second.
-
- Having supplied the initial home page to the browser with a valid
-document stored in the parameter 'Prompt', it closes the connection and
-waits for the next request. When the request comes, a log line is
-printed that allows us to see which request the server receives. The
-final step in the loop is to call the function 'CGI_setup()', which
-reads all the lines of the request (coming from the browser), processes
-them, and stores the transmitted parameters in the array 'PARAM'. The
-complete text of these application-independent functions can be found in
-*note A Simple CGI Library: CGI Lib. For now, we use a simplified
-version of 'CGI_setup()':
-
- function CGI_setup( method, uri, version, i) {
- delete GETARG; delete MENU; delete PARAM
- GETARG["Method"] = $1
- GETARG["URI"] = $2
- GETARG["Version"] = $3
- i = index($2, "?")
- # is there a "?" indicating a CGI request?
- if (i > 0) {
- split(substr($2, 1, i-1), MENU, "[/:]")
- split(substr($2, i+1), PARAM, "&")
- for (i in PARAM) {
- j = index(PARAM[i], "=")
- GETARG[substr(PARAM[i], 1, j-1)] = \
- substr(PARAM[i], j+1)
- }
- } else { # there is no "?", no need for splitting PARAMs
- split($2, MENU, "[/:]")
- }
- }
-
- At first, the function clears all variables used for global storage
-of request parameters. The rest of the function serves the purpose of
-filling the global parameters with the extracted new values. To
-accomplish this, the name of the requested resource is split into parts
-and stored for later evaluation. If the request contains a '?', then
-the request has CGI variables seamlessly appended to the web address.
-Everything in front of the '?' is split up into menu items, and
-everything behind the '?' is a list of 'VARIABLE=VALUE' pairs (separated
-by '&') that also need splitting. This way, CGI variables are isolated
-and stored. This procedure lacks recognition of special characters that
-are transmitted in coded form(1). Here, any optional request header and
-body parts are ignored. We do not need header parameters and the
-request body. However, when refining our approach or working with the
-'POST' and 'PUT' methods, reading the header and body becomes
-inevitable. Header parameters should then be stored in a global array
-as well as the body.
-
- On each subsequent run through the main loop, one request from a
-browser is received, evaluated, and answered according to the user's
-choice. This can be done by letting the value of the HTTP method guide
-the main loop into execution of the procedure 'HandleGET()', which
-evaluates the user's choice. In this case, we have only one
-hierarchical level of menus, but in the general case, menus are nested.
-The menu choices at each level are separated by '/', just as in file
-names. Notice how simple it is to construct menus of arbitrary depth:
-
- function HandleGET() {
- if ( MENU[2] == "human") {
- Footer = strftime() TopFooter
- } else if (MENU[2] == "POSIX") {
- Footer = systime() TopFooter
- }
- }
-
- The disadvantage of this approach is that our server is slow and can
-handle only one request at a time. Its main advantage, however, is that
-the server consists of just one 'gawk' program. No need for installing
-an 'httpd', and no need for static separate HTML files, CGI scripts, or
-'root' privileges. This is rapid prototyping. This program can be
-started on the same host that runs your browser. Then let your browser
-point to Please choose one of the following actions:
\
- \
-
"
- TopFooter = ""
- }
-
- 'SetUpServer()' is similar to the previous example, except for
-calling another function, 'SetUpEliza()'. This approach can be used to
-implement other kinds of servers. The only changes needed to do so are
-hidden in the functions 'SetUpServer()' and 'HandleGET()'. Perhaps it
-might be necessary to implement other HTTP methods. The 'igawk' program
-that comes with 'gawk' may be useful for this process.
-
- When extending this example to a complete application, the first
-thing to do is to implement the function 'SetUpServer()' to initialize
-the HTML pages and some variables. These initializations determine the
-way your HTML pages look (colors, titles, menu items, etc.).
-
- The function 'HandleGET()' is a nested case selection that decides
-which page the user wants to see next. Each nesting level refers to a
-menu level of the GUI. Each case implements a certain action of the
-menu. On the deepest level of case selection, the handler essentially
-knows what the user wants and stores the answer into the variable that
-holds the HTML page contents:
-
- function HandleGET() {
- # A real HTTP server would treat some parts of the URI as a file name.
- # We take parts of the URI as menu choices and go on accordingly.
- if(MENU[2] == "AboutServer") {
- Document = "This is not a CGI script.\
- This is an httpd, an HTML file, and a CGI script all \
- in one GAWK script. It needs no separate www-server, \
- no installation, and no root privileges.\
- \
-
\\
-
JK 14.9.1997
" - } else if (MENU[2] == "AboutELIZA") { - Document = "This is an implementation of the famous ELIZA\ - program by Joseph Weizenbaum. It is written in GAWK and\ - uses an HTML GUI." - } else if (MENU[2] == "StartELIZA") { - gsub(/\+/, " ", GETARG["YouSay"]) - # Here we also have to substitute coded special characters - Document = "" - } - } - - Now we are down to the heart of ELIZA, so you can see how it works. -Initially the user does not say anything; then ELIZA resets its money -counter and asks the user to tell what comes to mind open heartedly. -The subsequent answers are converted to uppercase characters and stored -for later comparison. ELIZA presents the bill when being confronted -with a sentence that contains the phrase "shut up." Otherwise, it looks -for keywords in the sentence, conjugates the rest of the sentence, -remembers the keyword for later use, and finally selects an answer from -the set of possible answers: - - function ElizaSays(YouSay) { - if (YouSay == "") { - cost = 0 - answer = "HI, IM ELIZA, TELL ME YOUR PROBLEM" - } else { - q = toupper(YouSay) - gsub("'", "", q) - if(q == qold) { - answer = "PLEASE DONT REPEAT YOURSELF !" - } else { - if (index(q, "SHUT UP") > 0) { - answer = "WELL, PLEASE PAY YOUR BILL. ITS EXACTLY ... $"\ - int(100*rand()+30+cost/100) - } else { - qold = q - w = "-" # no keyword recognized yet - for (i in k) { # search for keywords - if (index(q, i) > 0) { - w = i - break - } - } - if (w == "-") { # no keyword, take old subject - w = wold - subj = subjold - } else { # find subject - subj = substr(q, index(q, w) + length(w)+1) - wold = w - subjold = subj # remember keyword and subject - } - for (i in conj) - gsub(i, conj[i], q) # conjugation - # from all answers to this keyword, select one randomly - answer = r[indices[int(split(k[w], indices) * rand()) + 1]] - # insert subject into answer - gsub("_", subj, answer) - } - } - } - cost += length(answer) # for later payment : 1 cent per character - return answer - } - - In the long but simple function 'SetUpEliza()', you can see tables -for conjugation, keywords, and answers.(1) The associative array 'k' -contains indices into the array of answers 'r'. To choose an answer, -ELIZA just picks an index randomly: - - function SetUpEliza() { - srand() - wold = "-" - subjold = " " - - # table for conjugation - conj[" ARE " ] = " AM " - conj["WERE " ] = "WAS " - conj[" YOU " ] = " I " - conj["YOUR " ] = "MY " - conj[" IVE " ] =\ - conj[" I HAVE " ] = " YOU HAVE " - conj[" YOUVE " ] =\ - conj[" YOU HAVE "] = " I HAVE " - conj[" IM " ] =\ - conj[" I AM " ] = " YOU ARE " - conj[" YOURE " ] =\ - conj[" YOU ARE " ] = " I AM " - - # table of all answers - r[1] = "DONT YOU BELIEVE THAT I CAN _" - r[2] = "PERHAPS YOU WOULD LIKE TO BE ABLE TO _ ?" - ... - - # table for looking up answers that - # fit to a certain keyword - k["CAN YOU"] = "1 2 3" - k["CAN I"] = "4 5" - k["YOU ARE"] =\ - k["YOURE"] = "6 7 8 9" - ... - } - - Some interesting remarks and details (including the original source -code of ELIZA) are found on Mark Humphrys' home page. Yahoo! also has -a page with a collection of ELIZA-like programs. Many of them are -written in Java, some of them disclosing the Java source code, and a few -even explain how to modify the Java source code. - - ---------- Footnotes ---------- - - (1) The version shown here is abbreviated. The full version comes -with the 'gawk' distribution. - - -File: gawkinet.info, Node: Caveats, Next: Challenges, Prev: Simple Server, Up: Using Networking - -2.11 Network Programming Caveats -================================ - -By now it should be clear that debugging a networked application is more -complicated than debugging a single-process single-hosted application. -The behavior of a networked application sometimes looks noncausal -because it is not reproducible in a strong sense. Whether a network -application works or not sometimes depends on the following: - - * How crowded the underlying network is - - * If the party at the other end is running or not - - * The state of the party at the other end - - The most difficult problems for a beginner arise from the hidden -states of the underlying network. After closing a TCP connection, it's -often necessary to wait a short while before reopening the connection. -Even more difficult is the establishment of a connection that previously -ended with a "broken pipe." Those connections have to "time out" for a -minute or so before they can reopen. Check this with the command -'netstat -a', which provides a list of still "active" connections. - - -File: gawkinet.info, Node: Challenges, Prev: Caveats, Up: Using Networking - -2.12 Where To Go From Here -========================== - -Now, you have learned enough to build your own application. You could, -for example, take part in the Loebner Contest to win $100,000. The -Loebner Prize is the first formal instantiation of a Turing Test. Hugh -Loebner agreed with The Cambridge Center for Behavioral Studies to -underwrite a contest designed to implement the Turing Test. Dr. Loebner -pledged a Grand Prize of $100,000 for the first computer whose responses -were indistinguishable from a human's. Each year an annual prize of -$2000 and a bronze medal is awarded to the _most_ human computer. The -winner of the annual contest is the best entry relative to other entries -that year, irrespective of how good it is in an absolute sense. Here is -an example of a conversation with the winning program of 1997: - - (c)1997 Cambridge Center For Behavioral Studies all rights reserved [CONVERSE] - [Intelligent Research Ltd.] Start at: [1997/04/29 08:59:40] - PROGRAM[10:39:20]Hi, my name is Catherine, what's yours? - JUDGE02[10:39:36]My name is Nathan. - PROGRAM[10:39:37]Well, it's nice to meet you, Nathan. - PROGRAM[10:39:45]Did you see that story on CNN last night about the lesbian - PROGRAM[10:40:03]couple who came out at a White House party on Sunday? - JUDGE02[10:40:45]No. I'm sorry I missed that. How did the Prez take it? - PROGRAM[10:40:47]Ellen Degeneres was one of them - she was kissing her lover - PROGRAM[10:41:08]in front of Bill Clinton. Do you think he was very - PROGRAM[10:41:21]embarrassed? - JUDGE02[10:41:37]You tell me. I didn't see it. - PROGRAM[10:41:38]Are you still a Friend of Bill Clinton? - JUDGE02[10:42:22]Yes. I would like to talk about something else. Do you know anything about sculpture. - PROGRAM[10:42:24]Well, I suppose he's doing his best like most of us, but he - PROGRAM[10:42:35]does seem to attract an UNUSUAL amount of bad publicity, - PROGRAM[10:42:51]wouldnt you say--can it all be bad luck? - JUDGE02[10:43:20]I asked you if you knew anything about sculpture. - PROGRAM[10:43:21]OK, but what happens now--does it all drift on, with - PROGRAM[10:43:36]everyone waiting to see how much his friends have said about - PROGRAM[10:43:47]him under threat of lots and lots of jail-or will something - PROGRAM[10:44:01]dramatic actually happen? - JUDGE02[10:44:19]Do you know what sculpture is? - PROGRAM[10:44:20]Well, youre more a fan of his than I am I guess---though I - PROGRAM[10:44:34]cant SWEAR what Id have done in that locked hotel room, I - PROGRAM[10:44:51]must say. - JUDGE02[10:45:26]Have you ever been to the Salmagundi Club? - PROGRAM[10:45:29]Never. to go back to the original discussion Time to get - PROGRAM[10:45:43]off this one I think and onto something more down to earth! - JUDGE02[10:46:20]What is more down to earth than art? - PROGRAM[10:46:21]I don't know what -- to be honest. - - PROGRAM[10:46:30]I suppose it depends on where you're coming from, but as the - PROGRAM[10:46:46]song goes in My Fair Lady, "Why can't a woman be more like a - PROGRAM[10:47:03]man? " - JUDGE02[10:47:52]I liked that song but I prefer "Why can't children be more like we are" - JUDGE02[10:48:10]from another play the name of which I cannot remember. - PROGRAM[10:48:12]What, if anything, do you enjoy about being a man? - JUDGE02[10:49:01]I would enjoy all aspects of life no matter what my gender. - PROGRAM[10:49:02]Do you think of yourself as being attractive? - - This program insists on always speaking about the same story around -Bill Clinton. You see, even a program with a rather narrow mind can -behave so much like a human being that it can win this prize. It is -quite common to let these programs talk to each other via network -connections. But during the competition itself, the program and its -computer have to be present at the place the competition is held. We -all would love to see a 'gawk' program win in such an event. Maybe it -is up to you to accomplish this? - - Some other ideas for useful networked applications: - * Read the file 'doc/awkforai.txt' in the 'gawk' distribution. It - was written by Ronald P. Loui (at the time, Associate Professor of - Computer Science, at Washington University in St. Louis, -" i " | " \ - "" config[i] " |