2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (C) 2018 IBM.
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
23 package org.onap.logging.filter.base;
25 import java.io.BufferedReader;
26 import java.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.io.PrintWriter;
32 import java.util.Enumeration;
33 import java.util.zip.GZIPInputStream;
34 import javax.servlet.Filter;
35 import javax.servlet.FilterChain;
36 import javax.servlet.FilterConfig;
37 import javax.servlet.ReadListener;
38 import javax.servlet.ServletException;
39 import javax.servlet.ServletInputStream;
40 import javax.servlet.ServletOutputStream;
41 import javax.servlet.ServletRequest;
42 import javax.servlet.ServletResponse;
43 import javax.servlet.WriteListener;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.servlet.http.HttpServletRequestWrapper;
46 import javax.servlet.http.HttpServletResponse;
47 import javax.servlet.http.HttpServletResponseWrapper;
48 import javax.ws.rs.core.HttpHeaders;
50 public class PayloadLoggingServletFilter implements Filter {
52 private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PayloadLoggingServletFilter.class);
53 private static final String REDACTED = "***REDACTED***";
55 private static class ByteArrayServletStream extends ServletOutputStream {
56 ByteArrayOutputStream baos;
58 ByteArrayServletStream(ByteArrayOutputStream baos) {
63 public void write(int param) throws IOException {
68 public boolean isReady() {
73 public void setWriteListener(WriteListener arg0) {
74 // this method does nothing
78 private static class ByteArrayPrintWriter extends PrintWriter {
79 private ByteArrayOutputStream baos;
80 private int errorCode = -1;
81 private String errorMsg = "";
82 private boolean errored = false;
84 public ByteArrayPrintWriter(ByteArrayOutputStream out) {
89 public ServletOutputStream getStream() {
90 return new ByteArrayServletStream(baos);
93 public Boolean hasErrored() {
97 public int getErrorCode() {
101 public String getErrorMsg() {
105 public void setError(int code) {
110 public void setError(int code, String msg) {
118 private class BufferedServletInputStream extends ServletInputStream {
119 ByteArrayInputStream bais;
121 public BufferedServletInputStream(ByteArrayInputStream bais) {
126 public int available() {
127 return bais.available();
136 public int read(byte[] buf, int off, int len) {
137 return bais.read(buf, off, len);
141 public boolean isFinished() {
142 return available() < 1;
146 public boolean isReady() {
151 public void setReadListener(ReadListener arg0) {
152 // this method does nothing
157 private class BufferedRequestWrapper extends HttpServletRequestWrapper {
158 ByteArrayInputStream bais;
159 ByteArrayOutputStream baos;
160 BufferedServletInputStream bsis;
163 public BufferedRequestWrapper(HttpServletRequest req) throws IOException {
166 InputStream is = req.getInputStream();
167 baos = new ByteArrayOutputStream();
168 byte[] buf = new byte[1024];
170 while ((letti = is.read(buf)) > 0) {
171 baos.write(buf, 0, letti);
173 buffer = baos.toByteArray();
177 public ServletInputStream getInputStream() {
179 bais = new ByteArrayInputStream(buffer);
180 bsis = new BufferedServletInputStream(bais);
181 } catch (Exception ex) {
182 log.error("Exception in getInputStream", ex);
187 public byte[] getBuffer() {
193 public void init(FilterConfig filterConfig) throws ServletException {
194 // this method does nothing
198 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
199 throws IOException, ServletException {
200 final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
201 BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpRequest);
203 StringBuilder requestHeaders = new StringBuilder("REQUEST|");
204 requestHeaders.append(httpRequest.getMethod());
205 requestHeaders.append(":");
206 requestHeaders.append(httpRequest.getRequestURL().toString());
207 requestHeaders.append("|");
208 requestHeaders.append(getSecureRequestHeaders(httpRequest));
209 log.info(requestHeaders.toString());
211 log.info("REQUEST BODY|" + new String(bufferedRequest.getBuffer()));
213 final HttpServletResponse response = (HttpServletResponse) servletResponse;
214 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
215 final ByteArrayPrintWriter pw = new ByteArrayPrintWriter(baos);
217 HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
219 public PrintWriter getWriter() {
224 public ServletOutputStream getOutputStream() {
225 return pw.getStream();
229 public void sendError(int sc) throws IOException {
236 public void sendError(int sc, String msg) throws IOException {
237 super.sendError(sc, msg);
238 pw.setError(sc, msg);
243 filterChain.doFilter(bufferedRequest, wrappedResp);
244 } catch (Exception e) {
245 log.error("Chain Exception", e);
249 byte[] bytes = baos.toByteArray();
250 StringBuilder responseHeaders = new StringBuilder("RESPONSE HEADERS|");
251 responseHeaders.append(formatResponseHeaders(response));
252 responseHeaders.append("Status:");
253 responseHeaders.append(response.getStatus());
254 responseHeaders.append(";IsCommited:" + wrappedResp.isCommitted());
256 log.info(responseHeaders.toString());
258 if ("gzip".equals(response.getHeader("Content-Encoding"))) {
259 log.info("UNGZIPED RESPONSE BODY|" + decompressGZIPByteArray(bytes));
261 log.info("RESPONSE BODY|" + new String(bytes));
264 if (pw.hasErrored()) {
265 log.info("ERROR RESPONSE|" + pw.getErrorCode() + ":" + pw.getErrorMsg());
267 if (!wrappedResp.isCommitted()) {
268 response.getOutputStream().write(bytes);
269 response.getOutputStream().flush();
272 } catch (Exception e) {
273 log.error("Exception in response filter", e);
279 public void destroy() {
280 // this method does nothing
283 private String decompressGZIPByteArray(byte[] bytes) {
284 BufferedReader in = null;
285 InputStreamReader inR = null;
286 ByteArrayInputStream byteS = null;
287 GZIPInputStream gzS = null;
288 StringBuilder str = new StringBuilder();
290 byteS = new ByteArrayInputStream(bytes);
291 gzS = new GZIPInputStream(byteS);
292 inR = new InputStreamReader(gzS);
293 in = new BufferedReader(inR);
297 while ((content = in.readLine()) != null) {
302 } catch (Exception e) {
303 log.error("Failed get read GZIPInputStream", e);
308 } catch (IOException e1) {
309 log.error("Failed to close ByteStream", e1);
314 } catch (IOException e2) {
315 log.error("Failed to close GZStream", e2);
320 } catch (IOException e3) {
321 log.error("Failed to close InputReader", e3);
326 } catch (IOException e) {
327 log.error("Failed to close BufferedReader", e);
330 return str.toString();
333 protected String getSecureRequestHeaders(HttpServletRequest httpRequest) {
334 StringBuilder sb = new StringBuilder();
336 for (Enumeration<String> e = httpRequest.getHeaderNames(); e.hasMoreElements();) {
337 header = e.nextElement();
340 if (header.equalsIgnoreCase(HttpHeaders.AUTHORIZATION)) {
343 sb.append(httpRequest.getHeader(header));
347 return sb.toString();
350 protected String formatResponseHeaders(HttpServletResponse response) {
351 StringBuilder sb = new StringBuilder();
352 for (String headerName : response.getHeaderNames()) {
353 sb.append(headerName);
355 sb.append(response.getHeader(headerName));
358 return sb.toString();