Skip to content

Commit 2079b71

Browse files
ruhan1jdcasey
authored andcommitted
Apply maven ContentsFilteringTransfer and NPM PackageMaskingTransfer decorators
1 parent 1aecc47 commit 2079b71

25 files changed

Lines changed: 1565 additions & 82 deletions

File tree

addons/httprox/ftests/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
<artifactId>http-testserver</artifactId>
6161
<scope>provided</scope>
6262
</dependency>
63+
<dependency>
64+
<groupId>org.commonjava.maven.galley</groupId>
65+
<artifactId>galley-maven</artifactId>
66+
</dependency>
6367
<dependency>
6468
<groupId>junit</groupId>
6569
<artifactId>junit</artifactId>

addons/pkg-maven/common/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@
8181
<artifactId>galley-test-harness-core</artifactId>
8282
<scope>test</scope>
8383
</dependency>
84+
<dependency>
85+
<groupId>org.commonjava.indy</groupId>
86+
<artifactId>indy-test-fixtures-core</artifactId>
87+
<scope>test</scope>
88+
</dependency>
8489
<dependency>
8590
<groupId>org.commonjava.maven.galley</groupId>
8691
<artifactId>galley-test-harness-maven</artifactId>
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/**
2+
* Copyright (C) 2013 Red Hat, Inc. (nos-devel@redhat.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.commonjava.indy.pkg.maven.content;
17+
18+
import java.io.FilterOutputStream;
19+
import java.io.IOException;
20+
import java.io.OutputStream;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
import java.util.regex.Matcher;
24+
import java.util.regex.Pattern;
25+
26+
import javax.enterprise.context.ApplicationScoped;
27+
28+
import org.apache.commons.lang.StringUtils;
29+
import org.commonjava.atlas.maven.ident.util.SnapshotUtils;
30+
import org.commonjava.atlas.maven.ident.version.part.SnapshotPart;
31+
import org.commonjava.maven.galley.event.EventMetadata;
32+
import org.commonjava.maven.galley.io.AbstractTransferDecorator;
33+
import org.commonjava.maven.galley.model.Location;
34+
import org.commonjava.maven.galley.model.Transfer;
35+
import org.commonjava.maven.galley.model.TransferOperation;
36+
import org.commonjava.maven.galley.io.OverriddenBooleanValue;
37+
import org.commonjava.maven.galley.transport.htcli.model.HttpLocation;
38+
import org.commonjava.maven.galley.util.TransferUtils;
39+
import org.slf4j.Logger;
40+
import org.slf4j.LoggerFactory;
41+
42+
/**
43+
* Represents a decorator responsible for filtering out location contents based on location settings. Effectively it is
44+
* designed to filter out snapshot or release versions from remote repositories when configured to not
45+
* provide the snapshot or release versions.
46+
*
47+
* @author pkocandr
48+
*/
49+
@ApplicationScoped
50+
public class MavenContentsFilteringTransferDecorator
51+
extends AbstractTransferDecorator
52+
{
53+
private final Logger logger = LoggerFactory.getLogger( this.getClass() );
54+
55+
@Override
56+
public OverriddenBooleanValue decorateExists( final Transfer transfer, final EventMetadata metadata )
57+
{
58+
final Location loc = transfer.getLocation();
59+
final boolean isHttp = loc instanceof HttpLocation;
60+
final boolean filtered = TransferUtils.filterTransfer( transfer );
61+
if ( isHttp && filtered )
62+
{
63+
return OverriddenBooleanValue.OVERRIDE_FALSE;
64+
}
65+
return OverriddenBooleanValue.DEFER;
66+
}
67+
68+
@Override
69+
public OutputStream decorateWrite( final OutputStream stream, final Transfer transfer, final TransferOperation op,
70+
final EventMetadata metadata ) throws IOException
71+
{
72+
final Location loc = transfer.getLocation();
73+
final boolean allowsSnapshots = loc.allowsSnapshots();
74+
final boolean allowsReleases = loc.allowsReleases();
75+
if ( loc instanceof HttpLocation && ( !allowsSnapshots || !allowsReleases ) && transfer.getFullPath()
76+
.endsWith( "maven-metadata.xml" ) )
77+
{
78+
return new MetadataFilteringOutputStream( stream, allowsSnapshots, allowsReleases, transfer );
79+
}
80+
else
81+
{
82+
return stream;
83+
}
84+
}
85+
86+
/**
87+
* Alters the listing to filter out artifacts belonging to a version that
88+
* should not be provided via the proxy.
89+
*/
90+
@Override
91+
public String[] decorateListing( final Transfer transfer, final String[] listing, final EventMetadata metadata )
92+
throws IOException
93+
{
94+
final Location loc = transfer.getLocation();
95+
final boolean allowsSnapshots = loc.allowsSnapshots();
96+
final boolean allowsReleases = loc.allowsReleases();
97+
98+
// process only proxied locations, i.e. HttpLocation instances
99+
if ( loc instanceof HttpLocation && ( !allowsSnapshots || !allowsReleases ) )
100+
{
101+
final String[] pathElements = transfer.getPath().split( "/" );
102+
// process only paths that *can* be a GAV
103+
if ( pathElements.length >= 3 )
104+
{
105+
final String artifactId = pathElements[pathElements.length - 2];
106+
final String version = pathElements[pathElements.length - 1];
107+
final boolean snapshotVersion = SnapshotUtils.isSnapshotVersion( version );
108+
// NOS-1434 Forbid all snapshot files if allowSnapshots not enabled
109+
if ( ( allowsSnapshots && snapshotVersion ) || ( allowsReleases && !snapshotVersion ) )
110+
{
111+
return listing;
112+
}
113+
return new String[0];
114+
}
115+
else
116+
{
117+
// process paths that does not contain version.
118+
// if list element contains snapshot folder, ignore them.
119+
if ( !allowsSnapshots )
120+
{
121+
final List<String> result = new ArrayList<>( listing.length );
122+
for ( final String element : listing )
123+
{
124+
String version = element;
125+
if ( element.endsWith( "/" ) )
126+
{
127+
version = element.substring( 0, version.length() - 1 );
128+
}
129+
if ( !SnapshotUtils.isSnapshotVersion( version ) )
130+
{
131+
result.add( element );
132+
}
133+
}
134+
return result.toArray( new String[0] );
135+
}
136+
}
137+
}
138+
return listing;
139+
}
140+
141+
/**
142+
* Checks if the given element is an artifact. Artifacts always starts with
143+
* &lt;artifactId&gt;-&lt;version&gt;.
144+
*/
145+
private boolean isArtifact( final String element, final String artifactId, final String version )
146+
{
147+
if ( element.endsWith( "/" ) )
148+
{
149+
return false;
150+
}
151+
152+
boolean isRemoteSnapshot = false;
153+
if ( SnapshotUtils.isSnapshotVersion( version ) && element.startsWith( artifactId + '-' )
154+
&& !element.startsWith( artifactId + '-' + version ) )
155+
{
156+
final SnapshotPart snapshotPart = SnapshotUtils.extractSnapshotVersionPart( version );
157+
final int artIdLenght = artifactId.length() + 1 + version.length() - snapshotPart.getLiteral().length() + 1;
158+
isRemoteSnapshot = SnapshotUtils.isRemoteSnapshotVersionPart(
159+
StringUtils.substring( element, artIdLenght, artIdLenght + 17 ) );
160+
}
161+
162+
return element.startsWith( artifactId + '-' + version + '-' ) || element.startsWith(
163+
artifactId + '-' + version + '.' ) || isRemoteSnapshot;
164+
}
165+
166+
private static class MetadataFilteringOutputStream
167+
extends FilterOutputStream
168+
{
169+
private final Logger logger = LoggerFactory.getLogger( this.getClass() );
170+
171+
private static final String LATEST = "<latest>([^<]+)</latest>";
172+
173+
private static final String RELEASE = "<release>([^<]+)</release>";
174+
175+
private static final String VERSION = "<version>([^<]+)</version>";
176+
177+
private static final String VERSIONS = "<versions>[\\s]*(?:(" + VERSION + ")[\\s]*)+</versions>";
178+
179+
private StringBuilder buffer = new StringBuilder();
180+
181+
private final boolean allowsSnapshots;
182+
183+
private final boolean allowsReleases;
184+
185+
private Transfer transfer;
186+
187+
private MetadataFilteringOutputStream( final OutputStream stream, final boolean allowsSnapshots,
188+
final boolean allowsReleases, Transfer transfer )
189+
{
190+
super( stream );
191+
this.allowsSnapshots = allowsSnapshots;
192+
this.allowsReleases = allowsReleases;
193+
this.transfer = transfer;
194+
}
195+
196+
private String filterMetadata()
197+
{
198+
199+
if ( buffer.length() == 0 )
200+
{
201+
return "";
202+
}
203+
204+
// filter versions from GA metadata
205+
final Pattern versionsPattern = Pattern.compile( VERSIONS, Pattern.MULTILINE );
206+
final Matcher m = versionsPattern.matcher( buffer );
207+
final List<String> versions = new ArrayList<>();
208+
if ( m.find() )
209+
{
210+
final Pattern versionPattern = Pattern.compile( VERSION );
211+
final Matcher versionMatcher = versionPattern.matcher( m.group() );
212+
while ( versionMatcher.find() )
213+
{
214+
versions.add( versionMatcher.group( 1 ) );
215+
}
216+
}
217+
218+
boolean changed = false;
219+
for ( final String version : new ArrayList<>( versions ) )
220+
{
221+
final boolean isSnapshot = SnapshotUtils.isSnapshotVersion( version );
222+
if ( !allowsSnapshots && isSnapshot || !allowsReleases && !isSnapshot )
223+
{
224+
logger.debug( "FILTER: Removing prohibited version: {} from: {}", version, transfer );
225+
versions.remove( version );
226+
changed = true;
227+
}
228+
}
229+
230+
String filteredMetadata = buffer.toString();
231+
if ( changed )
232+
{
233+
String filteredVersions;
234+
if ( versions.size() == 0 )
235+
{
236+
filteredVersions = "<versions></versions>";
237+
}
238+
else
239+
{
240+
filteredVersions = "<versions>\n<version>" + StringUtils.join( versions, "</version>\n<version>" )
241+
+ "</version>\n</versions>";
242+
}
243+
filteredMetadata = filteredMetadata.replaceFirst( VERSIONS, filteredVersions );
244+
}
245+
246+
final Pattern latestPattern = Pattern.compile( LATEST );
247+
final Matcher latestMatcher = latestPattern.matcher( filteredMetadata );
248+
if ( latestMatcher.find() )
249+
{
250+
final String latestVersion = latestMatcher.group( 1 );
251+
final boolean isSnapshot = latestVersion.endsWith( "-SNAPSHOT" );
252+
if ( !allowsSnapshots && isSnapshot || !allowsReleases && !isSnapshot )
253+
{
254+
logger.debug( "FILTER: Recalculating LATEST version; supplied value is prohibited: {} from: {}",
255+
latestVersion, transfer );
256+
257+
String newLatest;
258+
if ( versions.size() > 0 )
259+
{
260+
newLatest = "<latest>" + versions.get( versions.size() - 1 ) + "</latest>";
261+
}
262+
else
263+
{
264+
newLatest = "<latest></latest>";
265+
}
266+
filteredMetadata = filteredMetadata.replaceFirst( LATEST, newLatest );
267+
}
268+
}
269+
270+
if ( !allowsReleases )
271+
{
272+
final Pattern releasePattern = Pattern.compile( RELEASE );
273+
final Matcher releaseMatcher = releasePattern.matcher( filteredMetadata );
274+
if ( releaseMatcher.find() )
275+
{
276+
logger.debug( "FILTER: Suppressing prohibited release fields from: {}", transfer );
277+
278+
filteredMetadata = filteredMetadata.replaceFirst( RELEASE, "<release></release>" );
279+
}
280+
}
281+
282+
// filter snapshots from GAV metadata
283+
if ( !allowsSnapshots )
284+
{
285+
logger.debug( "FILTER: Suppressing prohibited snapshot fields from: {}", transfer );
286+
287+
final String snapshots = StringUtils.substringBetween( filteredMetadata, "<snapshotVersions>",
288+
"</snapshotVersions>" );
289+
if ( snapshots != null )
290+
{
291+
filteredMetadata = filteredMetadata.replace( snapshots, "" );
292+
}
293+
294+
final String snapshot = StringUtils.substringBetween( filteredMetadata, "<snapshot>", "</snapshot>" );
295+
if ( snapshot != null )
296+
{
297+
filteredMetadata = filteredMetadata.replace( snapshot, "" );
298+
}
299+
}
300+
301+
return filteredMetadata;
302+
}
303+
304+
@Override
305+
public void write( final int b ) throws IOException
306+
{
307+
buffer.append( (char) b );
308+
}
309+
310+
@Override
311+
public void flush() throws IOException
312+
{
313+
try
314+
{
315+
out.write( filterMetadata().getBytes() );
316+
out.flush();
317+
}
318+
finally
319+
{
320+
buffer = new StringBuilder();
321+
}
322+
}
323+
}
324+
}

0 commit comments

Comments
 (0)