You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by jo...@apache.org on 2007/10/24 02:16:41 UTC

svn commit: r587708 - in /maven/archiva/trunk/archiva-web/archiva-webapp/src: main/java/org/apache/maven/archiva/web/repository/ main/resources/org/codehaus/ main/resources/org/codehaus/plexus/ main/resources/org/codehaus/plexus/webdav/ main/resources/...

Author: joakime
Date: Tue Oct 23 17:16:40 2007
New Revision: 587708

URL: http://svn.apache.org/viewvc?rev=587708&view=rev
Log:
[MRM-565] Archiva 1.0-beta-3 fails in 404 on all legacy request.
Using new methods in RepositoryRequest to identify native resource path early and using it.
Adding PolicingServletRequest to deal with bad formatted request paths.
Beefing up RepositoryServletTest to test proxy-less (for now) requests ...
* Browse
* Get Checksum (default layout)
* Get Checksum (legacy layout)
* Get Metadata (versioned + default layout)
* Get Metadata (project + default layout)
* Get Artifact (default layout)
Adding custom mime-types.txt to get proper "Content-Type" headers on GET requests.


Added:
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java   (with props)
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt   (with props)
    maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml   (with props)
Modified:
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java
    maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java
    maven/archiva/trunk/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java
    maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml

Added: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java?rev=587708&view=auto
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java (added)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java Tue Oct 23 17:16:40 2007
@@ -0,0 +1,69 @@
+package org.apache.maven.archiva.web.repository;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.plexus.util.FileUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+/**
+ * PolicingServletRequest is for policing the incoming request for naughty bits, such as a double slashes,
+ * or paths that include "/../" type syntax, or query string.  Stripping out all things that are 
+ * not appropriate. 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
+public class PolicingServletRequest
+    extends HttpServletRequestWrapper
+    implements HttpServletRequest
+{
+    private String fixedPathInfo;
+
+    public PolicingServletRequest( HttpServletRequest originalRequest )
+    {
+        super( originalRequest );
+
+        fixedPathInfo = originalRequest.getPathInfo();
+
+        if ( StringUtils.isNotBlank( fixedPathInfo ) )
+        {
+            /* Perform a simple security normalization of the requested pathinfo.
+             * This is to cleanup requests that use "/../" or "///" type hacks.
+             */
+            fixedPathInfo = FileUtils.normalize( fixedPathInfo );
+        }
+    }
+
+    @Override
+    public String getPathInfo()
+    {
+        return fixedPathInfo;
+    }
+
+    @Override
+    public String getQueryString()
+    {
+        // No query string allowed.
+        return null;
+    }
+}

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java?rev=587708&r1=587707&r2=587708&view=diff
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java (original)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java Tue Oct 23 17:16:40 2007
@@ -138,29 +138,46 @@
         
         if ( isGet )
         {
-            fetchContentFromProxies( request );
-        }
+            // Default behaviour is to treat the resource natively.
+            String resource = request.getLogicalResource();
+            File resourceFile = new File( managedRepository.getRepoRoot(), resource );
 
-        if ( isPut )
-        {
-            /* Create parent directories that don't exist when writing a file
-             * This actually makes this implementation not compliant to the
-             * WebDAV RFC - but we have enough knowledge
-             * about how the collection is being used to do this reasonably and
-             * some versions of Maven's WebDAV don't
-             * correctly create the collections themselves.
-             */
+            // If this a directory resource, then we are likely browsing.
+            if ( resourceFile.exists() && resourceFile.isDirectory() )
+            {
+                // TODO: [MRM-440] - If webdav URL lacks a trailing /, navigating to all links in the listing return 404.
+                // TODO: Issue redirect with proper pathing.
+                
+                // Process the request.
+                davServer.process( request, response );
+                
+                // All done.
+                return;
+            }
 
-            File rootDirectory = getRootDirectory();
-            if ( rootDirectory != null )
+            // At this point the incoming request can either be in default or legacy layout format.
+            try
             {
-                new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
+                // Perform an adjustment of the resource to the managed repository expected path.
+                resource = repositoryRequest.toNativePath( request.getLogicalResource(), managedRepository );
+                resourceFile = new File( managedRepository.getRepoRoot(), resource );
+
+                // Adjust the pathInfo resource to be in the format that the dav server impl expects.
+                request.getRequest().setPathInfo( resource );
+
+                // Attempt to fetch the resource from any defined proxy.
+                fetchContentFromProxies( request, resource );
             }
-        }
+            catch ( LayoutException e )
+            {
+                // Invalid resource, pass it on.
+                respondResourceMissing( request, response, e );
 
-        if ( isGet )
-        {
-            if ( resourceExists( request ) )
+                // All done.
+                return;
+            }
+
+            if ( resourceFile.exists() )
             {
                 // [MRM-503] - Metadata file need Pragma:no-cache response header.
                 if ( request.getLogicalResource().endsWith( "/maven-metadata.xml" ) )
@@ -175,17 +192,35 @@
             }
             else
             {
-                respondResourceMissing( request, response );
+                respondResourceMissing( request, response, null );
             }
         }
 
         if ( isPut )
         {
+            /* Create parent directories that don't exist when writing a file
+             * This actually makes this implementation not compliant to the
+             * WebDAV RFC - but we have enough knowledge
+             * about how the collection is being used to do this reasonably and
+             * some versions of Maven's WebDAV don't
+             * correctly create the collections themselves.
+             */
+
+            File rootDirectory = getRootDirectory();
+            if ( rootDirectory != null )
+            {
+                new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
+            }
+            
+            // Allow the dav server to process the put request.
             davServer.process( request, response );
+            
+            // All done.
+            return;
         }
     }
 
