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

WarURLStreamHandlerFactory.java 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package com.vaadin.server;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.Serializable;
  5. import java.net.MalformedURLException;
  6. import java.net.URL;
  7. import java.net.URLConnection;
  8. import java.net.URLStreamHandler;
  9. import java.net.URLStreamHandlerFactory;
  10. import java.security.Permission;
  11. /**
  12. * Test factory for URL stream protocol handlers, needed for WAR handling in
  13. * {@link VaadinServletTest}. Cherry-picked from Flow, some of the
  14. * implementation details are not needed for Vaadin 8 at the moment, but they
  15. * are left in because they aren't interfering either.
  16. */
  17. public class WarURLStreamHandlerFactory
  18. implements URLStreamHandlerFactory, Serializable {
  19. private static final String WAR_PROTOCOL = "war";
  20. // Singleton instance
  21. private static volatile WarURLStreamHandlerFactory instance = null;
  22. private final boolean registered;
  23. /**
  24. * Obtain a reference to the singleton instance. It is recommended that
  25. * callers check the value of {@link #isRegistered()} before using the
  26. * returned instance.
  27. *
  28. * @return A reference to the singleton instance
  29. */
  30. public static WarURLStreamHandlerFactory getInstance() {
  31. getInstanceInternal(true);
  32. return instance;
  33. }
  34. private static WarURLStreamHandlerFactory getInstanceInternal(
  35. boolean register) {
  36. // Double checked locking. OK because instance is volatile.
  37. if (instance == null) {
  38. synchronized (WarURLStreamHandlerFactory.class) {
  39. if (instance == null) {
  40. instance = new WarURLStreamHandlerFactory(register);
  41. }
  42. }
  43. }
  44. return instance;
  45. }
  46. private WarURLStreamHandlerFactory(boolean register) {
  47. // Hide default constructor
  48. // Singleton pattern to ensure there is only one instance of this
  49. // factory
  50. registered = register;
  51. if (register) {
  52. URL.setURLStreamHandlerFactory(this);
  53. }
  54. }
  55. public boolean isRegistered() {
  56. return registered;
  57. }
  58. /**
  59. * Register this factory with the JVM. May be called more than once. The
  60. * implementation ensures that registration only occurs once.
  61. *
  62. * @return <code>true</code> if the factory is already registered with the
  63. * JVM or was successfully registered as a result of this call.
  64. * <code>false</code> if the factory was disabled prior to this
  65. * call.
  66. */
  67. public static boolean register() {
  68. return getInstanceInternal(true).isRegistered();
  69. }
  70. /**
  71. * Prevent this this factory from registering with the JVM. May be called
  72. * more than once.
  73. *
  74. * @return <code>true</code> if the factory is already disabled or was
  75. * successfully disabled as a result of this call.
  76. * <code>false</code> if the factory was already registered prior to
  77. * this call.
  78. */
  79. public static boolean disable() {
  80. return !getInstanceInternal(false).isRegistered();
  81. }
  82. @Override
  83. public URLStreamHandler createURLStreamHandler(String protocol) {
  84. // Tomcat's handler always takes priority so applications can't override
  85. // it.
  86. if (WAR_PROTOCOL.equals(protocol)) {
  87. return new WarHandler();
  88. }
  89. // Unknown protocol
  90. return null;
  91. }
  92. public static class WarHandler extends URLStreamHandler
  93. implements Serializable {
  94. @Override
  95. protected URLConnection openConnection(URL u) throws IOException {
  96. return new WarURLConnection(u);
  97. }
  98. @Override
  99. protected void setURL(URL u, String protocol, String host, int port,
  100. String authority, String userInfo, String path, String query,
  101. String ref) {
  102. if (path.startsWith("file:") && !path.startsWith("file:/")) {
  103. /*
  104. * Work around a problem with the URLs in the security policy
  105. * file. On Windows, the use of ${catalina.[home|base]} in the
  106. * policy file results in codebase URLs of the form file:C:/...
  107. * when they should be file:/C:/...
  108. *
  109. * For file: and jar: URLs, the JRE compensates for this. It
  110. * does not compensate for this for war:file:... URLs.
  111. * Therefore, we do that here
  112. */
  113. path = "file:/" + path.substring(5);
  114. }
  115. super.setURL(u, protocol, host, port, authority, userInfo, path,
  116. query, ref);
  117. }
  118. }
  119. public static class WarURLConnection extends URLConnection
  120. implements Serializable {
  121. private final URLConnection wrappedJarUrlConnection;
  122. private boolean connected;
  123. protected WarURLConnection(URL url) throws IOException {
  124. super(url);
  125. URL innerJarUrl = warToJar(url);
  126. wrappedJarUrlConnection = innerJarUrl.openConnection();
  127. }
  128. @Override
  129. public void connect() throws IOException {
  130. if (!connected) {
  131. wrappedJarUrlConnection.connect();
  132. connected = true;
  133. }
  134. }
  135. @Override
  136. public InputStream getInputStream() throws IOException {
  137. connect();
  138. return wrappedJarUrlConnection.getInputStream();
  139. }
  140. @Override
  141. public Permission getPermission() throws IOException {
  142. return wrappedJarUrlConnection.getPermission();
  143. }
  144. @Override
  145. public long getLastModified() {
  146. return wrappedJarUrlConnection.getLastModified();
  147. }
  148. @Override
  149. public int getContentLength() {
  150. return wrappedJarUrlConnection.getContentLength();
  151. }
  152. @Override
  153. public long getContentLengthLong() {
  154. return wrappedJarUrlConnection.getContentLengthLong();
  155. }
  156. public static URL warToJar(URL warUrl) throws MalformedURLException {
  157. // Assumes that the spec is absolute and starts war:file:/...
  158. String file = warUrl.getFile();
  159. if (file.contains("*/")) {
  160. file = file.replaceFirst("\\*/", "!/");
  161. } else if (file.contains("^/")) {
  162. file = file.replaceFirst("\\^/", "!/");
  163. }
  164. return new URL("jar", warUrl.getHost(), warUrl.getPort(), file);
  165. }
  166. }
  167. }