You are viewing a plain text version of this content. The canonical link for it is here.
Posted to m2-dev@maven.apache.org by ev...@apache.org on 2004/06/25 11:37:30 UTC
cvs commit: maven-components/maven-mboot/src/main Base64.java HttpUtils.java
evenisse 2004/06/25 02:37:30
Modified: maven-mboot/src/main HttpUtils.java
Added: maven-mboot/src/main Base64.java
Log:
Upgrade HttpUtils from maven1
Revision Changes Path
1.3 +181 -44 maven-components/maven-mboot/src/main/HttpUtils.java
Index: HttpUtils.java
===================================================================
RCS file: /home/cvs/maven-components/maven-mboot/src/main/HttpUtils.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- HttpUtils.java 27 Jan 2004 18:58:11 -0000 1.2
+++ HttpUtils.java 25 Jun 2004 09:37:30 -0000 1.3
@@ -1,4 +1,22 @@
+/* ====================================================================
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed 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 java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -8,8 +26,31 @@
import java.net.URL;
import java.net.URLConnection;
+/**
+ * Http utils for retrieving files.
+ *
+ * @author costin@dnt.ro
+ * @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth)
+ * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
+ *
+ * @todo Need to add a timeout so we can flip to a backup repository.
+ * @todo Download everything in a single session.
+ * @todo Throw meaningful exception when authentication fails.
+ */
public class HttpUtils
{
+ /**
+ * Use a proxy to bypass the firewall with or without authentication
+ *
+ * @param proxyHost Proxy Host (if proxy is required), or null
+ * @param proxyPort Proxy Port (if proxy is required), or null
+ * @param proxyUserName Proxy Username (if authentification is required),
+ * or null
+ * @param proxyPassword Proxy Password (if authentification is required),
+ * or null
+ * @throws SecurityException if an operation is not authorized by the
+ * SecurityManager
+ */
public static void useProxyUser( final String proxyHost,
final String proxyPort,
final String proxyUserName,
@@ -35,6 +76,26 @@
}
}
+ /**
+ * Retrieve a remote file. Throws an Exception on errors unless the
+ * ifnoreErrors flag is set to True
+ *
+ * @param url the of the file to retrieve
+ * @param destinationFile where to store it
+ * @param ignoreErrors whether to ignore errors during I/O or throw an
+ * exception when they happen
+ * @param useTimestamp whether to check the modified timestamp on the
+ * <code>destinationFile</code> against the remote <code>source</code>
+ * @param proxyHost Proxy Host (if proxy is required), or null
+ * @param proxyPort Proxy Port (if proxy is required), or null
+ * @param proxyUserName Proxy Username (if authentification is required),
+ * or null.
+ * @param proxyPassword Proxy Password (if authentification is required),
+ * or null.
+ * @param useChecksum Flag to indicate the use of the checksum for the retrieved
+ * artifact if it is available.
+ * @throws IOException If an I/O exception occurs.
+ */
public static void getFile( String url,
File destinationFile,
boolean ignoreErrors,
@@ -44,7 +105,7 @@
String proxyUserName,
String proxyPassword,
boolean useChecksum )
- throws Exception
+ throws IOException
{
// Get the requested file.
getFile( url,
@@ -80,6 +141,24 @@
}
}
+ /**
+ * Retrieve a remote file. Throws an Exception on errors unless the
+ * ifnoreErrors flag is set to True
+ *
+ * @param url the of the file to retrieve
+ * @param destinationFile where to store it
+ * @param ignoreErrors whether to ignore errors during I/O or throw an
+ * exception when they happen
+ * @param useTimestamp whether to check the modified timestamp on the
+ * <code>destinationFile</code> against the remote <code>source</code>
+ * @param proxyHost Proxy Host (if proxy is required), or null
+ * @param proxyPort Proxy Port (if proxy is required), or null
+ * @param proxyUserName Proxy Username (if authentification is required),
+ * or null
+ * @param proxyPassword Proxy Password (if authentification is required),
+ * or null
+ * @throws IOException If an I/O exception occurs.
+ */
public static void getFile( String url,
File destinationFile,
boolean ignoreErrors,
@@ -88,7 +167,58 @@
String proxyPort,
String proxyUserName,
String proxyPassword )
- throws Exception
+ throws IOException
+ {
+ //set the timestamp to the file date.
+ long timestamp = -1;
+ if ( useTimestamp && destinationFile.exists() )
+ {
+ timestamp = destinationFile.lastModified();
+ }
+
+ try
+ {
+ getFile( url,
+ destinationFile,
+ timestamp,
+ proxyHost,
+ proxyPort,
+ proxyUserName,
+ proxyPassword );
+ }
+ catch ( IOException ex )
+ {
+ if ( !ignoreErrors )
+ {
+ throw ex;
+ }
+ }
+ }
+
+ /**
+ * Retrieve a remote file.
+ *
+ * @param url the URL of the file to retrieve
+ * @param destinationFile where to store it
+ * @param timestamp if provided, the remote URL is only retrieved if it was
+ * modified more recently than timestamp. Otherwise, negative value indicates that
+ * the remote URL should be retrieved unconditionally.
+ * @param proxyHost Proxy Host (if proxy is required), or null
+ * @param proxyPort Proxy Port (if proxy is required), or null
+ * @param proxyUserName Proxy Username (if authentification is required),
+ * or null
+ * @param proxyPassword Proxy Password (if authentification is required),
+ * or null
+ * @throws IOException If an I/O exception occurs.
+ */
+ public static void getFile( String url,
+ File destinationFile,
+ long timestamp,
+ String proxyHost,
+ String proxyPort,
+ String proxyUserName,
+ String proxyPassword )
+ throws IOException
{
String[] s = parseUrl( url );
String username = s[0];
@@ -97,23 +227,14 @@
URL source = new URL( parsedUrl );
- //set the timestamp to the file date.
- long timestamp = 0;
- boolean hasTimestamp = false;
- if ( useTimestamp && destinationFile.exists() )
- {
- timestamp = destinationFile.lastModified();
- hasTimestamp = true;
- }
-
//set proxy connection
useProxyUser( proxyHost, proxyPort, proxyUserName, proxyPassword );
//set up the URL connection
URLConnection connection = source.openConnection();
+
//modify the headers
- //NB: things like user authentication could go in here too.
- if ( useTimestamp && hasTimestamp )
+ if ( timestamp >= 0 )
{
connection.setIfModifiedSince( timestamp );
}
@@ -121,22 +242,7 @@
if ( username != null || password != null )
{
String up = username + ":" + password;
- String encoding = null;
- // check to see if sun's Base64 encoder is available.
- try
- {
- sun.misc.BASE64Encoder encoder =
- (sun.misc.BASE64Encoder) Class.forName(
- "sun.misc.BASE64Encoder" ).newInstance();
-
- encoding = encoder.encode( up.getBytes() );
- }
- catch ( Exception ex )
- {
- // Do nothing, as for MavenSession we will never use
- // auth and we will eventually move over httpclient
- // in the commons.
- }
+ String encoding = Base64.encode(up.getBytes(), false);
connection.setRequestProperty( "Authorization", "Basic " + encoding );
}
@@ -146,6 +252,14 @@
if ( connection instanceof HttpURLConnection )
{
HttpURLConnection httpConnection = (HttpURLConnection) connection;
+ // although HTTPUrlConnection javadocs says FileNotFoundException should be
+ // thrown on a 404 error, that certainly does not appear to be the case, so
+ // test for 404 ourselves, and throw FileNotFoundException as needed
+ if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND)
+ {
+ throw new FileNotFoundException(url.toString() + " (HTTP Error: "
+ + httpConnection.getResponseCode() + " " + httpConnection.getResponseMessage() + ")");
+ }
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED )
{
return;
@@ -153,7 +267,12 @@
// test for 401 result (HTTP only)
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED )
{
- throw new Exception( "Not authorized." );
+ throw new IOException( "Not authorized." );
+ }
+ // test for 407 result (HTTP only)
+ if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH )
+ {
+ throw new IOException( "Not authorized by proxy." );
}
}
@@ -163,6 +282,7 @@
// Some protocols (FTP) dont include dates, of course.
InputStream is = null;
+ IOException isException = null;
for ( int i = 0; i < 3; i++ )
{
try
@@ -172,20 +292,20 @@
}
catch ( IOException ex )
{
- // do nothing
+ isException = ex;
}
}
if ( is == null )
{
- if ( ignoreErrors )
- {
- return;
- }
-
- // This will never happen with maven's use of this class.
- throw new Exception( "Can't get " + destinationFile.getName() + " to " + destinationFile );
+ throw isException;
}
+ if ( connection.getLastModified() <= timestamp &&
+ connection.getLastModified() != 0 )
+ {
+ return;
+ }
+
FileOutputStream fos = new FileOutputStream( destinationFile );
byte[] buffer = new byte[100 * 1024];
@@ -204,10 +324,9 @@
// if (and only if) the use file time option is set, then the
// saved file now has its timestamp set to that of the downloaded
// file
- if ( useTimestamp )
+ if ( timestamp >= 0 )
{
long remoteTimestamp = connection.getLastModified();
-
if ( remoteTimestamp != 0 )
{
touchFile( destinationFile, remoteTimestamp );
@@ -215,6 +334,15 @@
}
}
+ /**
+ * Parse an url which might contain a username and password. If the
+ * given url doesn't contain a username and password then return the
+ * origin url unchanged.
+ *
+ * @param url The url to parse.
+ * @return The username, password and url.
+ * @throws RuntimeException if the url is (very) invalid
+ */
static String[] parseUrl( String url )
{
String[] parsedUrl = new String[3];
@@ -231,18 +359,28 @@
int i = url.indexOf( "@" );
if ( i > 0 )
{
- String s = url.substring( 7, i );
+ String protocol = url.substring( 0, url.indexOf("://") ) + "://";
+ String s = url.substring( protocol.length(), i );
int j = s.indexOf( ":" );
parsedUrl[0] = s.substring( 0, j );
parsedUrl[1] = s.substring( j + 1 );
- parsedUrl[2] = "http://" + url.substring( i + 1 );
+ parsedUrl[2] = protocol + url.substring( i + 1 );
}
return parsedUrl;
}
+ /**
+ * set the timestamp of a named file to a specified time.
+ *
+ * @param file the file to touch
+ * @param timemillis in milliseconds since the start of the era
+ * @return true if it succeeded. False means that this is a java1.1 system
+ * and that file times can not be set
+ * @throws RuntimeException Thrown in unrecoverable error. Likely this
+ * comes from file access failures.
+ */
private static boolean touchFile( File file, long timemillis )
- throws Exception
{
long modifiedTime;
@@ -256,7 +394,6 @@
}
file.setLastModified( modifiedTime );
-
return true;
}
}
1.1 maven-components/maven-mboot/src/main/Base64.java
Index: Base64.java
===================================================================
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed 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 java.io.ByteArrayOutputStream;
// import org.apache.commons.logging.Log;
// import org.apache.commons.logging.LogFactory;
/**
* Encode/Decode Base-64.
*
* @author John Casey
*/
public final class Base64
{
// private static final Log LOG = LogFactory.getLog( Base64.class );
private static final String CRLF = System.getProperty( "line.separator" );
private static final int LINE_END = 64;
public static String encode( byte[] data )
{
return Base64.encode( data, true );
}
public static String encode( byte[] data, boolean useLineDelimiter )
{
if ( data == null )
{
return null;
}
else if ( data.length == 0 )
{
return "";
}
int padding = 3 - ( data.length % 3 );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "padding = " + padding + "characters." );
// }
StringBuffer buffer = new StringBuffer();
for ( int i = 0; i < data.length; i += 3 )
{
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "iteration base offset = " + i );
// }
int neutral = ( data[i] < 0 ? data[i] + 256 : data[i] );
int block = ( neutral & 0xff );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "after first byte, block = " + Integer.toBinaryString( block ) );
// }
boolean inLastSegment = false;
block <<= 8;
if ( i + 1 < data.length )
{
neutral = ( data[i + 1] < 0 ? data[i + 1] + 256 : data[i + 1] );
block |= ( neutral & 0xff );
}
else
{
inLastSegment = true;
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "after second byte, block = " + Integer.toBinaryString( block ) + "; inLastSegment = "
// + inLastSegment );
// }
block <<= 8;
if ( i + 2 < data.length )
{
neutral = ( data[i + 2] < 0 ? data[i + 2] + 256 : data[i + 2] );
block |= ( neutral & 0xff );
}
else
{
inLastSegment = true;
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "after third byte, block = " + Integer.toBinaryString( block ) + "; inLastSegment = "
// + inLastSegment );
// }
char[] encoded = new char[4];
int encIdx = 0;
encoded[0] = toBase64Char( ( block >>> 18 ) & 0x3f );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "first character = " + encoded[0] );
// }
encoded[1] = toBase64Char( ( block >>> 12 ) & 0x3f );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "second character = " + encoded[1] );
// }
if ( inLastSegment && padding > 1 )
{
encoded[2] = '=';
}
else
{
encoded[2] = toBase64Char( ( block >>> 6 ) & 0x3f );
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "third character = " + encoded[2] );
// }
if ( inLastSegment && padding > 0 )
{
encoded[3] = '=';
}
else
{
encoded[3] = toBase64Char( block & 0x3f );
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "fourth character = " + encoded[3] );
// }
buffer.append( encoded );
}
if ( useLineDelimiter )
{
return canonicalize( buffer.toString() );
}
else
{
return buffer.toString();
}
}
public static byte[] decode( String src )
{
return Base64.decode( src, true );
}
public static byte[] decode( String src, boolean useLineDelimiter )
{
if ( src == null )
{
return null;
}
else if ( src.length() < 1 )
{
return new byte[0];
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "pre-canonicalization = \n" + src );
// }
String data = src;
if ( useLineDelimiter )
{
data = deCanonicalize( src );
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "post-canonicalization = \n" + data );
// }
ByteArrayOutputStream baos = new ByteArrayOutputStream();
char[] input = data.toCharArray();
int index = 0;
for ( int i = 0; i < input.length; i += 4 )
{
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "iteration base offset = " + i );
// }
int block = ( toBase64Int( input[i] ) & 0x3f );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "block after first char [" + input[i] + "] = " + Integer.toBinaryString( block ) );
// }
block <<= 6;
block |= ( toBase64Int( input[i + 1] ) & 0x3f );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "block after second char [" + input[i + 1] + "] = " + Integer.toBinaryString( block ) );
// }
boolean inPadding = false;
boolean twoCharPadding = false;
block <<= 6;
if ( input[i + 2] != '=' )
{
block |= ( toBase64Int( input[i + 2] ) & 0x3f );
}
else
{
twoCharPadding = true;
inPadding = true;
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "block after third char [" + input[i + 2] + "] = " + Integer.toBinaryString( block ) );
// }
block <<= 6;
if ( input[i + 3] != '=' )
{
block |= ( toBase64Int( input[i + 3] ) & 0x3f );
}
else
{
inPadding = true;
}
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "block after fourth char [" + input[i + 3] + "] = " + Integer.toBinaryString( block ) );
// }
baos.write( ( block >>> 16 ) & 0xff );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( ( block >>> 16 ) & 0xff ) );
// }
if ( !inPadding || !twoCharPadding )
{
baos.write( ( block >>> 8 ) & 0xff );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( ( block >>> 8 ) & 0xff ) );
// }
}
if ( !inPadding )
{
baos.write( block & 0xff );
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( block & 0xff ) );
// }
}
}
byte[] result = baos.toByteArray();
// if ( LOG.isDebugEnabled() )
// {
// LOG.debug( "byte array is " + result.length + " bytes long." );
// }
return result;
}
private static char toBase64Char( int input )
{
if ( input > -1 && input < 26 )
{
return ( char ) ( 'A' + input );
}
else if ( input > 25 && input < 52 )
{
return ( char ) ( 'a' + input - 26 );
}
else if ( input > 51 && input < 62 )
{
return ( char ) ( '0' + input - 52 );
}
else if ( input == 62 )
{
return '+';
}
else if ( input == 63 )
{
return '/';
}
else
{
return '?';
}
}
private static int toBase64Int( char input )
{
if ( input >= 'A' && input <= 'Z' )
{
return input - 'A';
}
else if ( input >= 'a' && input <= 'z' )
{
return input + 26 - 'a';
}
else if ( input >= '0' && input <= '9' )
{
return input + 52 - '0';
}
else if ( input == '+' )
{
return 62;
}
else if ( input == '/' )
{
return 63;
}
else
{
return 0;
}
}
private static String deCanonicalize( String data )
{
if ( data == null )
{
return null;
}
StringBuffer buffer = new StringBuffer( data.length() );
for ( int i = 0; i < data.length(); i++ )
{
char c = data.charAt( i );
if ( c != '\r' && c != '\n' )
{
buffer.append( c );
}
}
return buffer.toString();
}
private static String canonicalize( String data )
{
StringBuffer buffer = new StringBuffer( ( int ) ( data.length() * 1.1 ) );
int col = 0;
for ( int i = 0; i < data.length(); i++ )
{
if ( col == LINE_END )
{
buffer.append( CRLF );
col = 0;
}
buffer.append( data.charAt( i ) );
col++;
}
buffer.append( CRLF );
return buffer.toString();
}
}
Re: cvs commit: maven-components/maven-mboot/src/main Base64.java
HttpUtils.java
Posted by John Casey <jd...@commonjava.org>.
Ah, the human precompiler hard at work...
-j
On Fri, 2004-06-25 at 06:41, Jerome Lacoste wrote:
> On Fri, 2004-06-25 at 11:37, evenisse@apache.org wrote:
> > evenisse 2004/06/25 02:37:30
> >
> > Modified: maven-mboot/src/main HttpUtils.java
> > Added: maven-mboot/src/main Base64.java
> > Log:
> > Upgrade HttpUtils from maven1
>
>
> [...]
>
> > String[] parsedUrl = new String[3];
> > @@ -231,18 +359,28 @@
> > int i = url.indexOf( "@" );
> > if ( i > 0 )
> > {
> > - String s = url.substring( 7, i );
> > + String protocol = url.substring( 0, url.indexOf("://") ) + "://";
>
> String protocol = url.substring( 0, url.indexOf("://") + 3 );
>
>
--
John Casey
jdcasey@commonjava.org
CommonJava Open Components Project
http://www.commonjava.org
Re: cvs commit: maven-components/maven-mboot/src/main Base64.java
HttpUtils.java
Posted by Jerome Lacoste <je...@coffeebreaks.org>.
On Fri, 2004-06-25 at 11:37, evenisse@apache.org wrote:
> evenisse 2004/06/25 02:37:30
>
> Modified: maven-mboot/src/main HttpUtils.java
> Added: maven-mboot/src/main Base64.java
> Log:
> Upgrade HttpUtils from maven1
[...]
> String[] parsedUrl = new String[3];
> @@ -231,18 +359,28 @@
> int i = url.indexOf( "@" );
> if ( i > 0 )
> {
> - String s = url.substring( 7, i );
> + String protocol = url.substring( 0, url.indexOf("://") ) + "://";
String protocol = url.substring( 0, url.indexOf("://") + 3 );