-    private void respondResourceMissing( DavServerRequest request, HttpServletResponse response )
+    private void respondResourceMissing( DavServerRequest request, HttpServletResponse response, Throwable t )
     {
         response.setStatus( HttpServletResponse.SC_NOT_FOUND );
 
@@ -196,7 +231,6 @@
             missingUrl.append( request.getRequest().getServerName() ).append( ":" );
             missingUrl.append( request.getRequest().getServerPort() );
             missingUrl.append( request.getRequest().getServletPath() );
-            // missingUrl.append( request.getRequest().getPathInfo() );
 
             String message = "Error 404 Not Found";
 
@@ -217,6 +251,13 @@
             out.println( "\">" );
             out.print( missingUrl.toString() );
             out.println( "</a></p>" );
+            
+            if ( t != null )
+            {
+                out.println( "<pre>" );
+                t.printStackTrace( out );
+                out.println( "</pre>" );
+            }
 
             out.println( "</body></html>" );
 
@@ -228,74 +269,23 @@
         }
     }
 
-    private boolean resourceExists( DavServerRequest request )
-    {
-        String resource = request.getLogicalResource();
-        File resourceFile = new File( managedRepository.getRepoRoot(), resource );
-        return resourceFile.exists();
-    }
-
-    private void fetchContentFromProxies( DavServerRequest request )
+    private void fetchContentFromProxies( DavServerRequest request, String resource )
         throws ServletException
     {
-        String resource = request.getLogicalResource();
-        
-        // Cleanup bad requests from maven 1.
-        // Often seen is a double slash.
-        // example: http://hostname:8080/archiva/repository/internal//pmd/jars/pmd-3.0.jar
-        if ( resource.startsWith( "/" ) )
-        {
-            resource = resource.substring( 1 );
-        }
-
-        if ( resource.endsWith( ".sha1" ) || resource.endsWith( ".md5" ) )
+        if ( repositoryRequest.isSupportFile( resource ) )
         {
             // Checksums are fetched with artifact / metadata.
+            
+            // Need to adjust the path for the checksum resource.
             return;
         }
 
         // Is it a Metadata resource?
-        if ( resource.endsWith( "/" + MetadataTools.MAVEN_METADATA ) )
+        if ( repositoryRequest.isDefault( resource ) && repositoryRequest.isMetadata( resource ) )
         {
-            ProjectReference project;
-            VersionedReference versioned;
-
-            try
-            {
-
-                versioned = metadataTools.toVersionedReference( resource );
-                if ( versioned != null )
-                {
-                    connectors.fetchFromProxies( managedRepository, versioned );
-                    request.getRequest().setPathInfo( metadataTools.toPath( versioned ) );
-                    return;
-                }
-            }
-            catch ( RepositoryMetadataException e )
-            {
-                /* eat it */
-            }
-            catch ( ProxyException e )
-            {
-                throw new ServletException( "Unable to fetch versioned metadata resource.", e );
-            }
-
-            try
+            if ( fetchMetadataFromProxies( request, resource ) )
             {
-                project = metadataTools.toProjectReference( resource );
-                if ( project != null )
-                {
-                    connectors.fetchFromProxies( managedRepository, project );
-                    request.getRequest().setPathInfo( metadataTools.toPath( project ) );
-                }
-            }
-            catch ( RepositoryMetadataException e )
-            {
-                /* eat it */
-            }
-            catch ( ProxyException e )
-            {
-                throw new ServletException( "Unable to fetch project metadata resource.", e );
+                return;
             }
         }
 
@@ -326,6 +316,52 @@
         }
     }
 
