.tcl
file in your pages directory. That method is illustrated first. However, the alternative method is also described for the sake of illustrating how to create a Tcl procedure and bind it to an URL..tcl
file in the pages directory. hello.tcl
. (The file must have .tcl
as the extension.)
hello.tcl
file:
ns_return $conn 200 text/plain "Hello World"
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 1: 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" }
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 3: 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>" }
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 4: 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 }
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 5: 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 6: 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 }