You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Get.java 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import java.io.File;
  56. import java.io.FileOutputStream;
  57. import java.io.IOException;
  58. import java.io.InputStream;
  59. import java.net.HttpURLConnection;
  60. import java.net.URL;
  61. import java.net.URLConnection;
  62. import java.util.Date;
  63. import org.apache.tools.ant.BuildException;
  64. import org.apache.tools.ant.Project;
  65. import org.apache.tools.ant.Task;
  66. import org.apache.tools.ant.util.FileUtils;
  67. import org.apache.tools.ant.util.JavaEnvUtils;
  68. /**
  69. * Gets a particular file from a URL source.
  70. * Options include verbose reporting, timestamp based fetches and controlling
  71. * actions on failures. NB: access through a firewall only works if the whole
  72. * Java runtime is correctly configured.
  73. *
  74. * @author costin@dnt.ro
  75. * @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth)
  76. *
  77. * @since Ant 1.1
  78. *
  79. * @ant.task category="network"
  80. */
  81. public class Get extends Task {
  82. private URL source; // required
  83. private File dest; // required
  84. private boolean verbose = false;
  85. private boolean useTimestamp = false; //off by default
  86. private boolean ignoreErrors = false;
  87. private String uname = null;
  88. private String pword = null;
  89. /**
  90. * Does the work.
  91. *
  92. * @exception BuildException Thrown in unrecoverable error.
  93. */
  94. public void execute() throws BuildException {
  95. if (source == null) {
  96. throw new BuildException("src attribute is required", getLocation());
  97. }
  98. if (dest == null) {
  99. throw new BuildException("dest attribute is required", getLocation());
  100. }
  101. if (dest.exists() && dest.isDirectory()) {
  102. throw new BuildException("The specified destination is a directory",
  103. getLocation());
  104. }
  105. if (dest.exists() && !dest.canWrite()) {
  106. throw new BuildException("Can't write to " + dest.getAbsolutePath(),
  107. getLocation());
  108. }
  109. try {
  110. log("Getting: " + source);
  111. //set the timestamp to the file date.
  112. long timestamp = 0;
  113. boolean hasTimestamp = false;
  114. if (useTimestamp && dest.exists()) {
  115. timestamp = dest.lastModified();
  116. if (verbose) {
  117. Date t = new Date(timestamp);
  118. log("local file date : " + t.toString());
  119. }
  120. hasTimestamp = true;
  121. }
  122. //set up the URL connection
  123. URLConnection connection = source.openConnection();
  124. //modify the headers
  125. //NB: things like user authentication could go in here too.
  126. if (useTimestamp && hasTimestamp) {
  127. connection.setIfModifiedSince(timestamp);
  128. }
  129. // prepare Java 1.1 style credentials
  130. if (uname != null || pword != null) {
  131. String up = uname + ":" + pword;
  132. String encoding;
  133. // check to see if sun's Base64 encoder is available.
  134. try {
  135. sun.misc.BASE64Encoder encoder =
  136. (sun.misc.BASE64Encoder)
  137. Class.forName("sun.misc.BASE64Encoder").newInstance();
  138. encoding = encoder.encode (up.getBytes());
  139. } catch (Exception ex) { // sun's base64 encoder isn't available
  140. Base64Converter encoder = new Base64Converter();
  141. encoding = encoder.encode(up.getBytes());
  142. }
  143. connection.setRequestProperty ("Authorization",
  144. "Basic " + encoding);
  145. }
  146. //connect to the remote site (may take some time)
  147. connection.connect();
  148. //next test for a 304 result (HTTP only)
  149. if (connection instanceof HttpURLConnection) {
  150. HttpURLConnection httpConnection
  151. = (HttpURLConnection) connection;
  152. if (httpConnection.getResponseCode()
  153. == HttpURLConnection.HTTP_NOT_MODIFIED) {
  154. //not modified so no file download. just return
  155. //instead and trace out something so the user
  156. //doesn't think that the download happened when it
  157. //didnt
  158. log("Not modified - so not downloaded");
  159. return;
  160. }
  161. // test for 401 result (HTTP only)
  162. if (httpConnection.getResponseCode()
  163. == HttpURLConnection.HTTP_UNAUTHORIZED) {
  164. String message="HTTP Authorization failure";
  165. if(ignoreErrors) {
  166. log(message,Project.MSG_WARN);
  167. return;
  168. } else {
  169. throw new BuildException(message);
  170. }
  171. }
  172. }
  173. //REVISIT: at this point even non HTTP connections may
  174. //support the if-modified-since behaviour -we just check
  175. //the date of the content and skip the write if it is not
  176. //newer. Some protocols (FTP) dont include dates, of
  177. //course.
  178. InputStream is = null;
  179. for (int i = 0; i < 3 ; i++) {
  180. try {
  181. is = connection.getInputStream();
  182. break;
  183. } catch (IOException ex) {
  184. log("Error opening connection " + ex);
  185. }
  186. }
  187. if (is == null) {
  188. log("Can't get " + source + " to " + dest);
  189. if (ignoreErrors) {
  190. return;
  191. }
  192. throw new BuildException("Can't get " + source + " to " + dest,
  193. getLocation());
  194. }
  195. FileOutputStream fos = new FileOutputStream(dest);
  196. boolean finished = false;
  197. try {
  198. byte[] buffer = new byte[100 * 1024];
  199. int length;
  200. while ((length = is.read(buffer)) >= 0) {
  201. fos.write(buffer, 0, length);
  202. if (verbose) {
  203. System.out.print(".");
  204. }
  205. }
  206. if (verbose) {
  207. System.out.println();
  208. }
  209. finished = true;
  210. } finally {
  211. if (fos != null) {
  212. fos.close();
  213. }
  214. is.close();
  215. // we have started to (over)write dest, but failed.
  216. // Try to delete the garbage we'd otherwise leave
  217. // behind.
  218. if (!finished) {
  219. dest.delete();
  220. }
  221. }
  222. //if (and only if) the use file time option is set, then
  223. //the saved file now has its timestamp set to that of the
  224. //downloaded file
  225. if (useTimestamp) {
  226. long remoteTimestamp = connection.getLastModified();
  227. if (verbose) {
  228. Date t = new Date(remoteTimestamp);
  229. log("last modified = " + t.toString()
  230. + ((remoteTimestamp == 0)
  231. ? " - using current time instead"
  232. : ""));
  233. }
  234. if (remoteTimestamp != 0) {
  235. FileUtils.newFileUtils()
  236. .setFileLastModified(dest, remoteTimestamp);
  237. }
  238. }
  239. } catch (IOException ioe) {
  240. log("Error getting " + source + " to " + dest);
  241. if (ignoreErrors) {
  242. return;
  243. }
  244. throw new BuildException(ioe, getLocation());
  245. }
  246. }
  247. /**
  248. * Set the URL to get.
  249. *
  250. * @param u URL for the file.
  251. */
  252. public void setSrc(URL u) {
  253. this.source = u;
  254. }
  255. /**
  256. * Where to copy the source file.
  257. *
  258. * @param dest Path to file.
  259. */
  260. public void setDest(File dest) {
  261. this.dest = dest;
  262. }
  263. /**
  264. * If true, show verbose progress information.
  265. *
  266. * @param v if "true" then be verbose
  267. */
  268. public void setVerbose(boolean v) {
  269. verbose = v;
  270. }
  271. /**
  272. * If true, log errors but do not treat as fatal.
  273. *
  274. * @param v if "true" then don't report download errors up to ant
  275. */
  276. public void setIgnoreErrors(boolean v) {
  277. ignoreErrors = v;
  278. }
  279. /**
  280. * If true, conditionally download a file based on the timestamp
  281. * of the local copy.
  282. *
  283. * <p>In this situation, the if-modified-since header is set so
  284. * that the file is only fetched if it is newer than the local
  285. * file (or there is no local file) This flag is only valid on
  286. * HTTP connections, it is ignored in other cases. When the flag
  287. * is set, the local copy of the downloaded file will also have
  288. * its timestamp set to the remote file time.</p>
  289. *
  290. * <p>Note that remote files of date 1/1/1970 (GMT) are treated as
  291. * 'no timestamp', and web servers often serve files with a
  292. * timestamp in the future by replacing their timestamp with that
  293. * of the current time. Also, inter-computer clock differences can
  294. * cause no end of grief.</p>
  295. * @param v "true" to enable file time fetching
  296. */
  297. public void setUseTimestamp(boolean v) {
  298. if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1)) {
  299. useTimestamp = v;
  300. }
  301. }
  302. /**
  303. * Username for basic auth.
  304. *
  305. * @param u username for authentication
  306. */
  307. public void setUsername(String u) {
  308. this.uname = u;
  309. }
  310. /**
  311. * password for the basic authentication.
  312. *
  313. * @param p password for authentication
  314. */
  315. public void setPassword(String p) {
  316. this.pword = p;
  317. }
  318. /*********************************************************************
  319. * BASE 64 encoding of a String or an array of bytes.
  320. *
  321. * Based on RFC 1421.
  322. *
  323. * @author
  324. * Unknown
  325. * @author
  326. * <a HREF="gg@grtmail.com">Gautam Guliani</a>
  327. *********************************************************************/
  328. class Base64Converter {
  329. public final char [ ] alphabet = {
  330. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
  331. 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
  332. 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
  333. 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
  334. 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
  335. 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
  336. 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
  337. '4', '5', '6', '7', '8', '9', '+', '/' }; // 56 to 63
  338. public String encode(String s) {
  339. return encode (s.getBytes());
  340. }
  341. public String encode(byte[ ] octetString) {
  342. int bits24;
  343. int bits6;
  344. char [ ] out
  345. = new char[((octetString.length - 1) / 3 + 1) * 4];
  346. int outIndex = 0;
  347. int i = 0;
  348. while ((i + 3) <= octetString.length) {
  349. // store the octets
  350. bits24 = (octetString[i++] & 0xFF) << 16;
  351. bits24 |= (octetString[i++] & 0xFF) << 8;
  352. bits6 = (bits24 & 0x00FC0000) >> 18;
  353. out[outIndex++] = alphabet[bits6];
  354. bits6 = (bits24 & 0x0003F000) >> 12;
  355. out[outIndex++] = alphabet[bits6];
  356. bits6 = (bits24 & 0x00000FC0) >> 6;
  357. out[outIndex++] = alphabet[bits6];
  358. bits6 = (bits24 & 0x0000003F);
  359. out[outIndex++] = alphabet[bits6];
  360. }
  361. if (octetString.length - i == 2) {
  362. // store the octets
  363. bits24 = (octetString[i] & 0xFF) << 16;
  364. bits24 |= (octetString[i + 1] & 0xFF) << 8;
  365. bits6 = (bits24 & 0x00FC0000) >> 18;
  366. out[outIndex++] = alphabet[bits6];
  367. bits6 = (bits24 & 0x0003F000) >> 12;
  368. out[outIndex++] = alphabet[bits6];
  369. bits6 = (bits24 & 0x00000FC0) >> 6;
  370. out[outIndex++] = alphabet[bits6];
  371. // padding
  372. out[outIndex++] = '=';
  373. } else if (octetString.length - i == 1) {
  374. // store the octets
  375. bits24 = (octetString[i] & 0xFF) << 16;
  376. bits6 = (bits24 & 0x00FC0000) >> 18;
  377. out[outIndex++] = alphabet[bits6];
  378. bits6 = (bits24 & 0x0003F000) >> 12;
  379. out[outIndex++] = alphabet[ bits6 ];
  380. // padding
  381. out[outIndex++] = '=';
  382. out[outIndex++] = '=';
  383. }
  384. return new String(out);
  385. }
  386. }
  387. }