1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.appender;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.net.HttpURLConnection;
24 import java.net.URL;
25 import java.nio.charset.Charset;
26 import java.util.Objects;
27
28 import javax.net.ssl.HttpsURLConnection;
29
30 import org.apache.logging.log4j.core.Layout;
31 import org.apache.logging.log4j.core.LogEvent;
32 import org.apache.logging.log4j.core.LoggerContext;
33 import org.apache.logging.log4j.core.config.Configuration;
34 import org.apache.logging.log4j.core.config.ConfigurationException;
35 import org.apache.logging.log4j.core.config.Property;
36 import org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier;
37 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
38 import org.apache.logging.log4j.core.util.IOUtils;
39
40 public class HttpURLConnectionManager extends HttpManager {
41
42 private static final Charset CHARSET = Charset.forName("US-ASCII");
43
44 private final URL url;
45 private final boolean isHttps;
46 private final String method;
47 private final int connectTimeoutMillis;
48 private final int readTimeoutMillis;
49 private final Property[] headers;
50 private final SslConfiguration sslConfiguration;
51 private final boolean verifyHostname;
52
53 public HttpURLConnectionManager(final Configuration configuration, final LoggerContext loggerContext, final String name,
54 final URL url, final String method, final int connectTimeoutMillis,
55 final int readTimeoutMillis,
56 final Property[] headers,
57 final SslConfiguration sslConfiguration,
58 final boolean verifyHostname) {
59 super(configuration, loggerContext, name);
60 this.url = url;
61 if (!(url.getProtocol().equalsIgnoreCase("http") || url.getProtocol().equalsIgnoreCase("https"))) {
62 throw new ConfigurationException("URL must have scheme http or https");
63 }
64 this.isHttps = this.url.getProtocol().equalsIgnoreCase("https");
65 this.method = Objects.requireNonNull(method, "method");
66 this.connectTimeoutMillis = connectTimeoutMillis;
67 this.readTimeoutMillis = readTimeoutMillis;
68 this.headers = headers != null ? headers : new Property[0];
69 this.sslConfiguration = sslConfiguration;
70 if (this.sslConfiguration != null && !isHttps) {
71 throw new ConfigurationException("SSL configuration can only be specified with URL scheme https");
72 }
73 this.verifyHostname = verifyHostname;
74 }
75
76 @Override
77 public void send(final Layout<?> layout, final LogEvent event) throws IOException {
78 final HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
79 urlConnection.setAllowUserInteraction(false);
80 urlConnection.setDoOutput(true);
81 urlConnection.setDoInput(true);
82 urlConnection.setRequestMethod(method);
83 if (connectTimeoutMillis > 0) {
84 urlConnection.setConnectTimeout(connectTimeoutMillis);
85 }
86 if (readTimeoutMillis > 0) {
87 urlConnection.setReadTimeout(readTimeoutMillis);
88 }
89 if (layout.getContentType() != null) {
90 urlConnection.setRequestProperty("Content-Type", layout.getContentType());
91 }
92 for (final Property header : headers) {
93 urlConnection.setRequestProperty(
94 header.getName(),
95 header.isValueNeedsLookup() ? getConfiguration().getStrSubstitutor().replace(event, header.getValue()) : header.getValue());
96 }
97 if (sslConfiguration != null) {
98 ((HttpsURLConnection)urlConnection).setSSLSocketFactory(sslConfiguration.getSslSocketFactory());
99 }
100 if (isHttps && !verifyHostname) {
101 ((HttpsURLConnection)urlConnection).setHostnameVerifier(LaxHostnameVerifier.INSTANCE);
102 }
103
104 final byte[] msg = layout.toByteArray(event);
105 urlConnection.setFixedLengthStreamingMode(msg.length);
106 urlConnection.connect();
107 try (OutputStream os = urlConnection.getOutputStream()) {
108 os.write(msg);
109 }
110
111 final byte[] buffer = new byte[1024];
112 try (InputStream is = urlConnection.getInputStream()) {
113 while (IOUtils.EOF != is.read(buffer)) {
114
115 }
116 } catch (final IOException e) {
117 final StringBuilder errorMessage = new StringBuilder();
118 try (InputStream es = urlConnection.getErrorStream()) {
119 errorMessage.append(urlConnection.getResponseCode());
120 if (urlConnection.getResponseMessage() != null) {
121 errorMessage.append(' ').append(urlConnection.getResponseMessage());
122 }
123 if (es != null) {
124 errorMessage.append(" - ");
125 int n;
126 while (IOUtils.EOF != (n = es.read(buffer))) {
127 errorMessage.append(new String(buffer, 0, n, CHARSET));
128 }
129 }
130 }
131 if (urlConnection.getResponseCode() > -1) {
132 throw new IOException(errorMessage.toString());
133 } else {
134 throw e;
135 }
136 }
137 }
138
139 }