View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  /*
22   * Copyright 2009 Red Hat, Inc.
23   *
24   * Red Hat licenses this file to you under the Apache License, version 2.0 (the
25   * "License"); you may not use this file except in compliance with the License.
26   * You may obtain a copy of the License at:
27   *
28   * http://www.apache.org/licenses/LICENSE-2.0
29   *
30   * Unless required by applicable law or agreed to in writing, software
31   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
32   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
33   * License for the specific language governing permissions and limitations under
34   * the License.
35   */
36  package org.waarp.gateway.kernel.rest.client;
37  
38  import com.fasterxml.jackson.databind.JsonNode;
39  import com.fasterxml.jackson.databind.node.ObjectNode;
40  import io.netty.buffer.ByteBuf;
41  import io.netty.buffer.Unpooled;
42  import io.netty.channel.Channel;
43  import io.netty.channel.ChannelHandlerContext;
44  import io.netty.channel.SimpleChannelInboundHandler;
45  import io.netty.handler.codec.http.HttpContent;
46  import io.netty.handler.codec.http.HttpHeaderNames;
47  import io.netty.handler.codec.http.HttpObject;
48  import io.netty.handler.codec.http.HttpResponse;
49  import io.netty.handler.codec.http.HttpResponseStatus;
50  import io.netty.handler.codec.http.LastHttpContent;
51  import io.netty.util.AttributeKey;
52  import org.waarp.common.crypto.ssl.WaarpSslUtility;
53  import org.waarp.common.json.JsonHandler;
54  import org.waarp.common.logging.WaarpLogger;
55  import org.waarp.common.logging.WaarpLoggerFactory;
56  import org.waarp.common.utility.WaarpStringUtils;
57  import org.waarp.gateway.kernel.exception.HttpIncorrectRequestException;
58  import org.waarp.gateway.kernel.rest.RestArgument;
59  
60  import java.net.ConnectException;
61  import java.nio.channels.ClosedChannelException;
62  
63  /**
64   *
65   */
66  public class HttpRestClientSimpleResponseHandler
67      extends SimpleChannelInboundHandler<HttpObject> {
68    /**
69     * Internal Logger
70     */
71    private static final WaarpLogger logger =
72        WaarpLoggerFactory.getLogger(HttpRestClientSimpleResponseHandler.class);
73  
74    public static final AttributeKey<RestFuture> RESTARGUMENT =
75        AttributeKey.valueOf("RestClient.Argument");
76  
77    private ByteBuf cumulativeBody;
78    protected JsonNode jsonObject;
79  
80    protected void actionFromResponse(final Channel channel) {
81      final RestArgument ra = new RestArgument((ObjectNode) jsonObject);
82      if (jsonObject == null) {
83        logger.warn("Recv: EMPTY");
84      } else {
85        logger.warn(ra.prettyPrint());
86      }
87      final RestFuture restFuture = channel.attr(RESTARGUMENT).get();
88      restFuture.setRestArgument(ra);
89      if (ra.getStatusCode() == HttpResponseStatus.OK.code()) {
90        restFuture.setSuccess();
91      } else {
92        logger.error("Error: " + ra.getStatusMessage());
93        restFuture.cancel();
94        if (channel.isActive()) {
95          WaarpSslUtility.closingSslChannel(channel);
96        }
97      }
98    }
99  
100   @Override
101   protected void channelRead0(final ChannelHandlerContext ctx,
102                               final HttpObject msg) throws Exception {
103     if (msg instanceof HttpResponse) {
104       final HttpResponse response = (HttpResponse) msg;
105       final HttpResponseStatus status = response.status();
106       logger.debug("{}: {} STATUS: {}", HttpHeaderNames.REFERER,
107                    response.headers().get(HttpHeaderNames.REFERER), status);
108     }
109     if (msg instanceof HttpContent) {
110       final HttpContent chunk = (HttpContent) msg;
111       if (chunk instanceof LastHttpContent) {
112         final ByteBuf content = chunk.content();
113         if (content != null && content.isReadable()) {
114           if (cumulativeBody != null) {
115             cumulativeBody = Unpooled.wrappedBuffer(cumulativeBody, content);
116           } else {
117             cumulativeBody = content;
118           }
119         }
120         // get the Json equivalent of the Body
121         if (cumulativeBody == null) {
122           jsonObject = JsonHandler.createObjectNode();
123         } else {
124           try {
125             final String json = cumulativeBody.toString(WaarpStringUtils.UTF8);
126             jsonObject = JsonHandler.getFromString(json);
127           } catch (final Throwable e2) {
128             logger.warn("Error" + " : {}", e2.getMessage());
129             throw new HttpIncorrectRequestException(e2);
130           }
131           cumulativeBody = null;
132         }
133         actionFromResponse(ctx.channel());
134       } else {
135         final ByteBuf content = chunk.content();
136         if (content != null && content.isReadable()) {
137           if (cumulativeBody != null) {
138             cumulativeBody = Unpooled.wrappedBuffer(cumulativeBody, content);
139           } else {
140             cumulativeBody = content;
141           }
142         }
143       }
144     }
145   }
146 
147   @Override
148   public void exceptionCaught(final ChannelHandlerContext ctx,
149                               final Throwable cause) {
150     final RestFuture restFuture = ctx.channel().attr(RESTARGUMENT).get();
151     if (cause instanceof ClosedChannelException) {
152       restFuture.setFailure(cause);
153       logger.debug("Close before ending");
154       return;
155     } else if (cause instanceof ConnectException) {
156       restFuture.setFailure(cause);
157       if (ctx.channel().isActive()) {
158         logger.debug("Will close");
159         WaarpSslUtility.closingSslChannel(ctx.channel());
160       }
161       return;
162     }
163     restFuture.setFailure(cause);
164     logger.error("Error", cause);
165     WaarpSslUtility.closingSslChannel(ctx.channel());
166   }
167 
168 }