+    private boolean fetchMetadataFromProxies( DavServerRequest request, String resource )
+        throws ServletException
+    {
+        ProjectReference project;
+        VersionedReference versioned;
+
+        try
+        {
+
+            versioned = metadataTools.toVersionedReference( resource );
+            if ( versioned != null )
+            {
+                connectors.fetchFromProxies( managedRepository, versioned );
+                return true;
+            }
+        }
+        catch ( RepositoryMetadataException e )
+        {
+            /* eat it */
+        }
+        catch ( ProxyException e )
+        {
+            throw new ServletException( "Unable to fetch versioned metadata resource.", e );
+        }
+
+        try
+        {
+            project = metadataTools.toProjectReference( resource );
+            if ( project != null )
+            {
+                connectors.fetchFromProxies( managedRepository, project );
+                return true;
+            }
+        }
+        catch ( RepositoryMetadataException e )
+        {
+            /* eat it */
+        }
+        catch ( ProxyException e )
+        {
+            throw new ServletException( "Unable to fetch project metadata resource.", e );
+        }
+        
+        return false;
+    }
+
     /**
      * A relocation capable client will request the POM prior to the artifact,
      * and will then read meta-data and do client side relocation. A simplier
@@ -399,6 +435,13 @@
         {
             // Invalid POM : ignore
         }
+    }
+    
+    @Override
+    public void setUseIndexHtml( boolean useIndexHtml )
+    {
+        super.setUseIndexHtml( useIndexHtml );
+        davServer.setUseIndexHtml( useIndexHtml );
     }
 
     public ManagedRepositoryContent getRepository()

Modified: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java?rev=587708&r1=587707&r2=587708&view=diff
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java (original)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java Tue Oct 23 17:16:40 2007
@@ -103,8 +103,17 @@
 
             DavServerComponent server = createServer( repo.getId(), repoDir, servletConfig );
 
+            server.setUseIndexHtml( true );
             server.addListener( audit );
         }
+    }
+    
+    @Override
+    protected void service( HttpServletRequest httpRequest, HttpServletResponse httpResponse )
+        throws ServletException, IOException
+    {
+        // Wrap the incoming request to adjust paths and whatnot.
+        super.service( new PolicingServletRequest( httpRequest ), httpResponse );
     }
 
     public synchronized ManagedRepositoryConfiguration getRepository( String prefix )

Added: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt?rev=587708&view=auto
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt (added)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt Tue Oct 23 17:16:40 2007
@@ -0,0 +1,129 @@
+# This is a comment. I love comments.
+
+# This file controls what Internet media types are sent to the client for
+# given file extension(s). Sending the correct media type to the client
+# is important so they know how to handle the content of the file.
+# Extra types can either be added here or by using an AddType directive
+# in your config files. For more information about Internet media types,
+# please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type
+# registry is at <http://www.iana.org/assignments/media-types/>.
+
+# MIME type                              Extensions
+
+application/andrew-inset                 ez
+application/atom+xml                     atom
+application/mac-binhex40                 hqx
+application/mac-compactpro               cpt
+application/mathml+xml                   mathml
+application/msword                       doc
+application/octet-stream                 bin dms lha lzh exe class so dll dmg
+application/oda                          oda
+application/ogg                          ogg
+application/pdf                          pdf
+application/pgp-encrypted				 pgp
+application/postscript                   ai eps ps
+application/rdf+xml                      rdf
+application/smil                         smi smil
+application/srgs                         gram
+application/srgs+xml                     grxml
+application/vnd.mif                      mif
+application/vnd.mozilla.xul+xml          xul
+application/vnd.ms-excel                 xls
+application/vnd.ms-powerpoint            ppt
+application/vnd.rn-realmedia             rm
+application/vnd.wap.wbxml                wbxml
+application/vnd.wap.wmlc                 wmlc
+application/vnd.wap.wmlscriptc           wmlsc
+application/voicexml+xml                 vxml
+application/x-bcpio                      bcpio
+application/x-cdlink                     vcd
+application/x-chess-pgn                  pgn
+application/x-cpio                       cpio
+application/x-csh                        csh
+application/x-director                   dcr dir dxr
+application/x-dvi                        dvi
+application/x-futuresplash               spl
+application/x-gtar                       gtar
+application/x-hdf                        hdf
+application/x-jar                        jar
+application/x-java-jnlp-file             jnlp
+application/x-javascript                 js
+application/x-koan                       skp skd skt skm
+application/x-latex                      latex
+application/x-netcdf                     nc cdf
+application/x-sh                         sh
+application/x-shar                       shar
+application/x-shockwave-flash            swf
+application/x-stuffit                    sit
+application/x-sv4cpio                    sv4cpio
+application/x-sv4crc                     sv4crc
+application/x-tar                        tar
+application/x-tcl                        tcl
+application/x-tex                        tex
+application/x-texinfo                    texinfo texi
+application/x-troff                      t tr roff
+application/x-troff-man                  man
+application/x-troff-me                   me
+application/x-troff-ms                   ms
+application/x-ustar                      ustar
+application/x-wais-source                src
+application/xhtml+xml                    xhtml xht
+application/xml                          xml xsl
+application/xml-dtd                      dtd
+application/xslt+xml                     xslt
+application/zip                          zip
+audio/basic                              au snd
+audio/midi                               mid midi kar
+audio/mpeg                               mpga mp2 mp3
+audio/x-aiff                             aif aiff aifc
+audio/x-mpegurl                          m3u
+audio/x-pn-realaudio                     ram ra
+audio/x-wav                              wav
+chemical/x-pdb                           pdb
+chemical/x-xyz                           xyz
+image/bmp                                bmp
+image/cgm                                cgm
+image/gif                                gif
+image/ief                                ief
+image/jp2                                jp2
+image/jpeg                               jpeg jpg jpe
+image/pict                               pict pic pct
+image/png                                png
+image/svg+xml                            svg
+image/tiff                               tiff tif
+image/vnd.djvu                           djvu djv
+image/vnd.wap.wbmp                       wbmp
+image/x-cmu-raster                       ras
+image/x-icon                             ico
+image/x-macpaint                         pntg pnt mac
+image/x-portable-anymap                  pnm
+image/x-portable-bitmap                  pbm
+image/x-portable-graymap                 pgm
+image/x-portable-pixmap                  ppm
+image/x-quicktime                        qtif qti
+image/x-rgb                              rgb
+image/x-xbitmap                          xbm
+image/x-xpixmap                          xpm
+image/x-xwindowdump                      xwd
+model/iges                               igs iges
+model/mesh                               msh mesh silo
+model/vrml                               wrl vrml
+text/calendar                            ics ifb
+text/css                                 css
+text/html                                html htm
+text/plain                               asc txt sha1 md5
+text/richtext                            rtx
+text/rtf                                 rtf
+text/sgml                                sgml sgm
+text/tab-separated-values                tsv
+text/vnd.wap.wml                         wml
+text/vnd.wap.wmlscript                   wmls
+text/x-setext                            etx
+video/mp4                                mp4
+video/mpeg                               mpeg mpg mpe
+video/quicktime                          qt mov
+video/vnd.mpegurl                        mxu m4u
+video/x-dv                               dv dif
+video/x-msvideo                          avi
+video/x-sgi-movie                        movie
+x-conference/x-cooltalk                  ice

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java?rev=587708&r1=587707&r2=587708&view=diff
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java (original)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java Tue Oct 23 17:16:40 2007
@@ -19,26 +19,36 @@
  * under the License.
  */
 
