Browse files

v1.3.3 add option to do hidden redirect to an index file in a directory

publish-directory arranges for a index file in a directory to be
returned when the uri specfies the directory name.  Normally aserve
returns a redirect to the index file which is then visible to the client.
There is now an option to simply return the contents of the index
file rather than do the redirect.

Are there user visible changes in this commit?  yes

Is bootstrapping needed?   no

Are tests included for new features?  yes

Tests run:  t-aserve

<release-note>
Changes to how directory entities return index files

First any uri from the client that refers to a directory on the disk
via a directory-entity will be changed (if necessary) to
end with a slash (/) via redirection.
Then the new hidden-index-redirect argument to publish-directory
will determine if a redirect is done to the index file or
if the contents of the index file are returned immediately.

</release-note>

<documentation>
 this change has been reflected in aserve.html (included with this
 commit).
</documentation>

Change-Id: I29ea111372fe0611ccd30960051262e122c1dfa4
  • Loading branch information...
1 parent 24cae48 commit 088bb41d5e97a01a143abb4cbeaeba4c1b9b0db4 John Foderaro committed Mar 9, 2011
Showing with 276 additions and 65 deletions.
  1. +78 −26 doc/aserve.html
  2. +8 −7 main.cl
  3. +51 −23 publish.cl
  4. +137 −9 test/t-aserve.cl
  5. +1 −0 test/testdir3/index.html
  6. +1 −0 test/testdir3/subdir/index.html
