This section contains the following examples:
This simple example can be accomplished using either ADPs or Tcl libraries. Since the actual "work" of the script is accomplished by only one Tcl command (ns_return), it would be easier to use an ADP, but the Tcl libraries method is used here for the sake of illustrating how to create a Tcl procedure and bind it to a URL.
This example details how to write a WWW "Hello World" operation in Tcl and bind it as a procedure to a URL.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
hello.test
in the entry box labeled Create a new script in this directory called.
/examples/tcl/hello.tcl
file.
# Example: Hello World # # This simple operation just returns a plain text message. # Things to notice: # # * ns_register_proc takes as arguments: # * the HTTP method # * the URL that the procedure handles # * the procedure that is executed # # * ns_return takes as arguments: # * the passed in connection # * a return status, in this case 200 for success, # * a MIME type # * the actual string to return # # * ns_return properly formats the HTTP response for you. ns_register_proc GET /example/hello hello proc hello {conn context} { ns_return $conn 200 text/plain "Hello World" }
The following is a more extensive example typical of an end-to-end AOLserver Tcl extension. In this case, one operation dynamically generates and returns a page to the user. The page includes a form where the user enters a few values. When the submit button is pressed, another operation extracts the data entered by the user and generates a short story that is returned to the user.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
story.test
in the entry box labeled Create a new script called.
# Example: Form generation and handling # # Two functions are registered. One generates and # returns an HTML form, and the other processes # the data in the form. # # Things to notice: # # * Different functions are registered to the same # URL with different methods. Note that some browsers # do not cache results properly when you do this. # # * The genstory function returns an error status # (500) if the client doesn't pass in any form data. # # * Form data is stored in an ns_set, and accessed # like any other set (e.g., headers) # # * A counter is used to loop through all the key # value pairs in the form. ns_register_proc GET /example/genstory genstoryform ns_register_proc POST /example/genstory genstory proc genstoryform {conn context} { ns_return $conn 200 text/html \ "<HTML> <HEAD> <TITLE>Automatic Story Generator</TITLE> </HEAD> <BODY> <H1> Automatic Story Generator </H1> <FORM ACTION=http:/example/genstory METHOD=POST> Noun: <INPUT TYPE=text NAME=noun1><BR> Noun: <INPUT TYPE=text NAME=noun2><BR> Name: <INPUT TYPE=text NAME=name1><BR> Name: <INPUT TYPE=text NAME=name2><BR> Adjective: <INPUT TYPE=text NAME=adjective1><BR> Adjective: <INPUT TYPE=text NAME=adjective2><BR> Verb: <INPUT TYPE=text NAME=verb1><BR> Verb: <INPUT TYPE=text NAME=verb2><BR> <P><INPUT TYPE=submit VALUE=\"Generate\"> </FORM> <P> </BODY></HTML> "} proc genstory {conn ignore} { set formdata [ns_conn form $conn] if {$formdata == ""} { ns_return $conn 200 text/plain "Need form data!" return } # Build up a human-readable representation of the form data. set hrformdata "<dl>" set size [ns_set size $formdata] for {set i 0} {$i < $size} {incr i} { append hrformdata "<dt>[ns_set key $formdata $i]</dt>\ <dd>[ns_set value $formdata $i]</dd>" } append hrformdata "</dl>" ns_return $conn 200 text/html \ "<HTML> <HEAD> <TITLE>The story of [ns_set get $formdata name1] and [ns_set get $formdata name2]</TITLE> </HEAD> <BODY> <H1> The story of [ns_set get $formdata name1] and [ns_set get $formdata name2] </H1> <P>Once upon a time [ns_set get $formdata name1] and [ns_set get $formdata name2] went for a walk in the woods looking for a [ns_set get $formdata noun1]. [ns_set get $formdata name1] was feeling [ns_set get $formdata adjective1] because [ns_set get $formdata name2] was so [ns_set get $formdata adjective2]. So [ns_set get $formdata name1] decided to [ns_set get $formdata verb1] [ns_set get $formdata name2] with a [ns_set get $formdata noun2]. This made [ns_set get $formdata name2] [ns_set get $formdata verb2]. <P><CENTER>The End</CENTER> The form data that made this possible:<BR> $hrformdata </BODY></HTML>" }
Because the AOLserver is a dynamic extensible environment, the /example/genstory URL is immediately ready. To test the new operations, open the /example/genstory URL in any browser to receive a page for entering the information needed to create the story. When you press the Generate button, your browser POSTs to the same /example/genstory URL. Because you must register both the method and URL, the AOLserver can distinguish the POST from a GET and can invoke the correct procedure to generate your story.
In most cases, a Tcl operation simply returns either a string or file to the client, and for these cases, the ns_return command can be used as shown in the examples above. The ns_return command generates a properly formatted HTTP response, including headers.
The ns_respond command is more powerful. In some cases, you may need to write a string directly using the low-level function ns_write command. The example below shows three ways to return an HTTP redirect to the client.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
write.test
in the entry box labeled Create a new script called.
# Example: Implementing redirects with ns_respond and # ns_write # # /example/not_here uses ns_respond to return an HTTP # redirect to /example/finaldest. # /example/not_here2 does the same thing using ns_write # /example/not_here3 does the same thing with # ns_returnredirect # # Things to notice: # # * When you use ns_write, you need to compose the # entire response; # # * "ns_info location" returns the http://hostname # part of the URL that you can use to generate # fully qualified URLs. # # * ns_returnredirect is a lot simpler than either # ns_respond or ns_write ns_register_proc GET /example/finaldest finaldest ns_register_proc GET /example/not_here not_here ns_register_proc GET /example/not_here2 not_here2 ns_register_proc GET /example/not_here3 not_here3 proc not_here {conn ignore} { set headers [ns_set new myheaders] ns_set put $headers Location [ns_info location]/example/finaldest ns_respond $conn -status 302 -type text/plain \ -string "Redirection" -headers $headers } proc not_here2 {conn context} { ns_write $conn \ "HTTP/1.0 302 Document follows MIME-Version: 1.0 Content-Type: text/html Content-Length: 291 Location: [ns_info location]/example/finaldest <HTML><HEAD><TITLE>Redirection</TITLE></HEAD><BODY> <H1>Redirection</H1>The actual location of what you were looking for is <A HREF=\"[ns_info location]/example/finaldest\"> here.</A> </BODY></HTML>" } proc finaldest {conn context} { ns_return $conn 200 text/plain \ "You have arrived at the final destination" } proc not_here3 {conn context} { ns_returnredirect $conn \ [ns_info location]/example/finaldest }
Because the AOLserver is a dynamic extensible environment, the /example/not_here, /example/not_here2, and /example/not_here3 URLs are immediately ready. To test the new operations, open the /example/not_here or /example/not_here2 or /example/not_here3 URLs in any browser. Your browser will be redirected to the /example/finaldest URL, which returns a simple message. The ns_respond command in not_here and the ns_returnredirect command in not_here3 encapsulate all the low level writes required in not_here2.
One of the strengths of the Tcl API is its ability to query and modify databases quickly and easily. It will tell you the structure of the database as well as let you query and modify its contents.
On a database error, these commands generate Tcl errors, so you may need to use the Tcl catch command to handle database errors that are generated by user input.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears.
table.test
in the entry box labeled Create a new script called.
# Example: Describing a database table # # /example/describetable prints out a column-by-column # description of the database table. The database pool name and # table name are specified at the end of the URL -- e.g., # /example/describetable/nsdbpool/ns_users # # Things to notice: # # * ns_returnbadrequest returns a nicely formatted message # telling the client they submitted an invalid request. # # * "ns_conn urlv" returns a Tcl array whose elements are the # slash-delimited parts of the URL. # # * The describetable function loops through all the columns # and uses "ns_column valuebyindex" to get the type of each # one. # # * ns_returnnotice nicely formats the return value. ns_register_proc GET /example/describetable describetable proc describetable {conn ignore} { if {[ns_conn urlc $conn] != 4} { return [ns_returnbadrequest $conn \ "Missing table name and or poolname"] } set pool [lindex [ns_conn urlv $conn] 2] if {[lsearch $pool [ns_db pools]] == -1} { return [ns_returnbadrequest $conn \ "Pool $pool does not exist"] } set db [ns_db gethandle $pool] set table [lindex [ns_conn urlv $conn] 3] set tinfo [ns_table info $db $table] if {$tinfo == ""} { return [ns_returnbadrequest $conn \ "Table $table does not exist"] } set output "Description of table:\ <blockquote><tt>$table</b></tt></blockquote><dl>" set size [ns_column count $tinfo] for {set i 0} {$i < $size} {incr i} { append output "<dt>[ns_column name $tinfo $i]\ <dd>[ns_column typebyindex $tinfo $i]</dd>" } append output "<hr>" ns_returnnotice $conn 200 "Table:$table in pool $pool" $output }
Because the AOLserver is a dynamic extensible environment, the /example/describetable URL is immediately ready. To test the new operations, open the /example/describetable/<poolname>/<tablename> URL in any browser, where you substitute <poolname> with the name of a database pool and <tablename> with the name of a table in the database. The AOLserver returns a page that describes the schema of the selected table.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
query.test
in the entry box labeled Create a new script called.
# Example: Getting data from the database # # /example/getemps queries a database in the default # pool and returns a list of all the employees listed # in the employees table. It assumes a table called # employees exists with the column emp_name. # # Things to notice: # # * Use "ns_dbgethandle" to get a handle for the database. # It assumes that there is a database pool named "default". # # * Use "ns_db select" to query the database and # "ns_db getrow" to retrieve data. # # * Rows are returned as ns_sets. # ns_register_proc GET /example/getemps getemps proc getemps {conn context} { set ul "<UL>" set db [ns_db gethandle default] set row [ns_db select $db \ "select emp_name from employees order by emp_name;"] while {[ns_db getrow $db $row]} { append ul "<LI>[ns_set get $row emp_name]\n" } append ul "</UL>" ns_returnnotice $conn 200 "Employee list" $ul }
Because the AOLserver is a dynamic extensible environment, the /example/getemps URL is immediately ready. To test the new operation, open the /example/getemps URL in any browser. The AOLserver returns a list of the names in the employee table.
This example defines a script called rolllog
that uses ns_accesslog to roll the access log to a file with an extension containing the current date. The ns_schedule_daily function is used to execute the rolllog
script on a daily basis.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
# Script to roll and rcp log file to host "grinder" proc rolllog {} { set suffix [ns_strftime "%y-%m-%d"] set new [ns_accesslog file].$suffix ns_accesslog roll $new exec rcp $new grinder:/logs/[file tail $new] } # Schedule "rolllog" to run at 3:30 am each morning # Use shared variable to keep an extra scheduling from # happening when script is re-sourced ns_share -init {return 0} scheduler_installed if {!$scheduler_installed} { set scheduler_installed 1 ns_schedule_daily -thread 3 30 rolllog }
Because the AOLserver is a dynamic extensible environment, the rolllog script is immediately scheduled to run the following morning.
This script uses ns_register_proc to redirect everything to another domain while preserving the URLs. For example, http://thissite/foo/bar.html will be redirected to http://www.newdomain.com/foo/bar.html.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
ns_register_proc GET / movesite http://www.newdomain.com proc movesite {conn newlocation} { ns_returnredirect $conn 302 $newlocation[ns_conn url $conn] }
lower
directory:
ns_register_proc GET /lower movesite http://www.newdomain.com proc movesite {conn newlocation} { ns_returnredirect $conn 302 $newlocation[ns_conn url $conn] }
Because the AOLserver is a dynamic extensible environment, the movesite script is immediately registered.
This example registers a filter procedure that will be run at post-authorization time for all HTML files. The procedure will set the Expires header to expire all HTML files after one hour.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
# Expire all HTML files after an hour ns_share -init {return 0} filters_installed if {!$filters_installed} { set filters_installed 1 ns_register_filter postauth GET /*.html ExpireSoon 3600 } proc ExpireSoon {conn seconds why} { ns_set update [ns_conn outputheaders $conn] Expires \ [ns_httptime [expr $seconds + [ns_time]]] }
Because the AOLserver is a dynamic extensible environment, the ExpireSoon script is immediately registered.
This example redirects only the top page according to the browser being used.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
ns_register_proc -noinherit GET / toppage proc toppage {conn ignore} { if [ns_browsermatch $conn "*Mozilla*"] { ns_returnfile $conn 200 text/html "netscape_top.html" } else { ns_returnfile $conn 200 text/html "other_top.html" } }
Because the AOLserver is a dynamic extensible environment, the toppage script is immediately registered.
This example registers a procedure to be run on a POST for all files with the .eml extension. A POST to an .eml file sends the .eml file as a mail message. Note that this code would need to provide error checking for bad input and bad files.
http://
followed by the name of the host where the server is running. A page containing links to several server functions appears. If you're using another browser, go to the /NS/Admin page on your server.
ns_register_proc POST /*.eml myemailer proc myemailer {conn ignore} { set form [ns_conn form $conn] set to [ns_set get $form to] set from [ns_set get $form from] set subject [ns_set get $form subject] set fp [open [ns_url2file [ns_conn url $conn]]] set body [read $fp] close $fp ns_sendmail $to $from $subject $body ns_returnnotice $conn 200 "Thank You" "Your mail has been sent." }
Because the AOLserver is a dynamic extensible environment, the myemailer script is immediately registered.