Index: mod_nsd/tcl_modules/fastpath.tcl
===================================================================
RCS file: /usr/local/cvsroot/mod_nsd/tcl_modules/fastpath.tcl,v
diff -u
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mod_nsd/tcl_modules/fastpath.tcl	6 May 2001 18:54:01 -0000	1.1
@@ -0,0 +1,467 @@
+#
+# The contents of this file are subject to the AOLserver Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://aolserver.com/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is AOLserver Code and related documentation
+# distributed by AOL.
+# 
+# The Initial Developer of the Original Code is America Online,
+# Inc. Portions created by AOL are Copyright (C) 1999 America Online,
+# Inc. All Rights Reserved.
+#
+# Alternatively, the contents of this file may be used under the terms
+# of the GNU General Public License (the "GPL"), in which case the
+# provisions of GPL are applicable instead of those above.  If you wish
+# to allow use of your version of this file only under the terms of the
+# GPL and not to allow others to use your version of this file under the
+# License, indicate your decision by deleting the provisions above and
+# replace them with the notice and other provisions required by the GPL.
+# If you do not delete the provisions above, a recipient may use your
+# version of this file under either the License or the GPL.
+#
+
+#
+# $Header: /usr/local/cvsroot/mod_nsd/tcl_modules/fastpath.tcl,v 1.1 2001/05/06 18:54:01 petrup Exp $
+#
+
+#
+# fastpath.tcl --
+#
+#   AOLserver 2.x fastpath routines moved from C.  The C code
+#   now only handles the simple case of returning a file through
+#   an optimized caching routines.  All legacy AOLpress publishing
+#   functions are handled with the Tcl code below.  In addition,
+#   the C code will dispatch to the _ns_dirlist proc below to
+#   handle directory listings and AOLpress MiniWeb top pages.
+#
+
+set path "ns/server/[ns_info server]"
+nsv_set _ns_fastpath type [ns_config $path directorylisting none]
+nsv_set _ns_fastpath hidedot [ns_config -bool $path hidedotfiles 1]
+nsv_set _ns_fastpath toppage [ns_config -bool $path returnmwtoppage 0]
+nsv_set _ns_fastpath aolpress [ns_config -bool $path enableaolpress 0]
+
+#
+# Register the publishing procs if enabled.  Note that you must
+# load a permission module (e.g., nsperm) or the server
+# will deny access to all these publishing methods.
+#
+
+if [nsv_get _ns_fastpath aolpress] {
+    ns_register_proc PUT / _ns_publish _ns_put
+    ns_register_proc DELETE / _ns_publish _ns_delete
+    ns_register_proc BROWSE / _ns_publish _ns_browse
+    ns_register_proc MKDIR / _ns_publish _ns_mkdir
+    ns_register_proc OPTIONS / _ns_publish _ns_options
+}
+
+
+#
+# _ns_isaolpress --
+#
+#   Is the client AOLpress?
+#
+
+proc _ns_isaolpress {} {
+    set agent [ns_set iget [ns_conn headers] user-agent]
+    return [string match NaviPress/* $agent]
+}
+
+
+#
+# _ns_getnvd --
+#
+#   Return the MiniWeb control file for a directory.
+#
+
+proc _ns_getnvd dir {
+    return $dir/document.nvd
+}
+
+
+#
+# _ns_ismw --
+#
+#   Is the directory a MiniWeb?
+#
+
+proc _ns_ismw dir {
+    return [file exists [_ns_getnvd $dir]]
+}
+
+
+#
+# _ns_dirlist --
+#
+#   Handle directory listings.  This code is invoked from C.
+#
+
+proc _ns_dirlist {} {
+    set url [ns_conn url]
+    set dir [ns_url2file $url]
+
+    #
+    # Handle special case of AOLpress MiniWebs.
+    #
+
+    if {[nsv_get _ns_fastpath toppage] && [_ns_ismw $dir]} {
+	set nvd [_ns_getnvd $dir]
+	if [_ns_isaolpress] {
+	    return [ns_returnfile 200 application/x-navidoc $file]
+	}
+	set fp [open $nvd]
+	while {[gets $fp line] >= 0} {
+	    if [string match Pages:* $line] {
+		break
+	    }
+	}
+	gets $fp line
+	close $fp
+	set file [lindex [split $line \"] 1]
+	if [file exists $dir/$file] { 
+	    return [ns_returnredirect $file]
+	}
+    }
+
+    #
+    # Handle default case of directory listing.  Simple
+    # format is just the files while fancy includes
+    # the size and modify time (which is more expensive).
+    #
+
+    switch [nsv_get _ns_fastpath type] {
+	simple {
+	    set simple 1
+	}
+	fancy {
+	    set simple 0
+	}
+	none -
+	default {
+	    return [ns_returnnotfound]
+	}
+    }
+
+    set hidedot [nsv_get _ns_fastpath hidedot]
+    set location [ns_conn location]
+    
+    set prefix "${location}${url}/"
+    set up "<a href=..>..</a>"
+    if $simple {
+	append list "
+<pre>
+$up
+"
+    } else {
+	append list "
+<table>
+<tr align=left><th>File</th><th>Size</th><th>Date</th></tr>
+<tr align=left><td colspan=3>$up</td></tr>
+"
+    }
+
+    foreach f [lsort [glob -nocomplain $dir/*]] {
+	set tail [file tail $f]
+	if {$hidedot && [string match .* $tail]} {
+	    continue
+	}
+	
+	set link "<a href=\"${prefix}${tail}\">${tail}</a>"
+
+	if $simple {
+	    append list $link\n
+	} else {
+	    
+	    if [catch {
+		file stat $f stat
+	    } errMsg ] {
+		append list "
+<tr align=left><td>$link</td><td>N/A</td><td>N/A</td></tr>\n
+"
+	    } else {
+		set size [expr $stat(size) / 1000 + 1]K
+		set mtime $stat(mtime)
+		set time [clock format $mtime -format "%d-%h-%Y %H:%M"]
+		append list "
+<tr align=left><td>$link</td><td>$size</td><td>$time</td></tr>\n
+"
+	    }
+	}
+    }
+    if $simple {
+	append list "</pre>"
+    } else {
+	append list "</table>"
+    }
+    ns_returnnotice 200 $url $list
+}
+
+
+#
+# _ns_publish --
+#
+#   Wrapper to log publishing actions.
+#
+
+proc _ns_publish proc {
+    ns_log notice "fastpath:[ns_conn authuser]:$proc [ns_conn url]"
+    $proc
+}
+
+proc ns_returnok {} {
+    ns_return 200 text/plain ""
+}
+
+proc _ns_remove file {
+    ns_log notice "fastpath:[ns_conn authuser]:unlink: $file"
+    ns_unlink $file
+}
+
+#
+# _ns_browse --
+#
+#   Handle the AOLpress BROWSE request to for its file dialog.
+#
+    
+proc _ns_browse {} {
+    set url [ns_conn url]
+    set dir [ns_url2file $url]
+    set files ""
+    foreach f [glob -nocomplain $dir/*] {
+	set tail [file tail $f]
+	if [file isdir $f] {
+	    set type "application/x-navidir"
+	} else {    
+	    set type [ns_guesstype $tail]
+	}
+	append files "$type $tail\n"
+    }
+    ns_return 200 application/x-navibrowse $files
+}
+
+
+#
+# _ns_mkdir --
+#
+#   Handle the AOLpress MKDIR request to create a new directory.
+#
+
+proc _ns_mkdir {} {
+    set url [ns_conn url]
+    set dir [ns_url2file $url]
+    if [file exists $dir] {
+	return [ns_returnbadrequest "File Exists"]
+    }
+
+    if [catch {ns_mkdir $dir} err] {
+	ns_log error "fastpath: mkdir $dir failed: $err"
+	ns_returnbadrequest "Could not create directory"
+    }
+    ns_returnok
+}
+
+
+#
+# _ns_options --
+#
+#   Handle the AOLpress OPTIONS request to return available functions.
+#   Note that LOCK and UNLOCK are not yet supported.
+#
+
+proc _ns_options {} {
+    set hdrs [ns_conn outputheaders]
+    ns_set put $hdrs Allow "OPTIONS, GET, HEAD, PUT, BROWSE, MKDIR"
+    ns_returnok
+}
+
+
+#
+# _ns_delete --
+#
+#   Handle the AOLpress DELETE request to delete a file
+#   or empty directory.  Note that deleting MiniWebs is
+#   not yet supported.
+#
+
+proc _ns_delete {} {
+    set url [ns_conn url]
+    set file [ns_url2file $url]
+    if ![file exists $file] {
+	return [ns_returnbadrequest "No Such File"]
+    }
+    if [catch {
+	if ![file isdir $file] {
+	    _ns_remove $file
+	} else {
+	    set dir $file
+	    if [_ns_ismw $dir] {
+		set nvd [_ns_getnvd $dir]
+		set tail [file tail $nvd]
+		set files($tail) 1
+		set pages 0
+		set fp [open $nvd]
+		while {[gets $fp line] >= 0} {
+		    if [string match Pages:* $line] {
+			set pages 1
+			break
+		    }
+		}
+		if $pages {
+		    while {[gets $fp line] >= 0} {
+			if ![regexp {^"} $line] break
+			set file [lindex [split $line \"] 1]
+			set files($file) 0
+		    }
+		}
+		close $fp
+		foreach file [glob -nocomplain $dir/*] {
+		    set tail [file tail $file]
+		    if ![info exists files($tail)] {
+			return [ns_returnbadrequest "Directory not empty"]
+		    }
+		    set files($tail) 1
+		}
+		foreach tail [array names files] {
+		    if $files($tail) {
+			_ns_remove $dir/$tail
+		    }
+		}
+	    }
+	    ns_rmdir $dir
+	}
+    } err] {
+	ns_log error "fastpath: delete $file failed: $err"
+	ns_returnbadrequest "Could not delete file"
+    }
+    ns_returnok
+}
+
+
+#
+# _ns_put --
+#
+#   Handle the AOLpress PUT request to save a file
+#   or MiniWeb.  The MiniWeb code is a bit tricky.
+#   Also, files are saved to tmp files and renamed
+#   to ensure half-written files don't become permanent
+#
+
+proc _ns_put {} {
+    set url [ns_conn url]
+    set file [ns_url2file $url]
+    set hdrs [ns_conn headers]
+    set isdir 0
+    set ismw 0
+    set exists [file exists $file]
+    set type [ns_set iget $hdrs content-type]
+
+    if {[ns_set ifind $hdrs x-navicreate] < 0} {
+	set create 0
+    } else {
+	set create 1
+    }
+
+    if {$create && $exists} {
+	return [ns_returnerror 500 "Already Exists"]
+    }
+    if $exists {
+	set isdir [file isdir $file]
+	if $isdir {
+	    set ismw [_ns_ismw $file]
+	}
+    }
+    if {$type == "application/x-naviwad"} {
+	if $exists {
+	    if !$ismw {
+		return [ns_returnerror 500 "not miniweb"]
+	    }
+	}
+	set ismw 1
+    } elseif {$exists && $isdir} {
+	return [ns_returnerror 500 "File is a directory"]
+    }
+
+    if [catch {
+	if $ismw {
+
+	    #
+	    # Create MiniWeb directory if necessary.
+	    #
+
+	    set dir $file
+	    if !$exists {
+		ns_mkdir $dir
+	    }
+
+	    #
+	    # Spool MiniWeb content in a tmp file.
+	    #
+
+	    set tmp [ns_tmpnam]
+	    set fp [open $tmp w+]
+	    fconfigure $fp -translation binary
+	    ns_conncptofp $fp
+
+	    #
+	    # Read the headers and save the content
+	    # for each included file.
+	    #
+
+	    seek $fp 0
+	    while {[gets $fp line] >= 0} {
+		set line [string trim $line]
+		if ![string length $line] {
+		    if {![info exists length] ||
+			![info exists name]} {
+			close $fp
+			return [ns_returnbadrequest]
+		    }
+		    set file $dir/$name
+		    set tmp2 [ns_mktemp $file.putXXXXXX]
+		    set fp2 [open $tmp2 w]
+		    ns_cpfp $fp $fp2 $length
+		    close $fp2
+		    ns_rename $tmp2 $file
+		    unset name
+		    unset length
+		} else {
+		    set kv [split $line :]
+		    set k [string trim [lindex $kv 0]]
+		    set v [string trim [lindex $kv 1]]
+		    switch [string tolower $k] {
+			content-name {
+			    set name $v
+			}
+			content-length {
+			    set length $v
+			}
+		    }
+		}
+	    }
+	    close $fp
+	    ns_unlink $tmp
+	} else {
+
+	    #
+	    # Save an ordinary file.
+	    #
+
+	    set tmp [ns_mktemp $file.putXXXXXX]
+	    set fp [open $tmp w]
+	    ns_conncptofp $fp
+	    close $fp
+	    ns_rename $tmp $file
+	}
+    } err] {
+	ns_log error "put: save $url failed: $err"
+	return [ns_returnerror 500 "Save failed"]
+    }
+    ns_returnok
+}
Index: mod_nsd/tcl_modules/util.tcl
===================================================================
RCS file: /usr/local/cvsroot/mod_nsd/tcl_modules/util.tcl,v
diff -u -r1.1 -r1.2
--- mod_nsd/tcl_modules/util.tcl	13 Apr 2001 21:09:32 -0000	1.1
+++ mod_nsd/tcl_modules/util.tcl	6 May 2001 18:54:01 -0000	1.2
@@ -383,3 +383,13 @@
 proc ns_updateheader {key value} {
     ns_set update [ns_conn outputheaders] $key $value
 }
+
+proc ns_returnnotice {status msg { longmsg "" } } {
+	ns_return $status text/html "<html>
+<body bgcolor=\"#ffffff\">
+<h1>$msg</h1>
+<p>$longmsg
+</body>
+</html>"
+}
+