brett 2004/07/01 05:55:49 Modified: src/java/org/apache/maven/util Tag: MAVEN-1_0-BRANCH HttpUtils.java src/java/org/apache/maven/verifier Tag: MAVEN-1_0-BRANCH DependencyVerifier.java xdocs Tag: MAVEN-1_0-BRANCH changes.xml Log: fixes to httpclient code Revision Changes Path No revision No revision 1.28.4.11 +156 -96 maven/src/java/org/apache/maven/util/HttpUtils.java Index: HttpUtils.java =================================================================== RCS file: /home/cvs/maven/src/java/org/apache/maven/util/HttpUtils.java,v retrieving revision 1.28.4.10 retrieving revision 1.28.4.11 diff -u -r1.28.4.10 -r1.28.4.11 --- HttpUtils.java 27 Jun 2004 07:57:48 -0000 1.28.4.10 +++ HttpUtils.java 1 Jul 2004 12:55:46 -0000 1.28.4.11 @@ -31,7 +31,9 @@ import java.net.URLConnection; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.TimeZone; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.httpclient.Credentials; @@ -61,6 +63,11 @@ { private static final Log LOG = LogFactory.getLog(HttpUtils.class); + private static final TimeZone GMT_TIME_ZONE = TimeZone.getTimeZone("GMT"); + + /** @todo make it a property. */ + private static final int REDIRECT_LIMIT = 5; + /** * Use a proxy to bypass the firewall with or without authentication * @@ -262,6 +269,8 @@ String loginDomain ) throws IOException { + LOG.debug( "Getting URL: " + url ); + //set the timestamp to the file date. long timestamp = -1; if ( useTimestamp && destinationFile.exists() ) @@ -360,90 +369,22 @@ client.getState().setCredentials(null, null, creds); } - int statusCode = -1; - InputStream is = null; - GetMethod get = new GetMethod(source.getPath()); - try { - if ( timestamp >= 0 ) - { - SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss zzz"); - get.addRequestHeader(new Header("If-Modified-Since", fmt.format(new Date(timestamp)))); - } - - // We will retry up to 3 times. - for (int i = 0; i < 3; i++) - { - try - { - statusCode = client.executeMethod(get); - if (statusCode != -1) { - break; - } - } - catch (HttpRecoverableException e) - { - if (i < 2) { - throw e; - } - LOG.warn( "A recoverable exception occurred." + e.getMessage()); - } - catch (IOException e) - { - throw e; - } - if (i < 2) { - LOG.warn("retrying " + (i + 1) + " of 3"); - } + for (int i = 0; i < REDIRECT_LIMIT; i++ ) + { + String redirect = retrieveArtifact(client, source, destinationFile, timestamp, silent); + if (redirect == null) { + break; } - - boolean use = statusCode < 300 && statusCode != HttpURLConnection.HTTP_NOT_MODIFIED; - - // Must read content regardless - is = get.getResponseBodyAsStream(); - if (is == null) { - if (!silent) LOG.info("Not modified"); - return; + if (i >= REDIRECT_LIMIT - 1) { + throw new IOException("Redirection limit of " + REDIRECT_LIMIT + " exceeded"); } - int projected = 0; - Header header = get.getResponseHeader("Content-Length"); - if (header != null) { - projected = Integer.valueOf(header.getValue()).intValue()/1024; - } + redirect = StringUtils.replace( redirect, ":/", "://" ); + redirect = StringUtils.replace( redirect, "//", "/" ); - long remoteTimestamp = 0; - header = get.getResponseHeader("Last-Modified"); - if (header != null) { - try { - remoteTimestamp = DateParser.parseDate(header.getValue()).getTime(); - } - catch (DateParseException e) { - LOG.warn("Unable to parse last modified header", e ); - } - } - else { - if (!silent) LOG.warn("warning: last-modified not specified"); - } - process( use, is, destinationFile, projected, timestamp, remoteTimestamp, silent ); - } - finally { - if (is != null) try { is.close(); } catch (Exception e) { LOG.error("error closing stream", e); } - get.releaseConnection(); - } - - if ( statusCode == HttpURLConnection.HTTP_NOT_FOUND) - { - throw new FileNotFoundException(url.toString()); - } - // test for 401 result (HTTP only) - if ( statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ) - { - throw new IOException( "Not authorized." ); - } - // test for 407 result (HTTP only) - if ( statusCode == HttpURLConnection.HTTP_PROXY_AUTH ) - { - throw new IOException( "Not authorized by proxy." ); + source = new URL( redirect ); + hc.setHost(source.getHost(), source.getPort(), source.getProtocol()); + client.setHostConfiguration(hc); } } else @@ -474,7 +415,7 @@ if ( connection.getLastModified() <= timestamp && connection.getLastModified() != 0 ) { - if (!silent) LOG.info("Not modified"); + if (!silent) LOG.debug("Not modified"); return; } @@ -489,6 +430,121 @@ } } + private static String retrieveArtifact(HttpClient client, URL source, File destinationFile, long timestamp, boolean silent) throws FileNotFoundException, IOException, HttpRecoverableException { + int statusCode = -1; + String redirectUrl = null; + InputStream is = null; + GetMethod get = new GetMethod(source.getPath()); + // Handle these ourselves until httpclient deals with cross host redirects + get.setFollowRedirects(false); + try { + if ( timestamp >= 0 ) + { + SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd-MMM-yy HH:mm:ss zzz"); + fmt.setTimeZone(GMT_TIME_ZONE); + Header hdr = new Header("If-Modified-Since", fmt.format(new Date(timestamp))); + LOG.debug("sending ==> " + hdr + "(" + timestamp + ")"); + get.addRequestHeader(hdr); + } + + // We will retry up to 3 times. + for (int i = 0; i < 3; i++) + { + try + { + statusCode = client.executeMethod(get); + if (statusCode != -1) { + LOG.debug("Received status code: " + statusCode); + break; + } + } + catch (HttpRecoverableException e) + { + if (i >= 2) { + throw e; + } + LOG.warn( "A recoverable exception occurred." + e.getMessage()); + } + catch (IOException e) + { + throw e; + } + LOG.warn("retrying (" + (i + 1) + ")"); + } + + boolean use = statusCode < 300; + + if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) { + if (!silent) LOG.debug("Not modified"); + } + else if (statusCode >= 300 && statusCode < 400) { + Header header = get.getResponseHeader("Location"); + if (header != null) { + redirectUrl = header.getValue(); + LOG.debug("Location: " + redirectUrl); + } + else { + LOG.warn("Location header not specified"); + } + } + + // Must read content regardless + is = get.getResponseBodyAsStream(); + if (is == null) { + return redirectUrl; + } + + int projected = 0; + Header header = get.getResponseHeader("Content-Length"); + if (header != null) { + try { + projected = Integer.valueOf(header.getValue()).intValue(); + } + catch (NumberFormatException e) { + LOG.warn( "error parsing content length header '" + header.getValue() + "' " + e ); + } + } + + long remoteTimestamp = 0; + if ( use ) { + header = get.getResponseHeader("Last-Modified"); + if (header != null) { + try { + remoteTimestamp = DateParser.parseDate(header.getValue()).getTime(); + } + catch (DateParseException e) { + LOG.warn("Unable to parse last modified header", e ); + } + LOG.debug("last-modified = " + header.getValue() + " (" + remoteTimestamp + ")"); + } + else { + if (!silent) LOG.warn("warning: last-modified not specified"); + } + } + process( use, is, destinationFile, projected, timestamp, remoteTimestamp, silent ); + } + finally { + if (is != null) try { is.close(); } catch (Exception e) { LOG.error("error closing stream", e); } + get.releaseConnection(); + } + + if ( statusCode == HttpURLConnection.HTTP_NOT_FOUND) + { + throw new FileNotFoundException(source.toString()); + } + // test for 401 result (HTTP only) + if ( statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ) + { + throw new IOException( "Not authorized." ); + } + // test for 407 result (HTTP only) + if ( statusCode == HttpURLConnection.HTTP_PROXY_AUTH ) + { + throw new IOException( "Not authorized by proxy." ); + } + return redirectUrl; + } + private static void process( boolean use, InputStream is, File destinationFile, long projected, long timestamp, long remoteTimestamp, boolean silent ) throws IOException { byte[] buffer = new byte[100 * 1024]; @@ -509,27 +565,30 @@ } } } + } + finally { + if (os != null) try { os.close(); } catch (Exception e) { LOG.error("error closing stream", e); } + } - if ( use ) { - if ( !silent ) { - System.out.println( (total/1024) + "K downloaded"); - } + if ( use ) { + if ( !silent ) { + System.out.println( (total/1024) + "K downloaded"); + } + + LOG.debug("Local timestamp: " + timestamp); + LOG.debug("Remote timestamp: " + remoteTimestamp); - // 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 ( timestamp >= 0 ) + // 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 ( timestamp >= 0 ) + { + if ( remoteTimestamp != 0 ) { - if ( remoteTimestamp != 0 ) - { - touchFile( destinationFile, remoteTimestamp ); - } + touchFile( destinationFile, remoteTimestamp ); } } } - finally { - if (os != null) try { os.close(); } catch (Exception e) { LOG.error("error closing stream", e); } - } } /** @@ -590,6 +649,7 @@ modifiedTime = timemillis; } + LOG.debug("touching " + file + " with " + modifiedTime); file.setLastModified( modifiedTime ); return true; } No revision No revision 1.34.4.8 +17 -6 maven/src/java/org/apache/maven/verifier/DependencyVerifier.java Index: DependencyVerifier.java =================================================================== RCS file: /home/cvs/maven/src/java/org/apache/maven/verifier/DependencyVerifier.java,v retrieving revision 1.34.4.7 retrieving revision 1.34.4.8 diff -u -r1.34.4.7 -r1.34.4.8 --- DependencyVerifier.java 27 Jun 2004 07:57:48 -0000 1.34.4.7 +++ DependencyVerifier.java 1 Jul 2004 12:55:46 -0000 1.34.4.8 @@ -141,7 +141,7 @@ { failedDependencies.add( artifact ); } - else + else if ( artifact.isSnapshot() ) { // The artifact exists but we need to take into account the user // being online and whether the artifact is a snapshot. If the user @@ -151,11 +151,11 @@ // take their chances with a strong warning that they could possibly // be using an out-of-date artifact. We don't want to cripple users // when working offline. - if ( online && artifact.isSnapshot() ) + if ( online ) { failedDependencies.add( artifact ); } - else if ( !online && artifact.isSnapshot() ) + else { log.warn( getMessage( "offline.snapshot.warning", artifact.getName() ) ); } @@ -235,6 +235,7 @@ */ private void getDependencies() { + log.debug("Getting failed dependencies: " + failedDependencies); for ( Iterator i = failedDependencies.iterator(); i.hasNext();) { Artifact artifact = (Artifact) i.next(); @@ -263,7 +264,7 @@ { // The snapshot jar locally exists and not in remote repository // FIXME: localize this message - log.debug("Artifact " + artifact.getUrlPath() + log.info("Artifact " + artifact.getUrlPath() + " doesn't exists in remote repository, but it exists locally"); i.remove(); } @@ -285,11 +286,16 @@ private boolean getRemoteArtifact( Artifact artifact ) { boolean artifactFound = false; + boolean errorsFound = false; for ( Iterator i = getProject().getContext().getMavenRepoRemote().iterator(); i.hasNext();) { String remoteRepo = (String) i.next(); + if (remoteRepo.endsWith("/")) { + remoteRepo = remoteRepo.substring(0, remoteRepo.length() - 1); + } + // The username and password parameters are not being // used here. Those are the "" parameters you see below. String url = remoteRepo + "/" + artifact.getUrlPath(); @@ -311,7 +317,6 @@ // of the checksum file was successful. try { - log.debug( "Getting URL: " + url ); String loginHost = (String) getProject().getContext().getVariable( MavenConstants.PROXY_LOGINHOST ); String loginDomain = (String) getProject().getContext().getVariable( MavenConstants.PROXY_LOGINDOMAIN ); HttpUtils.getFile( url, @@ -329,6 +334,11 @@ // Artifact was found, continue checking additional remote repos (if any) // in case there is a newer version (i.e. snapshots) in another repo artifactFound = true; + + if ( !artifact.isSnapshot() ) + { + break; + } } catch (FileNotFoundException e) { @@ -361,6 +371,7 @@ // FIXME: localize this message log.warn("Error retrieving artifact from [" + url + "]: " + e); log.debug("Error details", e); + errorsFound = true; } } No revision No revision 1.14.4.27 +7 -0 maven/xdocs/changes.xml Index: changes.xml =================================================================== RCS file: /home/cvs/maven/xdocs/changes.xml,v retrieving revision 1.14.4.26 retrieving revision 1.14.4.27 diff -u -r1.14.4.26 -r1.14.4.27 --- changes.xml 28 Jun 2004 12:22:07 -0000 1.14.4.26 +++ changes.xml 1 Jul 2004 12:55:49 -0000 1.14.4.27 @@ -24,6 +24,13 @@ <author email="[EMAIL PROTECTED]">Vincent Massol</author> </properties> <body> + <release version="1.0-final-SNAPSHOT" date="in CVS"> + <action dev="brett" type="fix" issue="MAVEN-1343">Bugfixes for new httpclient based downloading (incorrect timestamps)</action> + <action dev="brett" type="fix" issue="MAVEN-1353">Handle cross site redirects</action> + <action dev="brett" type="fix" issue="MAVEN-1290">Correct absolute paths with no drive designator on windows</action> + <action dev="brett" type="fix" issue="MAVEN-1341">Amend bootstrap to create directories that might not exist</action> + <action dev="brett" type="fix" issue="MAVEN-1344">If artifact is not a snapshot, don't continue checking for newer downloads once one is successful</action> + </release> <release version="1.0-rc4" date="2004-06-28"> <action dev="brett" type="update">Set maven.plugin.user.dir to ${maven.home.local}/plugins by default, move maven.plugin.unpacked.dir to ${maven.home.local}/cache.</action> <action dev="brett" type="update">Read local plugin jars from maven.plugin.user.dir instead of maven.plugin.unpacked.dir.</action>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]