+import com.meterware.httpunit.GetMethodWebRequest;
 import com.meterware.httpunit.PutMethodWebRequest;
+import com.meterware.httpunit.WebLink;
 import com.meterware.httpunit.WebRequest;
 import com.meterware.httpunit.WebResponse;
 import com.meterware.servletunit.ServletRunner;
 import com.meterware.servletunit.ServletUnitClient;
+
+import org.apache.commons.io.FileUtils;
 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
 import org.apache.maven.archiva.configuration.Configuration;
-import org.apache.maven.archiva.configuration.ConfigurationEvent;
-import org.apache.maven.archiva.configuration.IndeterminateConfigurationException;
 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
+import org.apache.maven.archiva.configuration.RemoteRepositoryConfiguration;
 import org.codehaus.plexus.PlexusConstants;
 import org.codehaus.plexus.PlexusTestCase;
-import org.codehaus.plexus.registry.RegistryException;
-import org.codehaus.plexus.util.FileUtils;
-import org.xml.sax.SAXException;
+import org.codehaus.plexus.webdav.util.MimeTypes;
 
-import javax.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * RepositoryServletTest 
+ *
+ * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
+ * @version $Id$
+ */
 public class RepositoryServletTest
     extends PlexusTestCase
 {
@@ -61,61 +71,66 @@
     {
         super.setUp();
 
-        // TODO: purely to quiet logging - shouldn't be needed
         String appserverBase = getTestFile( "target/appserver-base" ).getAbsolutePath();
         System.setProperty( "appserver.base", appserverBase );
 
-        configuration = (ArchivaConfiguration) lookup( ArchivaConfiguration.ROLE );
+        File testConf = getTestFile( "src/test/resources/repository-archiva.xml" );
+        File testConfDest = new File( appserverBase, "conf/archiva.xml" );
+        FileUtils.copyFile( testConf, testConfDest );
 
+        configuration = (ArchivaConfiguration) lookup( ArchivaConfiguration.ROLE );
         repositoryLocation = new File( appserverBase, "data/repositories/internal" );
+        Configuration config = configuration.getConfiguration();
+
+        config.addManagedRepository( createManagedRepository( "internal", "Internal Test Repo", repositoryLocation ) );
+        saveConfiguration();
 
         ServletRunner sr = new ServletRunner();
         sr.registerServlet( "/repository/*", UnauthenticatedRepositoryServlet.class.getName() );
         sc = sr.newClient();
-        sc.getSession( true ).getServletContext().setAttribute( PlexusConstants.PLEXUS_KEY, getContainer() );
+        HttpSession session = sc.getSession( true );
+        ServletContext servletContext = session.getServletContext();
+        servletContext.setAttribute( PlexusConstants.PLEXUS_KEY, getContainer() );
     }
 
     public void testPutWithMissingParentCollection()
-        throws IOException, SAXException
+        throws Exception
     {
         FileUtils.deleteDirectory( repositoryLocation );
 
         WebRequest request = new PutMethodWebRequest( REQUEST_PATH, getClass().getResourceAsStream( "/artifact.jar" ),
                                                       "application/octet-stream" );
         WebResponse response = sc.getResponse( request );
-        assertNotNull( "No response received", response );
-        assertEquals( "file contents", "artifact.jar\n",
-                      FileUtils.fileRead( new File( repositoryLocation, "path/to/artifact.jar" ) ) );
+        assertNotNull( "Should have received response", response );
+        assertEquals( "file contents", "artifact.jar\n", FileUtils
+            .readFileToString( new File( repositoryLocation, "path/to/artifact.jar" ), null ) );
     }
 
     public void testGetRepository()
-        throws IOException, ServletException
+        throws Exception
     {
         RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
         assertNotNull( servlet );
 
-        ManagedRepositoryConfiguration repository = servlet.getRepository( REPOSITORY_ID );
-        assertNotNull( repository );
-        assertEquals( "Archiva Managed Internal Repository", repository.getName() );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
     }
 
     public void testGetRepositoryAfterDelete()
-        throws IOException, ServletException, RegistryException, IndeterminateConfigurationException
+        throws Exception
     {
         RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
         assertNotNull( servlet );
 
         Configuration c = configuration.getConfiguration();
         c.removeManagedRepository( c.findManagedRepositoryById( REPOSITORY_ID ) );
-        // TODO it would be better to use a mock configuration and "save" to more accurately reflect the calls made
-        servlet.configurationEvent( new ConfigurationEvent( ConfigurationEvent.SAVED) );
+        saveConfiguration();
 
         ManagedRepositoryConfiguration repository = servlet.getRepository( REPOSITORY_ID );
         assertNull( repository );
     }
 
     public void testGetRepositoryAfterAdd()
-        throws IOException, ServletException, RegistryException, IndeterminateConfigurationException
+        throws Exception
     {
         RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
         assertNotNull( servlet );
@@ -131,16 +146,221 @@
         }
         repo.setLocation( repoRoot.getAbsolutePath() );
         c.addManagedRepository( repo );
-        // TODO it would be better to use a mock configuration and "save" to more accurately reflect the calls made
-        servlet.configurationEvent( new ConfigurationEvent( ConfigurationEvent.SAVED) );
+        saveConfiguration();
 
         ManagedRepositoryConfiguration repository = servlet.getRepository( NEW_REPOSITORY_ID );
         assertNotNull( repository );
         assertEquals( NEW_REPOSITORY_NAME, repository.getName() );
 
         // check other is still intact
-        repository = servlet.getRepository( REPOSITORY_ID );
-        assertNotNull( repository );
-        assertEquals( "Archiva Managed Internal Repository", repository.getName() );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+    }
+
+    public void testBrowse()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        new File( repositoryLocation, "org/apache/archiva" ).mkdirs();
+        new File( repositoryLocation, "net/sourceforge" ).mkdirs();
+        new File( repositoryLocation, "commons-lang" ).mkdirs();
+
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        // dumpResponse( response );
+
+        WebLink links[] = response.getLinks();
+        String expectedLinks[] = new String[] { "./commons-lang/", "./net/", "./org/", "./path/" };
+
+        assertEquals( "Links.length", expectedLinks.length, links.length );
+        for ( int i = 0; i < links.length; i++ )
+        {
+            assertEquals( "Link[" + i + "]", expectedLinks[i], links[i].getURLString() );
+        }
+    }
+
+    public void testGetNoProxyChecksumDefaultLayout()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        String commonsLangSha1 = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar.sha1";
+
+        File checksumFile = new File( repositoryLocation, commonsLangSha1 );
+        checksumFile.getParentFile().mkdirs();
+
+        FileUtils.writeStringToFile( checksumFile, "dummy-checksum", null );
+        
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangSha1 );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response OK", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        assertEquals( "Expected file contents", "dummy-checksum", response.getText() );
+    }
+    
+    public void testGetNoProxyChecksumLegacyLayout()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        String commonsLangSha1 = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar.sha1";
+
+        File checksumFile = new File( repositoryLocation, commonsLangSha1 );
+        checksumFile.getParentFile().mkdirs();
+
+        FileUtils.writeStringToFile( checksumFile, "dummy-checksum", null );
+
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + 
+                                                      "commons-lang/jars/commons-lang-2.1.jar.sha1" );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response OK", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        assertEquals( "Expected file contents", "dummy-checksum", response.getText() );
+    }
+    
+    public void testGetNoProxyVersionedMetadataDefaultLayout()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        String commonsLangMetadata = "commons-lang/commons-lang/2.1/maven-metadata.xml";
+        String expectedMetadataContents = "dummy-versioned-metadata";
+
+        File metadataFile = new File( repositoryLocation, commonsLangMetadata );
+        metadataFile.getParentFile().mkdirs();
+
+        FileUtils.writeStringToFile( metadataFile, expectedMetadataContents, null );
+
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangMetadata );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response OK", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        assertEquals( "Expected file contents", expectedMetadataContents, response.getText() );
+    }
+    
+    public void testGetNoProxyProjectMetadataDefaultLayout()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        String commonsLangMetadata = "commons-lang/commons-lang/maven-metadata.xml";
+        String expectedMetadataContents = "dummy-project-metadata";
+
+        File metadataFile = new File( repositoryLocation, commonsLangMetadata );
+        metadataFile.getParentFile().mkdirs();
+
+        FileUtils.writeStringToFile( metadataFile, expectedMetadataContents, null );
+
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangMetadata );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response OK", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        assertEquals( "Expected file contents", expectedMetadataContents, response.getText() );
+    }
+    
+    public void testGetNoProxyArtifactDefaultLayout()
+        throws Exception
+    {
+        RepositoryServlet servlet = (RepositoryServlet) sc.newInvocation( REQUEST_PATH ).getServlet();
+        assertNotNull( servlet );
+        assertRepositoryValid( servlet, REPOSITORY_ID );
+
+        String commonsLangJar = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar";
+        String expectedArtifactContents = "dummy-commons-lang-artifact";
+
+        File artifactFile = new File( repositoryLocation, commonsLangJar );
+        artifactFile.getParentFile().mkdirs();
+
+        FileUtils.writeStringToFile( artifactFile, expectedArtifactContents, null );
+
+        WebRequest request = new GetMethodWebRequest( "http://machine.com/repository/internal/" + commonsLangJar );
+        WebResponse response = sc.getResponse( request );
+        assertEquals( "Response OK", HttpServletResponse.SC_OK, response.getResponseCode() );
+
+        assertEquals( "Expected file contents", expectedArtifactContents, response.getText() );
+    }
+    
+    public void testMimeTypesAvailable()
+        throws Exception
+    {
+        MimeTypes mimeTypes = (MimeTypes) lookup( MimeTypes.class );
+        assertNotNull( mimeTypes );
+        
+        // Test for some added types.
+        assertEquals( "sha1", "text/plain", mimeTypes.getMimeType( "foo.sha1" ) );
+        assertEquals( "md5", "text/plain", mimeTypes.getMimeType( "foo.md5" ) );
+        assertEquals( "pgp", "application/pgp-encrypted", mimeTypes.getMimeType( "foo.pgp" ) );
+    }
+
+    private void dumpResponse( WebResponse response )
+    {
+        System.out.println( "---(response)---" );
+        System.out.println( "" + response.getResponseCode() + " " + response.getResponseMessage() );
+
+        String headerNames[] = response.getHeaderFieldNames();
+        for ( String headerName : headerNames )
+        {
+            System.out.println( "[header] " + headerName + ": " + response.getHeaderField( headerName ) );
+        }
+
+        System.out.println( "---(text)---" );
+        try
+        {
+            System.out.println( response.getText() );
+        }
+        catch ( IOException e )
+        {
+            System.err.print( "[Exception] : " );
+            e.printStackTrace( System.err );
+        }
+    }
+
+    private void assertRepositoryValid( RepositoryServlet servlet, String repoId )
+    {
+        ManagedRepositoryConfiguration repository = servlet.getRepository( repoId );
+        assertNotNull( "Archiva Managed Repository id:<" + repoId + "> should exist.", repository );
+        File repoRoot = new File( repository.getLocation() );
+        assertTrue( "Archiva Managed Repository id:<" + repoId + "> should have a valid location on disk.", repoRoot
+            .exists()
+            && repoRoot.isDirectory() );
+    }
+
+    private void saveConfiguration()
+        throws Exception
+    {
+        configuration.save( configuration.getConfiguration() );
+        // TODO it would be better to use a mock configuration and "save" to more accurately reflect the calls made
+        // RepositoryServlet servlet
+        // servlet.configurationEvent( new ConfigurationEvent( ConfigurationEvent.SAVED ) );
+    }
+
+    private ManagedRepositoryConfiguration createManagedRepository( String id, String name, File location )
+    {
+        ManagedRepositoryConfiguration repo = new ManagedRepositoryConfiguration();
+        repo.setId( id );
+        repo.setName( name );
+        repo.setLocation( location.getAbsolutePath() );
+        return repo;
+    }
+
+    private RemoteRepositoryConfiguration createRemoteRepository( String id, String name, String url )
+    {
+        RemoteRepositoryConfiguration repo = new RemoteRepositoryConfiguration();
+        repo.setId( id );
+        repo.setName( name );
+        repo.setUrl( url );
+        return repo;
     }
 }

