blob: 1da0e5dc9485e75bb09df1f263eba60e470ce63a [file] [log] [blame]
Andrea Campanellae1e3e442019-10-21 13:45:32 +02001/*
2 * Copyright 2016-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.odtn.impl;
18
19import com.google.common.annotations.Beta;
20import org.apache.commons.io.IOUtils;
21import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
22import org.onosproject.net.DeviceId;
23import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
25
26import javax.net.ssl.SSLContext;
27import javax.net.ssl.TrustManager;
28import javax.net.ssl.X509TrustManager;
29import javax.ws.rs.ProcessingException;
30import javax.ws.rs.client.Client;
31import javax.ws.rs.client.ClientBuilder;
32import javax.ws.rs.client.Entity;
33import javax.ws.rs.client.WebTarget;
34import javax.ws.rs.core.MediaType;
35import javax.ws.rs.core.Response;
36import javax.ws.rs.core.Response.Status;
37import java.io.ByteArrayInputStream;
38import java.io.IOException;
39import java.io.InputStream;
40import java.nio.charset.StandardCharsets;
41import java.security.KeyManagementException;
42import java.security.NoSuchAlgorithmException;
43import java.security.cert.CertificateException;
44import java.security.cert.X509Certificate;
45
46/**
47 * The implementation of HttpUtils.
48 */
49@Beta
50public class HttpUtil {
51
52 private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);
53 private static final String XML = "xml";
54 private static final String JSON = "json";
55 protected static final String DOUBLESLASH = "//";
56 protected static final String COLON = ":";
57 private static final int STATUS_OK = Response.Status.OK.getStatusCode();
58 private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode();
59 private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode();
60 private static final String HTTPS = "https";
61
62 private Client client = null;
63 private String protocol = null;
64 private String ip = null;
65 private String port = null;
66
67 public HttpUtil(String protocol, String ip, String port) {
68 //TODO check not null
69 this.protocol = protocol.equals("") ? HTTPS : protocol;
70 this.ip = ip;
71 this.port = port;
72 }
73
74 public void connect(String username, String password) {
75 client = ignoreSslClient();
76 authenticate(client, username, password);
77 }
78
79 public void disconnect() {
80 protocol = "";
81 ip = "";
82 port = "";
83 client = null;
84 }
85
86 public int post(String request, InputStream payload, MediaType mediaType) {
87 Response response = getResponse(request, payload, mediaType);
88 if (response == null) {
89 return Status.NO_CONTENT.getStatusCode();
90 }
91 return response.getStatus();
92 }
93
94 public <T> T post(DeviceId device, String request, InputStream payload, MediaType mediaType,
95 Class<T> responseClass) {
96 Response response = getResponse(request, payload, mediaType);
97 if (response != null && response.hasEntity()) {
98 // Do not read the entity if the responseClass is of type Response. This would allow the
99 // caller to receive the Response directly and try to read its appropriate entity locally.
100 return responseClass == Response.class ? (T) response : response.readEntity(responseClass);
101 }
102 log.error("Response from device {} for request {} contains no entity", device, request);
103 return null;
104 }
105
106 private Response getResponse(String request, InputStream payload, MediaType mediaType) {
107
108 WebTarget wt = getWebTarget(request);
109
110 Response response = null;
111 if (payload != null) {
112 try {
113 response = wt.request(mediaType)
114 .post(Entity.entity(IOUtils.toString(payload, StandardCharsets.UTF_8), mediaType));
115 } catch (IOException e) {
116 log.error("Cannot do POST {} request on GNPY because can't read payload", request);
117 }
118 } else {
119 response = wt.request(mediaType).post(Entity.entity(null, mediaType));
120 }
121 return response;
122 }
123
124 public int put(String request, InputStream payload, MediaType mediaType) {
125
126 WebTarget wt = getWebTarget(request);
127
128 Response response = null;
129 if (payload != null) {
130 try {
131 response = wt.request(mediaType).put(Entity.entity(IOUtils.
132 toString(payload, StandardCharsets.UTF_8), mediaType));
133 } catch (IOException e) {
134 log.error("Cannot do POST {} request on GNPY because can't read payload", request);
135 }
136 } else {
137 response = wt.request(mediaType).put(Entity.entity(null, mediaType));
138 }
139
140 if (response == null) {
141 return Status.NO_CONTENT.getStatusCode();
142 }
143 return response.getStatus();
144 }
145
146 public InputStream get(String request, MediaType mediaType) {
147 WebTarget wt = getWebTarget(request);
148
149 Response s = wt.request(mediaType).get();
150
151 if (checkReply(s)) {
152 return new ByteArrayInputStream(s.readEntity((String.class)).getBytes(StandardCharsets.UTF_8));
153 }
154 return null;
155 }
156
157 public int delete(DeviceId device, String request, InputStream payload, MediaType mediaType) {
158
159 WebTarget wt = getWebTarget(request);
160
161 // FIXME: do we need to delete an entry by enclosing data in DELETE
162 // request?
163 // wouldn't it be nice to use PUT to implement the similar concept?
164 Response response = null;
165 try {
166 response = wt.request(mediaType).delete();
167 } catch (ProcessingException procEx) {
168 log.error("Cannot issue DELETE {} request on device {}", request, device);
169 return Status.SERVICE_UNAVAILABLE.getStatusCode();
170 }
171
172 return response.getStatus();
173 }
174
175 private void authenticate(Client client, String username, String password) {
176 client.register(HttpAuthenticationFeature.basic(username, password));
177
178 }
179
180 protected WebTarget getWebTarget(String request) {
181 log.debug("Sending request to URL {} ", getUrlString(request));
182 return client.target(getUrlString(request));
183 }
184
185 protected String getUrlString(String request) {
186 return protocol + COLON + DOUBLESLASH + ip + COLON + port + request;
187 }
188
189 private boolean checkReply(Response response) {
190 if (response != null) {
191 boolean statusCode = checkStatusCode(response.getStatus());
192 if (!statusCode && response.hasEntity()) {
193 log.error("Failed request, HTTP error msg : " + response.readEntity(String.class));
194 }
195 return statusCode;
196 }
197 log.error("Null reply from device");
198 return false;
199 }
200
201 private boolean checkStatusCode(int statusCode) {
202 if (statusCode == STATUS_OK || statusCode == STATUS_CREATED || statusCode == STATUS_ACCEPTED) {
203 return true;
204 } else {
205 log.error("Failed request, HTTP error code : " + statusCode);
206 return false;
207 }
208 }
209
210 private Client ignoreSslClient() {
211 SSLContext sslcontext = null;
212
213 try {
214 sslcontext = SSLContext.getInstance("TLS");
215 sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
216 @Override
217 public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
218 }
219
220 @Override
221 public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
222 }
223
224 @Override
225 public X509Certificate[] getAcceptedIssuers() {
226 return new X509Certificate[0];
227 }
228 } }, new java.security.SecureRandom());
229 } catch (NoSuchAlgorithmException | KeyManagementException e) {
230 throw new IllegalStateException(e);
231 }
232
233 return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build();
234 }
235
236}