View
104 doc/aserve.html
@@ -36,7 +36,7 @@
</tbody>
</table>
<h1 align="center">AllegroServe - A Web Application Server<br>
-<small><small><small>version <font face="Courier New">1.3.1</font></small></small></small></h1>
+<small><small><small>version <font face="Courier New">1.3.3</font></small></small></small></h1>
<p align="left"><strong><small>copyright(c) 2000-2011. Franz Inc</small></strong></p>
<h2 align="left">Table of Contents</h2>
<p align="left"><a href="#introduction">Introduction</a><br>
@@ -257,6 +257,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
<strong>0 </strong>then the server runs in <em>simple server mode<strong>
</strong></em>in which the <strong>start</strong> function doesn't
return - instead it processes the requests itself, one at a time.&nbsp;
@@ -391,7 +392,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
in
a
fully
-patched ACL 8.0 (or newer).&nbsp;
+patched
+ACL 8.0 (or newer).&nbsp;
In older versions of ACL these values are ignored.&nbsp; By specifiying
these values you can have more control on how the server does SSL
certificate managment.<br>
@@ -434,7 +436,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
it
is
passed
-the request and is responsible for
+the
+request and is responsible for
generating and
sending a response to the client.&nbsp; If an entity can't be found
then AllegroServe
@@ -491,7 +494,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
class
preload
cache-p
-remove <br>
+remove
+<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
authorizer
server
@@ -512,7 +516,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
the
arguments
are
-optional..&nbsp; The arguments
+optional..&nbsp;
+The arguments
have these meanings: </p>
<ul>
<li><strong>path </strong>-- a string that must match the name part
@@ -544,6 +549,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</li>
<li><strong>preload</strong> --if true it instructs <strong>AllegroServe</strong>
to read the contents of the file in immediately and store it in a lisp
@@ -569,6 +575,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>This removes all entities, not just file entities.&nbsp;
If a <strong>host</strong> value is not passed in an argument, then
this will remove all entities for this <strong>path</strong>,
@@ -678,7 +685,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
hook
headers
-compress)</font></strong></p>
+compress
+hidden-index-redirect)</font></strong></p>
<p><strong>publish-directory</strong> is used to publish a complete
directory tree of
files.&nbsp; This is similar to how web servers such as Apache publish
@@ -720,12 +728,27 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
handle the request
in the normal manner.</p>
<p>If a request comes that maps to a directory rather than a file then
-AllegroServe tries
+AllegroServe takes special action.&nbsp; First AllegroServe ensures
+that the request uri ends in a slash. &nbsp; If the request was <span
+ style="text-decoration: underline;">http://foo.com/onedir/twodir</span>&nbsp;
+then AllegroServe will return a redirect response so the client now
+asks for <span style="text-decoration: underline;">http://foo.com/onedir/twodir/
+</span>.&nbsp; Next AllegroServe tries
to locate an index file for that directory.&nbsp; The <strong>indexes</strong>
argument
specifies a list of index files to search for.&nbsp; By default the
list consists of two
-filenames "index.html" and "index.htm".</p>
+filenames "index.html" and "index.htm".&nbsp; If an index file is found
+then the value of&nbsp; the<span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"> </span></span>hidden-index-redirect
+</span>argument is consulted.&nbsp; If it is nil then AllegroServe
+returns a redirect to the index file, e.g&nbsp; <span
+ style="text-decoration: underline;">http://foo.com/onedir/twodir/index.html</span>.<br>
+If <span style="font-weight: bold;">hidden-index-redirect</span> is
+true then AllegroServe will return the contents of the index file from
+the request, effectively doing the redirection to the index file
+internally and invisibly to the client.<br>
+</p>
<p>The value of the <strong>filter </strong>argument is a function of
four values: <strong>req</strong>
<strong>ent</strong>&nbsp; <strong>filename</strong> and <strong>info</strong>.&nbsp;
@@ -767,7 +790,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
disk
that
matches
-the incoming <strong>url</strong>.&nbsp;&nbsp;
+the
+incoming <strong>url</strong>.&nbsp;&nbsp;
Nomally
a
<strong>publish-file</strong>
@@ -995,7 +1019,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
argument
can
be
-a string or a list of
+a
+string or a list of
strings or nil
(which is the same as that argument not being given).<strong> </strong>&nbsp;
The
@@ -1007,7 +1032,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
are
not
exactly
-like unix shell wildcard
+like
+unix shell wildcard
filename
expressions).&nbsp;&nbsp; In particular <font face="Courier New">".*"</font>
is
@@ -1029,7 +1055,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
be
found
in
-the accumulated information, then
+the
+accumulated information, then
access is allowed.&nbsp;&nbsp; A similar thing is true if AllegroServe
is searching for <strong>:subdirectories</strong> information and none
is found.</li>
@@ -1081,7 +1108,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
its
response
every
-time a request comes in.&nbsp;
+time
+a request comes in.&nbsp;
The <strong>path</strong>,
<strong>host</strong>, <strong>port</strong>, <strong>remove, server</strong>
, <strong>authorizer,
@@ -1120,7 +1148,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
host
port
content-type
-function class <br>
+function
+class <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
format
remove
@@ -1140,7 +1169,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
handlers
have
lower
-priority than
+priority
+than
exact handlers.
&nbsp; Thus if you declare a prefix handler for "/foo" and also a
specific
@@ -1421,7 +1451,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
effect
on
the
-stream created.</em></p>
+stream
+created.</em></p>
<hr>
<p><a name="f-get-request-body"></a><strong><font face="Courier New">(get-request-body
request
@@ -1723,7 +1754,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
according
to
the
-CGI protocol.&nbsp; The
+CGI
+protocol.&nbsp; The
<strong>timeout</strong>
argument is how long AllegroServe should wait for a response from the <strong>program
</strong>before
@@ -1859,6 +1891,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>to turn it into an alist that associates form field
names with values.</li>
<li><strong>&lt;form method="post" enctype="multipart/form-data"&gt;
@@ -1943,6 +1976,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>is <strong>nil.</strong></li>
<li><strong>:data</strong> - the next multipart item is a simple form
value.&nbsp; The second value returned is a string naming the
@@ -1976,7 +2010,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
please
let
us
-know about it
+know
+about it
since we would like to enhance <strong>parse-multipart-header</strong>
to
understand this type of header. &nbsp;&nbsp; If you encounter
@@ -2226,6 +2261,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>where any of the listed name password pairs
will allow access to this page.</td>
</tr>
@@ -2305,6 +2341,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
the
+
<strong>ipaddress </strong>is a host
name and that host name cannot be translated to an IP address, then it
is assumed to match, and thus the request will be denied.&nbsp; </li>
@@ -2383,7 +2420,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
once.&nbsp;
Each
call
-will cause one Set-Cookie directive to be sent to the web browser.
+will
+cause one Set-Cookie directive to be sent to the web browser.
&nbsp;&nbsp;&nbsp;
The <strong>name</strong> and <strong>value</strong> arguments should
be given (and they
@@ -2523,7 +2561,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
threads
then
AllegroServe
-waits for one to be
+waits
+for one to be
available.</p>
<p>In each worker thread the variable <strong>*wserver*</strong> is
bound to the <strong>wserver</strong>
@@ -2599,7 +2638,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
locator
classes.&nbsp;&nbsp;&nbsp;
Locators
-should define
+should
+define
the <strong>standard-locator</strong>
method as well as </p>
<p><a name="f-unpublish-locator"></a><strong><font face="Courier New">(unpublish-locator
@@ -2635,6 +2675,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>to send back a response.</li>
<li><strong>:deny</strong> -- The request is denied and we want the
user to know that it was denied rather than sending a generic failed
@@ -2789,7 +2830,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
the
response
body
-in chunks if told to
+in
+chunks if told to
use the <strong>:http/1.1</strong> protocol.&nbsp; Buggy web servers
may do chunking incorrectly (even Apache has bugs in this regard but
we've worked around them).&nbsp; If you have trouble talking to a web
@@ -2836,6 +2878,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
a
+
<strong>:get</strong> then the value
of&nbsp; this argument is <strong>urlencoded</strong> and made the
query string of the uri being accessed.&nbsp; If the method is <strong>:post</strong>
@@ -2872,6 +2915,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>then if this argument is true (and, if an integer,
positive), <strong>do-http-request</strong> will call itself to access
the page to which the redirection is pointed.&nbsp; If <strong>redirect</strong>
@@ -3000,6 +3044,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong>argument need not be specified.</td>
</tr>
<tr>
@@ -3013,6 +3058,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
<a href="aserve.html#ssltls">SSL/TLS</a> for the use of this
argument.<br>
</td>
@@ -3029,6 +3075,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
passing
the
+
<strong>client-request </strong>object
as
an argument. &nbsp; At this point the client-request object contains
@@ -3609,6 +3656,7 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
+
</strong></li>
<li>the request-uri is still <strong>http://foo.bar.com:23/whatever </strong></li>
<li>the Host header value is still <strong>"foo.bar.com:23" </strong></li>
@@ -3777,7 +3825,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
clear:
it
means
-that this entity will be visible on this
+that
+this entity will be visible on this
virtual host.
&nbsp; The meaning of <strong>:wild </strong>is that this entity will
be visible on <em>all</em>
@@ -3973,7 +4022,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
only
meaningful
value
-you would want to pass is <span style="font-weight: bold;">:tlsv1</span>
+you
+would want to pass is <span style="font-weight: bold;">:tlsv1</span>
meaning that you only want to
communicate using TLS v1.0 (SSL v3.1), the most modern and secure of
the protocols.<br>
@@ -4097,7 +4147,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
a
right
click
-as well. </p>
+as
+well. </p>
<p>&nbsp;</p>
<hr>
<h2><a name="international-chars-aserve"></a>Using International
@@ -4220,7 +4271,8 @@ <h2 align="left">In<a name="introduction"></a>troduction</h2>
to
write
web
-pages that can use
+pages
+that can use
characters
from nearly every
language in the world (whether the web browser can find the glyphs to
View
15 main.cl
@@ -38,7 +38,7 @@
#+ignore
(check-smp-consistency)
-(defparameter *aserve-version* '(1 3 2))
+(defparameter *aserve-version* '(1 3 3))
(eval-when (eval load)
(require :sock)
@@ -515,8 +515,8 @@ Problems with protocol may occur." (ef-name ef)))))
(,g-external-format (find-external-format ,external-format))
)
(declare (ignore-if-unused ,g-req ,g-ent ,g-external-format))
- ,(if* body
- then `(compute-response-stream ,g-req ,g-ent))
+
+ (compute-response-stream ,g-req ,g-ent)
(if* (entity-headers ,g-ent)
then (bulk-set-reply-headers ,g-req (entity-headers ,g-ent)))
(if* ,g-headers
@@ -1252,9 +1252,10 @@ by keyword symbols and not by strings"
else "")
cond))
(top-level.debug:zoom
- (vhost-error-stream
- (wserver-default-vhost
- *wserver*)))
+ (or (vhost-error-stream
+ (wserver-default-vhost
+ *wserver*))
+ *initial-terminal-io*))
(if* (not (member :notrap *debug-current*))
then ; after the zoom ignore the error
(go out))
@@ -1266,7 +1267,7 @@ by keyword symbols and not by strings"
(if* (connection-reset-error cond)
thenret ; don't print these errors,
else (logmess
- (format nil "~agot error ~a~%"
+ (format nil "~agot the error ~a~%"
(if* *worker-request*
then (format
nil
View
74 publish.cl
@@ -194,10 +194,14 @@
; it should create and publish an entity and return it
(publisher :initarg :publisher
:initform nil
- :accessor directory-entity-publisher))
+ :accessor directory-entity-publisher)
- )
+ (hidden-index-redirect
+ :initform nil
+ :initarg :hidden-index-redirect
+ :reader directory-hidden-index-redirect)
+ ))
(defclass special-entity (entity)
@@ -888,6 +892,7 @@
hook
headers
(compress t)
+ hidden-index-redirect
)
;; make a whole directory available
@@ -922,6 +927,7 @@
:hook hook
:headers headers
:compress compress
+ :hidden-index-redirect hidden-index-redirect
)))
(publish-prefix-entity ent prefix locator host host-p nil)
@@ -1677,13 +1683,14 @@
;; entity for it so we can track last modified.
(let* ((postfix nil)
+ (path (request-decoded-uri-path req))
(realname (concatenate 'string
directory
- (setq postfix (subseq (request-decoded-uri-path req)
- (length (prefix ent))))))
+ (setq postfix (subseq path (length (prefix ent))))))
(redir-to)
(info)
(forbidden)
+ (redirect-kind *response-temporary-redirect*)
)
(debug-format :info "directory request for ~s~%" realname)
@@ -1729,16 +1736,36 @@
elseif (eq :directory type)
then ; Try the indexes (index.html, index.htm, or user-defined).
; tack on a trailing slash if there isn't one already.
- (if* (not (eq #\/ (schar realname (1- (length realname)))))
- then (setq realname (concatenate 'string realname "/")))
-
- (setf redir-to
- (dolist (index (directory-entity-indexes ent)
- ; no match to index file, give up
- (return-from process-entity-single-directory nil))
- (if* (eq :file (excl::filesys-type
- (concatenate 'string realname index)))
- then (return index))))
+
+ (if* (not (eq #\/ (schar path (1- (length path)))))
+ then ; uri referred to a a directory but didn't end
+ ; in a slash, so add that slash
+ (setq redirect-kind
+ *response-moved-permanently*)
+
+ (setf redir-to
+ "" ; tack on a empty string
+ )
+ else ; uri ends in /, realname is directory
+ ; ensure path we're building ends in / so
+ ; we can look for indexes
+ (if* (not (eq #\/
+ (schar realname (1- (length realname)))))
+ then (setq realname
+ (concatenate 'string realname "/")))
+ (dolist (index (directory-entity-indexes ent)
+ ; no match to index file, give up
+ (return-from process-entity-single-directory nil))
+ (if* (eq :file (excl::filesys-type
+ (concatenate 'string realname index)))
+ then ; we have an index
+ (if* (directory-hidden-index-redirect ent)
+ then ; just send back the index file contents
+ (setq realname
+ (concatenate 'string realname index))
+ else ; redirect to the index file
+ (setq redir-to index))
+ (return))))
elseif (not (eq :file type))
then ; bizarre object
@@ -1747,22 +1774,23 @@
(if* redir-to
then ; redirect to an existing index file
(with-http-response (req ent
- :response *response-temporary-redirect*)
+ :response redirect-kind)
(let ((path (uri-path (request-uri req))))
(setf (reply-header-slot-value req :location)
(render-uri
(copy-uri (request-uri req)
:path
- (concatenate 'string path
- (if* (and path
- (> (length path) 0)
- (eq #\/ (aref path
- (1- (length path)))))
- then ""
- else "/")
- redir-to))
+ (concatenate
+ 'string path
+ (if* (and path
+ (> (length path) 0)
+ (eq #\/ (aref path
+ (1- (length path)))))
+ then ""
+ else "/")
+ redir-to))
nil))
(with-http-body (req ent))))
View
146 test/t-aserve.cl
@@ -50,10 +50,16 @@
(error "Could not find the aserve examples directory.")))
)
+(defparameter *aserve-set-full-debug* nil) ; :all and :notrap are useful
+(net.aserve::debug-on *aserve-set-full-debug*)
+
; to trap errors when they happen uncomment this
-;(setq util.test:*break-on-test-failures* t
-; util.test:*error-protect-tests* nil)
-;(net.aserve::debug-on t)
+#+ignore
+(setq util.test:*break-on-test-failures* t
+ util.test:*error-protect-tests* nil)
+
+
+
; set to nil before loading the test to prevent the test from auto-running
(defvar user::*do-aserve-test* t)
@@ -99,11 +105,13 @@
(do-tests-inner))))
(do-tests-inner ()
+
(test-publish-file port nil) ; no compression
#+unix
(test-publish-file port t) ; with compression
(test-publish-directory port)
+
(test-publish-computed port)
(test-publish-multi port)
(test-publish-prefix port)
@@ -118,7 +126,10 @@
then (test-international port)
(test-spr27296))
(if* test-timeouts
- then (test-timeouts port)))
+ then (test-timeouts port))
+
+
+ )
)
(format t "~%~%===== test direct ~%~%")
@@ -166,6 +177,7 @@
:listeners 20 ; so keep-alive will be possible
))); let the system pick a port
(setq *wserver* wserver)
+ (net.aserve::debug-on *aserve-set-full-debug*)
(unpublish :all t) ; flush anything published
(setq *x-ssl* ssl)
(socket::local-port (net.aserve::wserver-socket wserver))
@@ -184,6 +196,9 @@
:proxy t
:proxy-proxy *x-proxy*))
+ (let ((*wserver* *proxy-wserver*))
+ (net.aserve::debug-on *aserve-set-full-debug*))
+
(push *x-proxy* *save-x-proxy*)
(setq *x-proxy* (format nil "localhost:~d"
(socket:local-port
@@ -1413,9 +1428,9 @@
(publish-directory :prefix "/test-pd/"
:destination test-dir
:hook #'(lambda (req ent extra)
- (declare (ignore req ent extra))
- (setq got-reps (or got-reps 0))
- (incf got-reps))
+ (declare (ignore req ent extra))
+ (setq got-reps (or got-reps 0))
+ (incf got-reps))
:headers '(("testvdir" . "testvval"))
:filter #'(lambda (req ent filename info)
(declare (ignore ent info))
@@ -1444,8 +1459,8 @@
(declare (ignore body))
(test 200 code)
(test "testvval"
- (cdr (assoc "testvdir" headers :test #'equal))
- :test #'equal))
+ (cdr (assoc "testvdir" headers :test #'equal))
+ :test #'equal))
(test 1 got-reps) ; hook fired
@@ -1602,6 +1617,119 @@
(test 200 (values2 (x-do-http-request
(format nil "~a/multiple-test/second.txt"
prefix-local))))
+
+ ;;
+ ;; test redirects to the index file
+ ;;
+ (publish-directory :prefix "/redirnormal/"
+ :destination
+ (concatenate 'string test-dir "testdir3/"))
+
+ ; do a normal redirect to the index
+
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirnormal/"
+ prefix-local))
+ (declare (ignore headers))
+ (test (file-contents
+ (concatenate 'string test-dir "testdir3/index.html"))
+ body
+ :test #'equal
+ )
+ (test 200 retcode)
+ (test "/redirnormal/index.html"
+ (net.uri:uri-path uri)
+ :test #'equal
+ ))
+
+ ; do one directory level down redirect
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirnormal/subdir"
+ prefix-local))
+ (declare (ignore headers))
+ (test (file-contents
+ (concatenate 'string test-dir "testdir3/subdir/index.html"))
+ body
+ :test #'equal
+ )
+ (test 200 retcode)
+ (test "/redirnormal/subdir/index.html"
+ (net.uri:uri-path uri)
+ :test #'equal
+ ))
+
+ ; check that the first step of a uri not ending in /
+ ; is to add the /
+
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirnormal/subdir"
+ prefix-local)
+ :redirect nil ; don't auto redirect
+ )
+
+ (declare (ignore body uri))
+ (test 301 retcode)
+ (test t (values (match-re "/redirnormal/subdir/$"
+ (cdr (assoc :location headers))))))
+
+
+ ; test where an internal redirect is done
+ (publish-directory :prefix "/redirhidden/"
+ :destination
+ (concatenate 'string test-dir "testdir3/")
+
+ :hidden-index-redirect t
+ )
+
+ ; simple
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirhidden/"
+ prefix-local))
+ (declare (ignore headers))
+ (test (file-contents
+ (concatenate 'string test-dir "testdir3/index.html"))
+ body
+ :test #'equal
+ )
+ (test 200 retcode)
+ (test "/redirhidden/"
+ (net.uri:uri-path uri)
+ :test #'equal
+ ))
+
+ ; one level down
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirhidden/subdir"
+ prefix-local))
+ (declare (ignore headers))
+ (test (file-contents
+ (concatenate 'string test-dir "testdir3/subdir/index.html"))
+ body
+ :test #'equal
+ )
+ (test 200 retcode)
+ (test "/redirhidden/subdir/"
+ (net.uri:uri-path uri)
+ :test #'equal
+ ))
+
+ ; one step one level done
+ (multiple-value-bind (body retcode headers uri)
+ (x-do-http-request
+ (format nil "~a/redirhidden/subdir"
+ prefix-local)
+ :redirect nil ; don't auto redirect
+ )
+
+ (declare (ignore body uri))
+ (test 301 retcode)
+ (test t (values (match-re "/redirhidden/subdir/$"
+ (cdr (assoc :location headers))))))
))
View
1 test/testdir3/index.html
@@ -0,0 +1 @@
+<html><body>topfile</body></html>
View
1 test/testdir3/subdir/index.html
@@ -0,0 +1 @@
+<html><body>innerfile</body></html>

0 comments on commit 088bb41

Please sign in to comment.