1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.gateway.kernel.rest.client;
21
22 import io.netty.bootstrap.Bootstrap;
23 import io.netty.buffer.ByteBuf;
24 import io.netty.buffer.Unpooled;
25 import io.netty.channel.Channel;
26 import io.netty.channel.ChannelFuture;
27 import io.netty.channel.ChannelInitializer;
28 import io.netty.channel.EventLoopGroup;
29 import io.netty.channel.nio.NioEventLoopGroup;
30 import io.netty.channel.socket.SocketChannel;
31 import io.netty.handler.codec.http.DefaultFullHttpRequest;
32 import io.netty.handler.codec.http.DefaultHttpRequest;
33 import io.netty.handler.codec.http.FullHttpRequest;
34 import io.netty.handler.codec.http.HttpHeaderNames;
35 import io.netty.handler.codec.http.HttpHeaderValues;
36 import io.netty.handler.codec.http.HttpHeaders;
37 import io.netty.handler.codec.http.HttpMethod;
38 import io.netty.handler.codec.http.HttpRequest;
39 import io.netty.handler.codec.http.HttpVersion;
40 import io.netty.handler.codec.http.QueryStringEncoder;
41 import org.joda.time.DateTime;
42 import org.waarp.common.crypto.HmacSha256;
43 import org.waarp.common.crypto.ssl.WaarpSslUtility;
44 import org.waarp.common.exception.CryptoException;
45 import org.waarp.common.logging.WaarpLogger;
46 import org.waarp.common.logging.WaarpLoggerFactory;
47 import org.waarp.common.logging.WaarpSlf4JLoggerFactory;
48 import org.waarp.common.utility.WaarpNettyUtil;
49 import org.waarp.common.utility.WaarpStringUtils;
50 import org.waarp.common.utility.WaarpThreadFactory;
51 import org.waarp.gateway.kernel.exception.HttpInvalidAuthenticationException;
52 import org.waarp.gateway.kernel.rest.RestArgument;
53
54 import java.io.File;
55 import java.io.IOException;
56 import java.net.InetSocketAddress;
57 import java.net.URI;
58 import java.net.URISyntaxException;
59 import java.util.Map;
60 import java.util.Map.Entry;
61
62
63
64
65 public class HttpRestClientHelper {
66 private static final String
67 NEED_MORE_ARGUMENTS_HTTP_HOST_PORT_URI_METHOD_USER_SIGN_PATH_NOSIGN_JSON =
68 "Need more arguments: http://host:port/uri method user pwd sign=path|nosign [json]";
69
70 private static WaarpLogger logger;
71
72 private final Bootstrap bootstrap;
73
74 private final HttpHeaders headers;
75
76 private String baseUri = "/";
77
78
79
80
81
82
83
84
85 public HttpRestClientHelper(final String baseUri, final int nbclient,
86 final long timeout,
87 final ChannelInitializer<SocketChannel> initializer) {
88 if (logger == null) {
89 logger = WaarpLoggerFactory.getLogger(HttpRestClientHelper.class);
90 }
91 if (baseUri != null) {
92 this.baseUri = baseUri;
93 }
94
95 bootstrap = new Bootstrap();
96
97
98
99 final EventLoopGroup workerGroup = new NioEventLoopGroup(nbclient,
100 new WaarpThreadFactory(
101 "Rest_" +
102 baseUri +
103 '_'));
104 WaarpNettyUtil.setBootstrap(bootstrap, workerGroup, 30000);
105
106 bootstrap.handler(initializer);
107
108
109 final HttpRequest request =
110 new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, baseUri);
111 headers = request.headers();
112 headers.set(HttpHeaderNames.ACCEPT_ENCODING,
113 HttpHeaderValues.GZIP + "," + HttpHeaderValues.DEFLATE);
114 headers.set(HttpHeaderNames.ACCEPT_CHARSET, "utf-8;q=0.7,*;q=0.7");
115 headers.set(HttpHeaderNames.ACCEPT_LANGUAGE, "fr,en");
116 headers.set(HttpHeaderNames.USER_AGENT,
117 "Netty Simple Http Rest Client side");
118 headers.set(HttpHeaderNames.ACCEPT,
119 "text/html,text/plain,application/xhtml+xml,application/xml,application/json;q=0.9,*/*;q=0.8");
120
121
122
123
124
125
126 }
127
128
129
130
131
132
133
134
135
136 public final Channel getChannel(final String host, final int port) {
137
138 final ChannelFuture future =
139 bootstrap.connect(new InetSocketAddress(host, port));
140
141 final Channel channel = WaarpSslUtility.waitforChannelReady(future);
142 if (channel != null) {
143 final RestFuture futureChannel = new RestFuture(true);
144 channel.attr(HttpRestClientSimpleResponseHandler.RESTARGUMENT)
145 .set(futureChannel);
146 }
147 return channel;
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 public final RestFuture sendQuery(final HmacSha256 hmacSha256,
175 final Channel channel,
176 final HttpMethod method, final String host,
177 final String addedUri, final String user,
178 final String pwd,
179 final Map<String, String> uriArgs,
180 final String json) {
181
182 logger.debug("Prepare request: {}:{}:{}", method, addedUri, json);
183 final RestFuture future =
184 channel.attr(HttpRestClientSimpleResponseHandler.RESTARGUMENT).get();
185 final QueryStringEncoder encoder;
186 if (addedUri != null) {
187 encoder = new QueryStringEncoder(baseUri + addedUri);
188 } else {
189 encoder = new QueryStringEncoder(baseUri);
190 }
191
192 if (uriArgs != null) {
193 for (final Entry<String, String> elt : uriArgs.entrySet()) {
194 encoder.addParam(elt.getKey(), elt.getValue());
195 }
196 }
197 final String[] result;
198 try {
199 result = RestArgument.getBaseAuthent(hmacSha256, encoder, user, pwd);
200 logger.debug("Authent encoded");
201 } catch (final HttpInvalidAuthenticationException e) {
202 logger.error(e.getMessage());
203 future.setFailure(e);
204 return future;
205 }
206 final URI uri;
207 try {
208 uri = encoder.toUri();
209 } catch (final URISyntaxException e) {
210 logger.error(e.getMessage());
211 future.setFailure(e);
212 return future;
213 }
214 if (logger.isDebugEnabled()) {
215 logger.debug("Uri ready: {}", uri.toASCIIString());
216 }
217 final FullHttpRequest request;
218 if (json != null) {
219 logger.debug("Add body");
220 final ByteBuf buffer =
221 Unpooled.wrappedBuffer(json.getBytes(WaarpStringUtils.UTF8));
222 request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method,
223 uri.toASCIIString(), buffer);
224 request.headers()
225 .set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
226 } else {
227 request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method,
228 uri.toASCIIString());
229 }
230
231 request.headers().add(headers);
232 request.headers().set(HttpHeaderNames.HOST, host);
233 if (user != null) {
234 request.headers().set(
235 (CharSequence) RestArgument.REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
236 user);
237 }
238 request.headers().set(
239 (CharSequence) RestArgument.REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field,
240 result[0]);
241 request.headers().set(
242 (CharSequence) RestArgument.REST_ROOT_FIELD.ARG_X_AUTH_KEY.field,
243 result[1]);
244
245 logger.debug("Send request");
246 channel.writeAndFlush(request);
247 logger.debug("Request sent");
248 return future;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 public final RestFuture sendQuery(final Channel channel,
273 final HttpMethod method, final String host,
274 final String addedUri, final String user,
275 final Map<String, String> uriArgs,
276 final String json) {
277
278 logger.debug("Prepare request: {}:{}:{}", method, addedUri, json);
279 final RestFuture future =
280 channel.attr(HttpRestClientSimpleResponseHandler.RESTARGUMENT).get();
281 final QueryStringEncoder encoder;
282 if (addedUri != null) {
283 encoder = new QueryStringEncoder(baseUri + addedUri);
284 } else {
285 encoder = new QueryStringEncoder(baseUri);
286 }
287
288 if (uriArgs != null) {
289 for (final Entry<String, String> elt : uriArgs.entrySet()) {
290 encoder.addParam(elt.getKey(), elt.getValue());
291 }
292 }
293 final URI uri;
294 try {
295 uri = encoder.toUri();
296 } catch (final URISyntaxException e) {
297 logger.error(e.getMessage());
298 future.setFailure(e);
299 return future;
300 }
301 if (logger.isDebugEnabled()) {
302 logger.debug("Uri ready: " + uri.toASCIIString());
303 }
304 final FullHttpRequest request;
305 if (json != null) {
306 logger.debug("Add body");
307 final ByteBuf buffer =
308 Unpooled.wrappedBuffer(json.getBytes(WaarpStringUtils.UTF8));
309 request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method,
310 uri.toASCIIString(), buffer);
311 request.headers()
312 .set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
313 } else {
314 request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method,
315 uri.toASCIIString());
316 }
317
318
319 request.headers().add(headers);
320 request.headers().set(HttpHeaderNames.HOST, host);
321 if (user != null) {
322 request.headers().set(
323 (CharSequence) RestArgument.REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
324 user);
325 }
326 request.headers().set(
327 (CharSequence) RestArgument.REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field,
328 new DateTime().toString());
329
330 logger.debug("Send request");
331 channel.writeAndFlush(request);
332 logger.debug("Request sent");
333 return future;
334 }
335
336
337
338
339 public final void closeAll() {
340 bootstrap.config().group().shutdownGracefully();
341 }
342
343
344
345
346
347 public static void main(final String[] args) {
348 WaarpLoggerFactory.setDefaultFactoryIfNotSame(
349 new WaarpSlf4JLoggerFactory(null));
350 logger = WaarpLoggerFactory.getLogger(HttpRestClientHelper.class);
351 if (args.length < 5) {
352 logger.error(
353 NEED_MORE_ARGUMENTS_HTTP_HOST_PORT_URI_METHOD_USER_SIGN_PATH_NOSIGN_JSON);
354 return;
355 }
356 final String uri = args[0];
357 final String meth = args[1];
358 final String user = args[2];
359 final String pwd = args[3];
360 final boolean sign = args[4].toLowerCase().contains("sign=");
361 HmacSha256 hmacSha256 = null;
362 if (sign) {
363 final String file = args[4].replace("sign=", "");
364 hmacSha256 = new HmacSha256();
365 try {
366 hmacSha256.setSecretKey(new File(file));
367 } catch (final CryptoException e) {
368 logger.error(
369 NEED_MORE_ARGUMENTS_HTTP_HOST_PORT_URI_METHOD_USER_SIGN_PATH_NOSIGN_JSON);
370 return;
371 } catch (final IOException e) {
372 logger.error(
373 NEED_MORE_ARGUMENTS_HTTP_HOST_PORT_URI_METHOD_USER_SIGN_PATH_NOSIGN_JSON);
374 return;
375 }
376 }
377 String json = null;
378 if (args.length > 5) {
379 json = args[5].replace("'", "\"");
380 }
381 final HttpMethod method = HttpMethod.valueOf(meth);
382 int port = -1;
383 final String host;
384 final String path;
385 try {
386 final URI realUri = new URI(uri);
387 port = realUri.getPort();
388 host = realUri.getHost();
389 path = realUri.getPath();
390 } catch (final URISyntaxException e) {
391 logger.error("Error: {}", e.getMessage());
392 return;
393 }
394 final HttpRestClientHelper client = new HttpRestClientHelper(path, 1, 30000,
395 new HttpRestClientSimpleInitializer());
396 final Channel channel = client.getChannel(host, port);
397 if (channel == null) {
398 client.closeAll();
399 logger.error("Cannot connect to " + host + " on port " + port);
400 return;
401 }
402 final RestFuture future;
403 if (sign) {
404 future =
405 client.sendQuery(hmacSha256, channel, method, host, null, user, pwd,
406 null, json);
407 } else {
408 future = client.sendQuery(channel, method, host, null, user, null, json);
409 }
410 future.awaitOrInterruptible();
411 WaarpSslUtility.closingSslChannel(channel);
412 if (future.isSuccess()) {
413 logger.warn(future.getRestArgument().prettyPrint());
414 } else {
415 final RestArgument ra = future.getRestArgument();
416 if (ra != null) {
417 logger.error(ra.prettyPrint());
418 } else {
419 logger.error("Query in error", future.getCause());
420 }
421 }
422 client.closeAll();
423 }
424 }