Modified: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml?rev=587708&r1=587707&r2=587708&view=diff
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml (original)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml Tue Oct 23 17:16:40 2007
@@ -29,15 +29,64 @@
       <lifecycle-handler>basic</lifecycle-handler>
     </component>
 
+    <!--
+     | Configuration
+     -->
+    <component>
+      <role>org.apache.maven.archiva.configuration.ArchivaConfiguration</role>
+      <implementation>org.apache.maven.archiva.configuration.DefaultArchivaConfiguration</implementation>
+      <requirements>
+        <requirement>
+          <role>org.codehaus.plexus.registry.Registry</role>
+          <role-hint>configured</role-hint>
+        </requirement>
+      </requirements>
+    </component>
+    <component>
+      <role>org.codehaus.plexus.registry.Registry</role>
+      <role-hint>configured</role-hint>
+      <implementation>org.codehaus.plexus.registry.commons.CommonsConfigurationRegistry</implementation>
+      <configuration>
+        <properties>
+          <system/>
+          <xml fileName="${appserver.base}/conf/archiva.xml"
+               config-name="org.apache.maven.archiva.base" config-at="org.apache.maven.archiva"/>
+        </properties>
+      </configuration>
+    </component>
+    
     <component>
       <role>org.codehaus.plexus.webdav.DavServerManager</role>
       <role-hint>default</role-hint>
       <implementation>org.codehaus.plexus.webdav.DefaultDavServerManager</implementation>
