]> source.dussan.org Git - archiva.git/commitdiff
[MRM-565] Archiva 1.0-beta-3 fails in 404 on all legacy request.
authorJoakim Erdfelt <joakime@apache.org>
Wed, 24 Oct 2007 00:16:40 +0000 (00:16 +0000)
committerJoakim Erdfelt <joakime@apache.org>
Wed, 24 Oct 2007 00:16:40 +0000 (00:16 +0000)
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.

git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/trunk@587708 13f79535-47bb-0310-9956-ffa450edef68

archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java [new file with mode: 0644]
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/ProxiedDavServer.java
archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/RepositoryServlet.java
archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt [new file with mode: 0644]
archiva-web/archiva-webapp/src/test/java/org/apache/maven/archiva/web/repository/RepositoryServletTest.java
archiva-web/archiva-webapp/src/test/resources/org/apache/maven/archiva/web/repository/RepositoryServletTest.xml
archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml [new file with mode: 0644]

diff --git a/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java b/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/repository/PolicingServletRequest.java
new file mode 100644 (file)
index 0000000..0076988
--- /dev/null
@@ -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;
+    }
+}
index 7dedee43b4eb9c9a2f243fce6b732ef2ef15d9fa..bdf8fa97f880b9ffe2461b2b6fd79c6f7a60ccff 100644 (file)
@@ -138,29 +138,46 @@ public class ProxiedDavServer
         
         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 @@ public class ProxiedDavServer
             }
             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 @@ public class ProxiedDavServer
             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 @@ public class ProxiedDavServer
             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 @@ public class ProxiedDavServer
         }
     }
 
-    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 )
+            if ( fetchMetadataFromProxies( request, resource ) )
             {
-                throw new ServletException( "Unable to fetch versioned metadata resource.", e );
-            }
-
-            try
-            {
-                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 @@ public class ProxiedDavServer
         }
     }
 
+    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
@@ -400,6 +436,13 @@ public class ProxiedDavServer
             // Invalid POM : ignore
         }
     }
+    
+    @Override
+    public void setUseIndexHtml( boolean useIndexHtml )
+    {
+        super.setUseIndexHtml( useIndexHtml );
+        davServer.setUseIndexHtml( useIndexHtml );
+    }
 
     public ManagedRepositoryContent getRepository()
     {
index 28856ef6f0a9a680abfb38969ecadd0ae856481b..9bd9596e6b6fcba4d68b26f5aaed7ebbc73bd25d 100644 (file)
@@ -103,9 +103,18 @@ public class RepositoryServlet
 
             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 )
     {
diff --git a/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt b/archiva-web/archiva-webapp/src/main/resources/org/codehaus/plexus/webdav/util/mime-types.txt
new file mode 100644 (file)
index 0000000..3c58035
--- /dev/null
@@ -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
index 604e2b4323790d03a4e687f437c9321e8de1a9b2..c0b24cee5254262c10518e313d54c6fea4efad70 100644 (file)
@@ -19,26 +19,36 @@ package org.apache.maven.archiva.web.repository;
  * 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 @@ public class RepositoryServletTest
     {
         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 @@ public class RepositoryServletTest
         }
         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;
     }
 }
index 5356abb87f568871659d0b464dbb964b53727f23..beccf43c939d8fd98fe846206393be24826887e6 100644 (file)
       <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>
diff --git a/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml b/archiva-web/archiva-webapp/src/test/resources/repository-archiva.xml
new file mode 100644 (file)
index 0000000..f642851
--- /dev/null
@@ -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>