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