|
|
.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.
"Hello World" as a file in the pages directory:
.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"

"Hello World" as a procedure bound to an 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 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"
}

Extract HTML form post data from the Ns_Set in Tcl:
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.

Use the low-level ns_write command:
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.

Use ns_table and ns_column commands to describe a database table:
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.
Query the database with ns_db:
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
}