-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
TeamsHttpClient.java
301 lines (261 loc) · 7.75 KB
/
TeamsHttpClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
package com.andrewensley.sonarteamsnotifier.extension;
import com.andrewensley.sonarteamsnotifier.domain.InvalidHttpResponseException;
import com.google.gson.Gson;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
class TeamsHttpClient {
/**
* Logger.
*/
private static final Logger LOG = Loggers.get(TeamsHttpClient.class);
private static final String NOT_SET = "NOT_SET";
/**
* The URL for the webhook.
*/
private URL hook;
/**
* The port to be used for the connection.
*/
private int port;
/**
* The full path of the URL including query string and anchor reference.
*/
private String path;
/**
* The payload to send with the request.
*/
private Payload payload;
/**
* Internal Apache HTTP Client.
*/
private CloseableHttpClient httpClient;
/**
* The target host of the webhook.
*/
private HttpHost target;
/**
* The HTTP POST request to send.
*/
private HttpPost httpPost;
/**
* The proxy host name or IP.
*/
private Optional<String> proxyIp;
/**
* The proxy port.
*/
private Optional<Integer> proxyPort;
/**
* The username for proxy authentication.
*/
private Optional<String> proxyUser;
/**
* The password for proxy authentication.
*/
private Optional<String> proxyPass;
/**
* Constructor.
*
* @param url The URL of the webhook.
* @param payload The payload to send to the webhook.
*
* @throws MalformedURLException If the URL is malformed.
*/
private TeamsHttpClient(String url, Payload payload) throws MalformedURLException {
this.hook = new URL(url);
this.payload = payload;
}
/**
* Static pattern constructor.
*
* @param url The URL of the webhook.
* @param payload The payload to send to the webhook.
*
* @return The TeamsHttpClient
*
* @throws MalformedURLException If the URL is malformed.
*/
static TeamsHttpClient of(String url, Payload payload) throws MalformedURLException {
return new TeamsHttpClient(url, payload);
}
/**
* Sets proxy settings on the TeamsHttpClient.
*
* @param ip The proxy host name or IP.
* @param port The proxy port.
*
* @return The TeamsHttpClient.
*/
TeamsHttpClient proxy(Optional<String> ip, Optional<Integer> port) {
this.proxyIp = ip;
this.proxyPort = port;
return this;
}
/**
* Sets proxy auth settings on the TeamsHttpClient.
*
* @param username The proxy username.
* @param password The proxy password.
*
* @return The TeamsHttpClient
*/
TeamsHttpClient proxyAuth(Optional<String> username, Optional<String> password) {
this.proxyUser = username;
this.proxyPass = password;
return this;
}
/**
* Builds the TeamsHttpClient, preparing it to make the request.
*
* @return The TeamsHttpClient
*
* @throws UnsupportedEncodingException If the payload is malformed.
*/
TeamsHttpClient build() throws UnsupportedEncodingException {
port = getPort();
path = getPath();
httpClient = getHttpClient();
target = new HttpHost(hook.getHost(), port);
httpPost = getHttpPost();
LOG.debug(
"TeamsHttpClient BUILT"
+ " | Host: " + hook.getHost()
+ " | Port: " + port
+ " | Path: " + path
+ " | ProxyEnabled: " + proxyEnabled()
+ " | ProxyAuthEnabled: " + proxyAuthEnabled()
+ " | Proxy IP: " + (proxyIp.orElse(NOT_SET))
+ " | Proxy Port: " + (proxyPort.isPresent() ? proxyPort.get() : NOT_SET)
+ " | Proxy User: " + (proxyUser.orElse(NOT_SET))
+ " | Proxy Pass: " + (proxyPass.orElse(NOT_SET))
);
return this;
}
/**
* Posts the message to the webhook.
*
* @return True on success. False on failure.
*/
boolean post() {
boolean success = false;
try {
CloseableHttpResponse response = httpClient.execute(target, httpPost);
int responseCode = response.getStatusLine().getStatusCode();
if (responseCode != 200) {
throw new InvalidHttpResponseException("Invalid HTTP Response Code: " + responseCode);
}
LOG.info("POST Successful!");
success = true;
} catch (Exception e) {
LOG.error("Failed to send teams message", e);
} finally {
try {
httpClient.close();
} catch (Exception e) {
LOG.error("Unable to close HTTP Client", e);
}
}
return success;
}
/**
* Gets the HttpPost request object.
*
* @return The HttpPost.
*
* @throws UnsupportedEncodingException If the payload is malformed.
*/
private HttpPost getHttpPost() throws UnsupportedEncodingException {
Gson gson = new Gson();
HttpPost tempHttpPost = new HttpPost(path);
tempHttpPost.setEntity(new StringEntity(gson.toJson(payload)));
tempHttpPost.setHeader("Accept", "application/json");
tempHttpPost.setHeader("Content-type", "application/json");
if (proxyEnabled()) {
HttpHost proxy = new HttpHost(proxyIp.get(), proxyPort.get());
RequestConfig config = RequestConfig.custom()
.setProxy(proxy)
.build();
tempHttpPost.setConfig(config);
}
return tempHttpPost;
}
/**
* Checks if the HttpClient should use a proxy.
*
* @return True if proxy is enabled. False if not.
*/
private boolean proxyEnabled() {
return (proxyIp.isPresent() && proxyPort.isPresent());
}
/**
* Checks if the HttpClient should use proxy authentication.
*
* @return True if proxy auth is enabled. False if not.
*/
private boolean proxyAuthEnabled() {
return (proxyEnabled() && proxyUser.isPresent() && proxyPass.isPresent());
}
/**
* Gets the internal HTTP Client to be used for the request.
*
* @return The HTTP Client.
*/
private CloseableHttpClient getHttpClient() {
CloseableHttpClient tempHttpClient;
if (proxyAuthEnabled()) {
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(proxyIp.get(), proxyPort.get()),
new UsernamePasswordCredentials(proxyUser.get(), proxyPass.get()));
credsProvider.setCredentials(
new AuthScope(hook.getHost(), port),
new UsernamePasswordCredentials(proxyUser.get(), proxyPass.get()));
tempHttpClient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
} else {
tempHttpClient = HttpClients.createDefault();
}
return tempHttpClient;
}
/**
* Gets the port of the webhook URL.
*
* @return The port of the webhook URL.
*/
private int getPort() {
int tempPort = hook.getPort();
if (tempPort == -1) {
tempPort = (hook.getProtocol().equals("https") ? 443 : 80);
}
return tempPort;
}
/**
* Gets the full path of the webhook URL, including query string and anchor reference.
*
* @return The full path of the webhook URL.
*/
private String getPath() {
String tempPath = hook.getPath();
if (!hook.getQuery().isEmpty()) {
tempPath += "?" + hook.getQuery();
}
if (!hook.getRef().isEmpty()) {
tempPath += "#" + hook.getRef();
}
return tempPath;
}
}