+      <description>DefaultDavServerManager</description>
       <configuration>
         <provider-hint>proxied</provider-hint>
       </configuration>
     </component>
-
+    
+    <component>
+      <role>org.codehaus.plexus.cache.Cache</role>
+      <role-hint>url-failures-cache</role-hint>
+      <implementation>org.codehaus.plexus.cache.ehcache.EhcacheCache</implementation>
+      <description>URL Failure Cache</description>
+      <configuration>
+        <disk-expiry-thread-interval-seconds>600</disk-expiry-thread-interval-seconds>
+        <disk-persistent>false</disk-persistent> <!--disabling disk persistence for unit testing. -->
+        <disk-store-path>${java.io.tmpdir}/archiva/urlcache</disk-store-path>
+        <eternal>false</eternal>
+        <max-elements-in-memory>1000</max-elements-in-memory>
+        <memory-eviction-policy>LRU</memory-eviction-policy>
+        <name>url-failures-cache</name>
+        <overflow-to-disk>false</overflow-to-disk>
+        <!-- 45 minutes = 2700 seconds -->
+        <time-to-idle-seconds>2700</time-to-idle-seconds>
+        <!-- 30 minutes = 1800 seconds  -->
+        <time-to-live-seconds>1800</time-to-live-seconds>
+      </configuration>
+    </component>    
+    
+    
     <!-- Don't drag in the world just to test this -->
     <component>
       <role>org.apache.maven.archiva.repository.scanner.RepositoryContentConsumers</role>

