1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.HttpURLConnection;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.util.List;
26
27 import org.apache.logging.log4j.Logger;
28 import org.apache.logging.log4j.core.config.plugins.Plugin;
29 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
30 import org.apache.logging.log4j.core.net.UrlConnectionFactory;
31 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
32 import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
33 import org.apache.logging.log4j.core.util.AbstractWatcher;
34 import org.apache.logging.log4j.core.util.Source;
35 import org.apache.logging.log4j.core.util.Watcher;
36 import org.apache.logging.log4j.status.StatusLogger;
37
38
39
40
41 @Plugin(name = "http", category = Watcher.CATEGORY, elementType = Watcher.ELEMENT_TYPE, printObject = true)
42 @PluginAliases("https")
43 public class HttpWatcher extends AbstractWatcher {
44
45 private Logger LOGGER = StatusLogger.getLogger();
46
47 private SslConfiguration sslConfiguration;
48 private URL url;
49 private volatile long lastModifiedMillis;
50 private static final int NOT_MODIFIED = 304;
51 private static final int OK = 200;
52 private static final int BUF_SIZE = 1024;
53 private static final String HTTP = "http";
54 private static final String HTTPS = "https";
55
56 public HttpWatcher(final Configuration configuration, final Reconfigurable reconfigurable,
57 final List<ConfigurationListener> configurationListeners, long lastModifiedMillis) {
58 super(configuration, reconfigurable, configurationListeners);
59 sslConfiguration = SslConfigurationFactory.getSslConfiguration();
60 this.lastModifiedMillis = lastModifiedMillis;
61 }
62
63 @Override
64 public long getLastModified() {
65 return lastModifiedMillis;
66 }
67
68 @Override
69 public boolean isModified() {
70 return refreshConfiguration();
71 }
72
73 @Override
74 public void watching(Source source) {
75 if (!source.getURI().getScheme().equals(HTTP) && !source.getURI().getScheme().equals(HTTPS)) {
76 throw new IllegalArgumentException(
77 "HttpWatcher requires a url using the HTTP or HTTPS protocol, not " + source.getURI().getScheme());
78 }
79 try {
80 url = source.getURI().toURL();
81 } catch (MalformedURLException ex) {
82 throw new IllegalArgumentException("Invalid URL for HttpWatcher " + source.getURI(), ex);
83 }
84 super.watching(source);
85 }
86
87 @Override
88 public Watcher newWatcher(Reconfigurable reconfigurable, List<ConfigurationListener> listeners,
89 long lastModifiedMillis) {
90 HttpWatcher watcher = new HttpWatcher(getConfiguration(), reconfigurable, listeners, lastModifiedMillis);
91 if (getSource() != null) {
92 watcher.watching(getSource());
93 }
94 return watcher;
95 }
96
97 private boolean refreshConfiguration() {
98 try {
99 final HttpURLConnection urlConnection = UrlConnectionFactory.createConnection(url, lastModifiedMillis,
100 sslConfiguration);
101 urlConnection.connect();
102
103 try {
104 int code = urlConnection.getResponseCode();
105 switch (code) {
106 case NOT_MODIFIED: {
107 LOGGER.debug("Configuration Not Modified");
108 return false;
109 }
110 case OK: {
111 try (InputStream is = urlConnection.getInputStream()) {
112 ConfigurationSource configSource = getConfiguration().getConfigurationSource();
113 configSource.setData(readStream(is));
114 lastModifiedMillis = urlConnection.getLastModified();
115 configSource.setModifiedMillis(lastModifiedMillis);
116 LOGGER.debug("Content was modified for {}", url.toString());
117 return true;
118 } catch (final IOException e) {
119 try (InputStream es = urlConnection.getErrorStream()) {
120 LOGGER.info("Error accessing configuration at {}: {}", url, readStream(es));
121 } catch (final IOException ioe) {
122 LOGGER.error("Error accessing configuration at {}: {}", url, e.getMessage());
123 }
124 return false;
125 }
126 }
127 default: {
128 if (code < 0) {
129 LOGGER.info("Invalid response code returned");
130 } else {
131 LOGGER.info("Unexpected response code returned {}", code);
132 }
133 return false;
134 }
135 }
136 } catch (final IOException ioe) {
137 LOGGER.error("Error accessing configuration at {}: {}", url, ioe.getMessage());
138 }
139 } catch (final IOException ioe) {
140 LOGGER.error("Error connecting to configuration at {}: {}", url, ioe.getMessage());
141 }
142 return false;
143 }
144
145 private byte[] readStream(InputStream is) throws IOException {
146 ByteArrayOutputStream result = new ByteArrayOutputStream();
147 byte[] buffer = new byte[BUF_SIZE];
148 int length;
149 while ((length = is.read(buffer)) != -1) {
150 result.write(buffer, 0, length);
151 }
152 return result.toByteArray();
153 }
154 }