]> source.dussan.org Git - archiva.git/blob
07b58c5bb6cc67e5242d50848e4cb0f074d68bdc
[archiva.git] /
1 package org.apache.maven.archiva.web.repository;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import org.apache.maven.archiva.model.ArtifactReference;
23 import org.apache.maven.archiva.model.ProjectReference;
24 import org.apache.maven.archiva.model.VersionedReference;
25 import org.apache.maven.archiva.proxy.ProxyException;
26 import org.apache.maven.archiva.proxy.RepositoryProxyConnectors;
27 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
28 import org.apache.maven.archiva.repository.RepositoryContentFactory;
29 import org.apache.maven.archiva.repository.RepositoryException;
30 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
31 import org.apache.maven.archiva.repository.content.RepositoryRequest;
32 import org.apache.maven.archiva.repository.layout.LayoutException;
33 import org.apache.maven.archiva.repository.metadata.MetadataTools;
34 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
35 import org.apache.maven.model.DistributionManagement;
36 import org.apache.maven.model.Model;
37 import org.apache.maven.model.Relocation;
38 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
39 import org.codehaus.plexus.webdav.AbstractDavServerComponent;
40 import org.codehaus.plexus.webdav.DavServerComponent;
41 import org.codehaus.plexus.webdav.DavServerException;
42 import org.codehaus.plexus.webdav.servlet.DavServerRequest;
43 import org.codehaus.plexus.webdav.util.WebdavMethodUtil;
44
45 import java.io.File;
46 import java.io.FileNotFoundException;
47 import java.io.FileReader;
48 import java.io.IOException;
49 import java.io.PrintWriter;
50
51 import javax.servlet.ServletConfig;
52 import javax.servlet.ServletException;
53 import javax.servlet.http.HttpServletResponse;
54
55 /**
56  * ProxiedDavServer
57  *
58  * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
59  * @version $Id$
60  * @plexus.component role="org.codehaus.plexus.webdav.DavServerComponent"
61  * role-hint="proxied" instantiation-strategy="per-lookup"
62  */
63 public class ProxiedDavServer
64     extends AbstractDavServerComponent
65 {
66     /**
67      * @plexus.requirement role-hint="simple"
68      */
69     private DavServerComponent davServer;
70
71     /**
72      * @plexus.requirement
73      */
74     private RepositoryContentFactory repositoryFactory;
75
76     /**
77      * @plexus.requirement
78      */
79     private RepositoryRequest repositoryRequest;
80
81     /**
82      * @plexus.requirement role-hint="default"
83      */
84     private RepositoryProxyConnectors connectors;
85
86     /**
87      * @plexus.requirement
88      */
89     private MetadataTools metadataTools;
90
91     private ManagedRepositoryContent managedRepository;
92
93     public String getPrefix()
94     {
95         return davServer.getPrefix();
96     }
97
98     public File getRootDirectory()
99     {
100         return davServer.getRootDirectory();
101     }
102
103     public void setPrefix( String prefix )
104     {
105         davServer.setPrefix( prefix );
106     }
107
108     public void setRootDirectory( File rootDirectory )
109     {
110         davServer.setRootDirectory( rootDirectory );
111     }
112
113     public void init( ServletConfig servletConfig )
114         throws DavServerException
115     {
116         davServer.init( servletConfig );
117
118         try
119         {
120             managedRepository = repositoryFactory.getManagedRepositoryContent( getPrefix() );
121         }
122         catch ( RepositoryNotFoundException e )
123         {
124             throw new DavServerException( e.getMessage(), e );
125         }
126         catch ( RepositoryException e )
127         {
128             throw new DavServerException( e.getMessage(), e );
129         }
130     }
131
132     public void process( DavServerRequest request, HttpServletResponse response )
133         throws DavServerException, ServletException, IOException
134     {
135         if ( WebdavMethodUtil.isReadMethod( request.getRequest().getMethod() ) )
136         {
137             fetchContentFromProxies( request );
138         }
139         else
140         {
141             /* Create parent directories that don't exist when writing a file
142              * This actually makes this implementation not compliant to the
143              * WebDAV RFC - but we have enough knowledge
144              * about how the collection is being used to do this reasonably and
145              * some versions of Maven's WebDAV don't
146              * correctly create the collections themselves.
147              */
148
149             File rootDirectory = getRootDirectory();
150             if ( rootDirectory != null )
151             {
152                 new File( rootDirectory, request.getLogicalResource() ).getParentFile().mkdirs();
153             }
154         }
155
156         // [MRM-503] - Metadata file need Pragma:no-cache response header.
157         if ( request.getLogicalResource().endsWith( "/maven-metadata.xml" ) )
158         {
159             response.addHeader( "Pragma", "no-cache" );
160             response.addHeader( "Cache-Control", "no-cache" );
161         }
162
163         // TODO: [MRM-524] determine http caching options for other types of files (artifacts, sha1, md5, snapshots)
164
165         if( resourceExists( request ) )
166         {
167             davServer.process( request, response );
168         }
169         else
170         {
171             respondResourceMissing( request, response );
172         }
173     }
174
175     private void respondResourceMissing( DavServerRequest request, HttpServletResponse response )
176     {
177         response.setStatus( HttpServletResponse.SC_NOT_FOUND );
178
179         try
180         {
181             StringBuffer missingUrl = new StringBuffer();
182             missingUrl.append( request.getRequest().getScheme() ).append( "://" );
183             missingUrl.append( request.getRequest().getServerName() ).append( ":" );
184             missingUrl.append( request.getRequest().getServerPort() );
185             missingUrl.append( request.getRequest().getServletPath() );
186             // missingUrl.append( request.getRequest().getPathInfo() );
187
188             String message = "Error 404 Not Found";
189
190             PrintWriter out = new PrintWriter( response.getOutputStream() );
191
192             response.setContentType( "text/html; charset=\"UTF-8\"" );
193
194             out.println( "<html>" );
195             out.println( "<head><title>" + message + "</title></head>" );
196             out.println( "<body>" );
197
198             out.print( "<p><h1>" );
199             out.print( message );
200             out.println( "</h1></p>" );
201
202             out.print( "<p>The following resource does not exist: <a href=\"" );
203             out.print( missingUrl.toString() );
204             out.println( "\">" );
205             out.print( missingUrl.toString() );
206             out.println( "</a></p>" );
207
208             out.println( "</body></html>" );
209
210             out.flush();
211         }
212         catch ( IOException e )
213         {
214             e.printStackTrace();
215         }
216     }
217
218     private boolean resourceExists( DavServerRequest request )
219     {
220         String resource = request.getLogicalResource();
221         File resourceFile = new File( managedRepository.getRepoRoot(), resource );
222         return resourceFile.exists();
223     }
224
225     private void fetchContentFromProxies( DavServerRequest request )
226         throws ServletException
227     {
228         String resource = request.getLogicalResource();
229         
230         // Cleanup bad requests from maven 1.
231         // Often seen is a double slash.
232         // example: http://hostname:8080/archiva/repository/internal//pmd/jars/pmd-3.0.jar
233         if ( resource.startsWith( "/" ) )
234         {
235             resource = resource.substring( 1 );
236         }
237
238         if ( resource.endsWith( ".sha1" ) || resource.endsWith( ".md5" ) )
239         {
240             // Checksums are fetched with artifact / metadata.
241             return;
242         }
243
244         // Is it a Metadata resource?
245         if ( resource.endsWith( "/" + MetadataTools.MAVEN_METADATA ) )
246         {
247             ProjectReference project;
248             VersionedReference versioned;
249
250             try
251             {
252
253                 versioned = metadataTools.toVersionedReference( resource );
254                 if ( versioned != null )
255                 {
256                     connectors.fetchFromProxies( managedRepository, versioned );
257                     request.getRequest().setPathInfo( metadataTools.toPath( versioned ) );
258                     return;
259                 }
260             }
261             catch ( RepositoryMetadataException e )
262             {
263                 /* eat it */
264             }
265             catch ( ProxyException e )
266             {
267                 throw new ServletException( "Unable to fetch versioned metadata resource.", e );
268             }
269
270             try
271             {
272                 project = metadataTools.toProjectReference( resource );
273                 if ( project != null )
274                 {
275                     connectors.fetchFromProxies( managedRepository, project );
276                     request.getRequest().setPathInfo( metadataTools.toPath( project ) );
277                 }
278             }
279             catch ( RepositoryMetadataException e )
280             {
281                 /* eat it */
282             }
283             catch ( ProxyException e )
284             {
285                 throw new ServletException( "Unable to fetch project metadata resource.", e );
286             }
287         }
288
289         // Not any of the above? Then it's gotta be an artifact reference.
290         try
291         {
292             // Get the artifact reference in a layout neutral way.
293             ArtifactReference artifact = repositoryRequest.toArtifactReference( resource );
294             
295             if ( artifact != null )
296             {
297                 applyServerSideRelocation( artifact );
298
299                 connectors.fetchFromProxies( managedRepository, artifact );
300                 
301                 // Set the path to the resource using managed repository specific layout format.
302                 request.getRequest().setPathInfo( managedRepository.toPath( artifact ) );
303                 return;
304             }
305         }
306         catch ( LayoutException e )
307         {
308             /* eat it */
309         }
310         catch ( ProxyException e )
311         {
312             throw new ServletException( "Unable to fetch artifact resource.", e );
313         }
314     }
315
316     /**
317      * A relocation capable client will request the POM prior to the artifact,
318      * and will then read meta-data and do client side relocation. A simplier
319      * client (like maven 1) will only request the artifact and not use the
320      * metadatas.
321      * <p>
322      * For such clients, archiva does server-side relocation by reading itself
323      * the &lt;relocation&gt; element in metadatas and serving the expected
324      * artifact.
325      */
326     protected void applyServerSideRelocation( ArtifactReference artifact )
327         throws ProxyException
328     {
329         if ( "pom".equals( artifact.getType() ) )
330         {
331             return;
332         }
333
334         // Build the artifact POM reference
335         ArtifactReference pomReference = new ArtifactReference();
336         pomReference.setGroupId( artifact.getGroupId() );
337         pomReference.setArtifactId( artifact.getArtifactId() );
338         pomReference.setVersion( artifact.getVersion() );
339         pomReference.setType( "pom" );
340
341         // Get the artifact POM from proxied repositories if needed
342         connectors.fetchFromProxies( managedRepository, pomReference );
343
344         // Open and read the POM from the managed repo
345         File pom = managedRepository.toFile( pomReference );
346         try
347         {
348             Model model = new MavenXpp3Reader().read( new FileReader( pom ) );
349             DistributionManagement dist = model.getDistributionManagement();
350             if ( dist != null )
351             {
352                 Relocation relocation = dist.getRelocation();
353                 if ( relocation != null )
354                 {
355                     // artifact is relocated : update the repositoryPath
356                     if ( relocation.getGroupId() != null )
357                     {
358                         artifact.setGroupId( relocation.getGroupId() );
359                     }
360                     if ( relocation.getArtifactId() != null )
361                     {
362                         artifact.setArtifactId( relocation.getArtifactId() );
363                     }
364                     if ( relocation.getVersion() != null )
365                     {
366                         artifact.setVersion( relocation.getVersion() );
367                     }
368                 }
369             }
370         }
371         catch ( FileNotFoundException e )
372         {
373             // Artifact has no POM in repo : ignore
374         }
375         catch ( Exception e )
376         {
377             // invalid POM : ignore
378         }
379     }
380
381     public ManagedRepositoryContent getRepository()
382     {
383         return managedRepository;
384     }
385 }