Added: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml
URL: http://svn.apache.org/viewvc/maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml?rev=587708&view=auto
==============================================================================
--- maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml (added)
+++ maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml Tue Oct 23 17:16:40 2007
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<configuration>
+
+  <version>2</version>
+  
+  <repositoryScanning>
+    <fileTypes>
+      <fileType>
+        <id>artifacts</id>
+        <patterns>
+          <pattern>**/*.pom</pattern>
+          <pattern>**/*.jar</pattern>
+          <pattern>**/*.ear</pattern>
+          <pattern>**/*.war</pattern>
+          <pattern>**/*.car</pattern>
+          <pattern>**/*.sar</pattern>
+          <pattern>**/*.mar</pattern>
+          <pattern>**/*.rar</pattern>
+          <pattern>**/*.dtd</pattern>
+          <pattern>**/*.tld</pattern>
+          <pattern>**/*.tar.gz</pattern>
+          <pattern>**/*.tar.bz2</pattern>
+          <pattern>**/*.zip</pattern>
+        </patterns>
+      </fileType>
+      <fileType>
+        <id>indexable-content</id>
+        <patterns>
+          <pattern>**/*.txt</pattern>
+          <pattern>**/*.TXT</pattern>
+          <pattern>**/*.block</pattern>
+          <pattern>**/*.config</pattern>
+          <pattern>**/*.pom</pattern>
+          <pattern>**/*.xml</pattern>
+          <pattern>**/*.xsd</pattern>
+          <pattern>**/*.dtd</pattern>
+          <pattern>**/*.tld</pattern>
+        </patterns>
+      </fileType>
+      <fileType>
+        <id>auto-remove</id>
+        <patterns>
+          <pattern>**/*.bak</pattern>
+          <pattern>**/*~</pattern>
+          <pattern>**/*-</pattern>
+        </patterns>
+      </fileType>
+      <fileType>
+        <id>ignored</id>
+        <patterns>
+          <pattern>**/.htaccess</pattern>
+          <pattern>**/KEYS</pattern>
+          <pattern>**/*.rb</pattern>
+          <pattern>**/*.sh</pattern>
+          <pattern>**/.svn/**</pattern>
+          <pattern>**/.DAV/**</pattern>
+        </patterns>
+      </fileType>
+    </fileTypes>
+    <knownContentConsumers>
+      <knownContentConsumer>update-db-artifact</knownContentConsumer>
+      <knownContentConsumer>create-missing-checksums</knownContentConsumer>
+      <knownContentConsumer>update-db-repository-metadata</knownContentConsumer>
+      <knownContentConsumer>validate-checksum</knownContentConsumer>
+      <knownContentConsumer>validate-signature</knownContentConsumer>
+      <knownContentConsumer>index-content</knownContentConsumer>
+      <knownContentConsumer>auto-remove</knownContentConsumer>
+      <knownContentConsumer>auto-rename</knownContentConsumer>
+    </knownContentConsumers>
+    <invalidContentConsumers>
+      <invalidContentConsumer>update-db-bad-content</invalidContentConsumer>
+    </invalidContentConsumers>
+  </repositoryScanning>
+
+  <databaseScanning>
+    <cronExpression>0 0 * * ?</cronExpression>
+    <unprocessedConsumers>
+      <unprocessedConsumer>index-artifact</unprocessedConsumer>
+      <unprocessedConsumer>update-db-project</unprocessedConsumer>
+      <unprocessedConsumer>validate-repository-metadata</unprocessedConsumer>
+      <unprocessedConsumer>index-archive-toc</unprocessedConsumer>
+      <unprocessedConsumer>update-db-bytecode-stats</unprocessedConsumer>
+      <unprocessedConsumer>index-public-methods</unprocessedConsumer>
+    </unprocessedConsumers>
+    <cleanupConsumers>
+      <cleanupConsumer>not-present-remove-db-artifact</cleanupConsumer>
+      <cleanupConsumer>not-present-remove-db-project</cleanupConsumer>
+      <cleanupConsumer>not-present-remove-indexed</cleanupConsumer>
+    </cleanupConsumers>
+  </databaseScanning>
+
+</configuration>

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Propchange: maven/archiva/trunk/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml