Refactor logging to use slf4j
[iotivity.git] / cloud / stack / src / main / java / org / iotivity / cloud / base / protocols / http / HCProxyHandler.java
1 /*
2  * //******************************************************************
3  * //
4  * // Copyright 2016 Samsung Electronics All Rights Reserved.
5  * //
6  * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7  * //
8  * // Licensed under the Apache License, Version 2.0 (the "License");
9  * // you may not use this file except in compliance with the License.
10  * // You may obtain a copy of the License at
11  * //
12  * //      http://www.apache.org/licenses/LICENSE-2.0
13  * //
14  * // Unless required by applicable law or agreed to in writing, software
15  * // distributed under the License is distributed on an "AS IS" BASIS,
16  * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * // See the License for the specific language governing permissions and
18  * // limitations under the License.
19  * //
20  * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21  */
22 package org.iotivity.cloud.base.protocols.http;
23
24 import java.util.concurrent.ConcurrentHashMap;
25
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28 import org.iotivity.cloud.base.protocols.IResponse;
29 import org.iotivity.cloud.base.protocols.Message;
30
31 import io.netty.channel.ChannelDuplexHandler;
32 import io.netty.channel.ChannelFuture;
33 import io.netty.channel.ChannelFutureListener;
34 import io.netty.channel.ChannelHandlerContext;
35 import io.netty.channel.ChannelPromise;
36 import io.netty.handler.codec.http.HttpContent;
37 import io.netty.handler.codec.http.HttpHeaderNames;
38 import io.netty.handler.codec.http.HttpHeaders;
39 import io.netty.handler.codec.http.HttpRequest;
40 import io.netty.handler.codec.http.HttpResponse;
41 import io.netty.handler.codec.http.LastHttpContent;
42 import io.netty.util.CharsetUtil;
43
44 /**
45  * This channel handler intercepts HTTP request and CoAP response
46  * and translate them into CoAP request and HTTP response accordingly.
47  */
48 public class HCProxyHandler extends ChannelDuplexHandler {
49     private final static Logger Log = LoggerFactory.getLogger(HCProxyHandler.class);
50     private static ConcurrentHashMap<String, HCProxyProcessor> hcProxyProcessorMap
51     = new ConcurrentHashMap<String, HCProxyProcessor>();
52
53     @Override
54     public void channelRead(ChannelHandlerContext ctx, Object msg)
55             throws Exception {
56
57         // Wait translating the request until the end of content is received
58         if (msg instanceof HttpRequest) {
59
60             StringBuilder contentStrBuilder = new StringBuilder();
61             ctx.channel().attr(HCProxyProcessor.ctxStrContent)
62                     .set(contentStrBuilder);
63
64             HttpRequest httpRequest = (HttpRequest) msg;
65
66             HCProxyProcessor hcProxyProcessor = new HCProxyProcessor(ctx);
67
68             HCProxyHandler.hcProxyProcessorMap
69                     .put(ctx.channel().id().asLongText(), hcProxyProcessor);
70
71             // Set the values for required attributes in hcProxyProcessor
72             hcProxyProcessor.setHttpMethod(httpRequest.method());
73             hcProxyProcessor.setHostingHttpUri(httpRequest.uri());
74             HttpHeaders httpHeaders = httpRequest.headers();
75             hcProxyProcessor.setContentType(
76                     httpHeaders.get(HttpHeaderNames.CONTENT_TYPE));
77
78             // Check Session-ID for the already signed-in transaction
79             hcProxyProcessor.checkSessionId(
80                     httpHeaders.get(HttpHeaderNames.COOKIE));
81         }
82
83         // Do not hand over the message to next handler until the end of content
84         if (msg instanceof HttpContent) {
85
86             HttpContent content = (HttpContent) msg;
87
88             StringBuilder contentStrBuilder = ctx.channel()
89                     .attr(HCProxyProcessor.ctxStrContent).get();
90             contentStrBuilder
91                     .append(content.content().toString(CharsetUtil.UTF_8));
92
93             if (content instanceof LastHttpContent) {
94
95                 HCProxyProcessor hcProxyProcessor = HCProxyHandler.hcProxyProcessorMap
96                         .get(ctx.channel().id().asLongText());
97
98                 if (hcProxyProcessor != null
99                         && hcProxyProcessor.getContentType() != null) {
100                     hcProxyProcessor.setContent(contentStrBuilder.toString());
101                 }
102
103                 contentStrBuilder.setLength(0);
104
105                 // Check HTTP request whether there is an error or not
106                 String errorStatusCode = hcProxyProcessor.checkHttpRequest();
107
108                 if (errorStatusCode != null) {
109
110                     Log.trace("HTTP Error: " + errorStatusCode);
111
112                     HttpResponse httpResponse = hcProxyProcessor
113                             .getErrorResponse(errorStatusCode);
114
115                     ctx.writeAndFlush(httpResponse);
116                 }
117
118                 // Create a message request from HTTP request
119                 Message message = null;
120
121                 if (hcProxyProcessor != null) {
122                     message = hcProxyProcessor.getRequestMessage();
123                 }
124
125                 if (message != null) {
126                     ctx.fireChannelRead(message);
127                 } else {
128                     errorStatusCode = "500 Internal Server Error: "
129                             + "HTTP-Method does not recognized.";
130
131                     Log.trace("HTTP Error: " + errorStatusCode);
132
133                     HttpResponse httpResponse = hcProxyProcessor
134                             .getErrorResponse(errorStatusCode);
135
136                     ctx.writeAndFlush(httpResponse);
137                 }
138             }
139         }
140     }
141
142     @Override
143     public void write(ChannelHandlerContext ctx, Object msg,
144             ChannelPromise promise) {
145
146         // Create HTTP response from the response
147         HttpResponse httpResponse = null;
148
149         if (msg instanceof IResponse) {
150
151             IResponse response = (IResponse) msg;
152
153             HCProxyProcessor hcProxyProcessor = HCProxyHandler.hcProxyProcessorMap
154                     .get(ctx.channel().id().asLongText());
155
156             if (hcProxyProcessor != null) {
157
158                 /*
159                  * If HTTP request was sign-in and HTTP response is 200 OK,
160                  * then set HTTP Cookie in the response for the session.
161                  */
162                 httpResponse = hcProxyProcessor.getHttpResponse(response);
163             }
164
165             if (httpResponse == null) {
166                 String errorStatusCode = "500 Internal Server Error: "
167                         + "HTTP response could not be generated.";
168
169                 Log.trace("HTTP Error: " + errorStatusCode);
170
171                 httpResponse = hcProxyProcessor
172                         .getErrorResponse(errorStatusCode);
173             }
174
175             msg = httpResponse;
176         }
177
178         ChannelFuture future = ctx.writeAndFlush(msg);
179
180         // Close the http connection after sending response
181         future.addListener(new ChannelFutureListener() {
182
183             @Override
184             public void operationComplete(ChannelFuture future)
185                     throws Exception {
186
187                 if (future.isSuccess()) {
188                     future.channel().close();
189                 } else {
190                     Log.warn("[{}] HTTP Disconnected (Unexpectedly), Address: {}",
191                             ctx.channel().id().asLongText().substring(26),
192                             ctx.channel().remoteAddress().toString());
193                 }
194             }
195         });
196     }
197 }