diff --git a/jersey-servlet-example-annotations/pom.xml b/jersey-servlet-example-annotations/pom.xml
index 2c96779..680c602 100644
--- a/jersey-servlet-example-annotations/pom.xml
+++ b/jersey-servlet-example-annotations/pom.xml
@@ -103,7 +103,7 @@
com.moesif.servlet
moesif-servlet
- 1.8.1
+ 1.8.3
diff --git a/jersey-servlet-example-annotations/src/main/java/com/moesif/servlet/jersey/example/MoesifServletFilter.java b/jersey-servlet-example-annotations/src/main/java/com/moesif/servlet/jersey/example/MoesifServletFilter.java
index 559b887..1bd2756 100644
--- a/jersey-servlet-example-annotations/src/main/java/com/moesif/servlet/jersey/example/MoesifServletFilter.java
+++ b/jersey-servlet-example-annotations/src/main/java/com/moesif/servlet/jersey/example/MoesifServletFilter.java
@@ -15,7 +15,7 @@
urlPatterns ="/*",
initParams = {
@WebInitParam(name = "application-id",
- value = "Your Moesif Application Id"),
+ value = "eyJhcHAiOiIxOTg6NzQ0IiwidmVyIjoiMi4xIiwib3JnIjoiNjQwOjEyOCIsImlhdCI6MTczMDQxOTIwMH0.duHFw2GFPGinL-RL_Bv2QyvxNzwO2oqtxnieO22P2B0"),
@WebInitParam(name = "logBody", value = "true")
}
)
diff --git a/moesif-servlet/pom.xml b/moesif-servlet/pom.xml
index 6d1a794..5a86f93 100644
--- a/moesif-servlet/pom.xml
+++ b/moesif-servlet/pom.xml
@@ -43,8 +43,6 @@
1.8
2.17.0
3.4
- 1.1.3
- 1.8
@@ -69,16 +67,6 @@
commons-io
${commons-io.version}
-
- org.apache.logging.log4j
- log4j-api
- 2.17.2
-
-
- org.apache.logging.log4j
- log4j-core
- 2.17.2
-
@@ -87,12 +75,6 @@
4.13.2
test
-
- org.assertj
- assertj-core
- 3.23.1
- test
-
org.mockito
mockito-core
@@ -115,8 +97,8 @@
maven-compiler-plugin
3.10.1
- ${java.version}
- ${java.version}
+ ${maven.compiler.source}
+ ${maven.compiler.target}
@@ -161,7 +143,7 @@
sign-artifacts
verify
- sign
+
diff --git a/moesif-servlet/src/main/java/com/moesif/servlet/MoesifConfiguration.java b/moesif-servlet/src/main/java/com/moesif/servlet/MoesifConfiguration.java
index 3c9f66c..a989915 100644
--- a/moesif-servlet/src/main/java/com/moesif/servlet/MoesifConfiguration.java
+++ b/moesif-servlet/src/main/java/com/moesif/servlet/MoesifConfiguration.java
@@ -51,8 +51,6 @@ public EventModel maskContent(EventModel eventModel) {
public int queueSize = 1000000; // maximum queue capacity to hold events.
public int retry = 0; // how many times to retry, if fails to post events.ß
public int updateConfigTime = 5*60; // in seconds - time to update app config periodically.
- public int maxBodySize = 450 * 1024; // in bytes - max body size to capture.
- public boolean logBody = true;
@Deprecated
public String getTags(HttpServletRequest request, HttpServletResponse response) {
diff --git a/moesif-servlet/src/main/java/com/moesif/servlet/MoesifFilter.java b/moesif-servlet/src/main/java/com/moesif/servlet/MoesifFilter.java
index 469e869..01f5175 100644
--- a/moesif-servlet/src/main/java/com/moesif/servlet/MoesifFilter.java
+++ b/moesif-servlet/src/main/java/com/moesif/servlet/MoesifFilter.java
@@ -1,10 +1,12 @@
package com.moesif.servlet;
+import com.mashape.unirest.request.body.Body;
import com.moesif.api.BodyParser;
import com.moesif.api.IpAddress;
import com.moesif.api.MoesifAPIClient;
import com.moesif.api.controllers.APIController;
import com.moesif.api.models.*;
+import com.moesif.servlet.wrappers.BodyHandler;
import com.moesif.servlet.wrappers.LoggingHttpServletRequestWrapper;
import com.moesif.servlet.wrappers.LoggingHttpServletResponseWrapper;
import org.apache.commons.lang3.StringUtils;
@@ -25,6 +27,7 @@ public class MoesifFilter implements Filter {
private MoesifConfiguration config;
private MoesifAPIClient moesifApi;
private boolean debug;
+ private boolean logBody;
private BatchProcessor batchProcessor = null; // Manages queue & provides a taskRunner to send events in batches.
private int sendBatchJobAliveCounter = 0; // counter to check scheduled job is alive or not.
@@ -126,7 +129,8 @@ public void setDebug(boolean debug) {
* @param logBody boolean
*/
public void setLogBody(boolean logBody) {
- this.config.logBody = logBody;
+ this.logBody = logBody;
+ BodyHandler.logBody = logBody;
}
/**
@@ -365,8 +369,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
return;
}
- LoggingHttpServletRequestWrapper requestWrapper = new LoggingHttpServletRequestWrapper(httpRequest, config);
- LoggingHttpServletResponseWrapper responseWrapper = new LoggingHttpServletResponseWrapper(httpResponse, config);
+ LoggingHttpServletRequestWrapper requestWrapper = new LoggingHttpServletRequestWrapper(httpRequest);
+ LoggingHttpServletResponseWrapper responseWrapper = new LoggingHttpServletResponseWrapper(httpResponse);
// Initialize transactionId
@@ -465,13 +469,16 @@ private EventRequestModel getEventRequestModel(LoggingHttpServletRequestWrapper
}
- if (this.config.logBody) {
+ if (this.logBody) {
String content = requestWrapper.getContent();
if (content != null && !content.isEmpty()) {
BodyParser.BodyWrapper bodyWrapper = BodyParser.parseBody(requestWrapper.getHeaders(), content);
eventRequestBuilder.body(bodyWrapper.body);
eventRequestBuilder.transferEncoding(bodyWrapper.transferEncoding);
}
+ if (requestWrapper.bodySkipped) {
+ eventRequestBuilder.body(BodyHandler.getLargeBodyError(requestWrapper.contentLength));
+ }
}
return eventRequestBuilder.build();
@@ -485,13 +492,16 @@ private EventResponseModel getEventResponseModel(LoggingHttpServletResponseWrapp
.headers(responseWrapper.getHeaders());
- if (this.config.logBody) {
+ if (this.logBody) {
String content = responseWrapper.getContent();
if (content != null && !content.isEmpty()) {
BodyParser.BodyWrapper bodyWrapper = BodyParser.parseBody(responseWrapper.getHeaders(), content);
eventResponseBuilder.body(bodyWrapper.body);
eventResponseBuilder.transferEncoding(bodyWrapper.transferEncoding);
}
+ if (responseWrapper.bodySkipped) {
+ eventResponseBuilder.body(BodyHandler.getLargeBodyError(responseWrapper.contentLength));
+ }
}
return eventResponseBuilder.build();
diff --git a/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/BodyHandler.java b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/BodyHandler.java
new file mode 100644
index 0000000..d93ad94
--- /dev/null
+++ b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/BodyHandler.java
@@ -0,0 +1,32 @@
+package com.moesif.servlet.wrappers;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BodyHandler {
+
+ public static boolean logBody = true;
+ public static final int MAX_BODY_SIZE = 10; // Move to a common utility class
+
+ public static String encodeContent(byte[] content, String encoding) {
+ try {
+ return new String(content, encoding != null ? encoding : StandardCharsets.UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ return "[UNSUPPORTED ENCODING]";
+ }
+ }
+
+ // a method that returns a simple java map representing an error message for large body meant to be serialized into json
+ public static Map getLargeBodyError(long contentLength) {
+ Map error = new HashMap<>();
+ error.put("msg", "request.body.length " + contentLength + " exceeded requestMaxBodySize of " + MAX_BODY_SIZE + " bytes");
+ return error;
+ }
+
+}
diff --git a/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletRequestWrapper.java b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletRequestWrapper.java
index 248800f..9491cea 100644
--- a/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletRequestWrapper.java
+++ b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletRequestWrapper.java
@@ -1,6 +1,7 @@
package com.moesif.servlet.wrappers;
-import org.apache.commons.io.IOUtils;
+import com.moesif.servlet.MoesifConfiguration;
+import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
@@ -19,15 +20,14 @@
public class LoggingHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final List FORM_CONTENT_TYPE = Arrays.asList("application/x-www-form-urlencoded", "multipart/form-data");
-
private static final String METHOD_POST = "POST";
-
- private byte[] content;
-
private final Map parameterMap;
-
private final HttpServletRequest delegate;
+ private byte[] content;
+ public boolean bodySkipped = false;
+ public long contentLength = 0;
+
public LoggingHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.delegate = request;
@@ -38,14 +38,88 @@ public LoggingHttpServletRequestWrapper(HttpServletRequest request) {
}
}
+ private void readContentLength() {
+ try {
+ this.contentLength = Long.parseLong(getHeader("Content-Length"));
+ } catch (NumberFormatException e) {
+ // ignore malformed content length
+ }
+ }
+
+ private void updateContentLength(long length) {
+ if (contentLength == 0) {
+ contentLength = length;
+ }
+ }
+
+ private boolean shouldSkipBody() {
+ readContentLength();
+ // should skip if we are not logging body by config or content length is greater than max body size
+ return !BodyHandler.logBody || contentLength > BodyHandler.MAX_BODY_SIZE;
+ }
+
@Override
public ServletInputStream getInputStream() throws IOException {
- if (ArrayUtils.isEmpty(content)) {
+ if (bodySkipped || ArrayUtils.isEmpty(content)) {
return delegate.getInputStream();
}
return new LoggingServletInputStream(content);
}
+ public String getContent() {
+ try {
+ if (shouldSkipBody()) {
+ bodySkipped = true;
+ return null;
+ }
+
+ if (this.parameterMap.isEmpty()) {
+ content = boundedStreamToArray(delegate.getInputStream(), BodyHandler.MAX_BODY_SIZE);
+ if (content == null) {
+ bodySkipped = true;
+ return null;
+ }
+ } else {
+ content = getContentFromParameterMap(this.parameterMap);
+ if (content.length > BodyHandler.MAX_BODY_SIZE) {
+ bodySkipped = true;
+ return null;
+ }
+ }
+
+ String normalizedContent = BodyHandler.encodeContent(content, getCharacterEncoding());
+ updateContentLength(normalizedContent.length());
+ return normalizedContent;
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new IllegalStateException();
+ }
+ }
+
+ private byte[] boundedStreamToArray(InputStream inputStream, long maxBytes) {
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int totalBytesRead = 0;
+ int bytesRead;
+
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
+ totalBytesRead += bytesRead;
+ if (totalBytesRead > maxBytes) {
+ updateContentLength(totalBytesRead);
+ return null;
+ }
+ baos.write(buffer, 0, bytesRead);
+ }
+ updateContentLength(totalBytesRead);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ // this is not expected but would typically represent a dropped connection which we should not handle here
+ e.printStackTrace();
+ return null;
+ }
+ }
+
@Override
public BufferedReader getReader() throws IOException {
if (ArrayUtils.isEmpty(content)) {
@@ -90,23 +164,6 @@ public String[] getParameterValues(String name) {
return this.parameterMap.get(name);
}
- public String getContent() {
- try {
- if (this.parameterMap.isEmpty()) {
- content = IOUtils.toByteArray(delegate.getInputStream());
- } else {
- content = getContentFromParameterMap(this.parameterMap);
- }
- String requestEncoding = delegate.getCharacterEncoding();
- String normalizedContent = StringUtils.normalizeSpace(new String(content, requestEncoding != null ? requestEncoding : StandardCharsets.UTF_8.name()));
- return normalizedContent;
- // return StringUtils.isBlank(normalizedContent) ? "[EMPTY]" : normalizedContent;
- } catch (IOException e) {
- e.printStackTrace();
- throw new IllegalStateException();
- }
- }
-
private byte[] getContentFromParameterMap(Map parameterMap) {
List result = new ArrayList();
diff --git a/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletResponseWrapper.java b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletResponseWrapper.java
index e3b982d..937f98a 100644
--- a/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletResponseWrapper.java
+++ b/moesif-servlet/src/main/java/com/moesif/servlet/wrappers/LoggingHttpServletResponseWrapper.java
@@ -6,12 +6,17 @@
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
-import java.io.*;
-import java.util.*;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
public class LoggingHttpServletResponseWrapper extends HttpServletResponseWrapper {
+ public long contentLength = 0;
+ public boolean bodySkipped = false;
private ServletOutputStream outputStream;
private LoggingServletOutputStream logStream;
private PrintWriter writer;
@@ -61,7 +66,7 @@ public Map getHeaders() {
Map headers = new HashMap(0);
Collection headerNames = getHeaderNames();
- for (String headerName: headerNames) {
+ for (String headerName : headerNames) {
if (headerName != null) {
if (headerName.equals("set-cookie")) {
headers.put(headerName, getHeader(headerName));
@@ -73,31 +78,50 @@ public Map getHeaders() {
return headers;
}
+ private void readContentLength() {
+ try {
+ this.contentLength = Long.parseLong(getHeader("Content-Length"));
+ } catch (NumberFormatException e) {
+ // ignore malformed content length
+ }
+ }
+
+ private boolean shouldSkipBody() {
+ readContentLength();
+ // should skip if we are not logging body by config or content length is greater than max body size
+ return !BodyHandler.logBody || contentLength > BodyHandler.MAX_BODY_SIZE;
+ }
+
public String getContent() {
try {
flushBuffer();
- if (logStream == null) {
+ if (shouldSkipBody() || logStream == null || logStream.getBufferedStream() == null) {
return null;
}
+ updateContentLength(logStream.getBufferedStream().size());
String responseEncoding = getResponse().getCharacterEncoding();
- return logStream.baos.toString(responseEncoding != null ? responseEncoding : UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- return "[UNSUPPORTED ENCODING]";
+ return BodyHandler.encodeContent(logStream.getBufferedStream().toByteArray(), responseEncoding);
} catch (IOException e) {
return "[IO EXCEPTION]";
}
}
- private class LoggingServletOutputStream extends ServletOutputStream {
- public LoggingServletOutputStream(ServletOutputStream outputStream) {
-
- this.outputStream = outputStream;
- this.baos = new ByteArrayOutputStream(1024);
+ private void updateContentLength(long length) {
+ if (contentLength == 0) {
+ contentLength = length;
}
+ }
+ public class LoggingServletOutputStream extends ServletOutputStream {
+ public boolean bufferExceeded = false;
private ServletOutputStream outputStream;
private ByteArrayOutputStream baos;
+ public LoggingServletOutputStream(ServletOutputStream outputStream) {
+ this.outputStream = outputStream;
+ this.baos = new ByteArrayOutputStream();
+ }
+
@Override
public boolean isReady() {
return outputStream.isReady();
@@ -111,30 +135,47 @@ public void setWriteListener(WriteListener writeListener) {
@Override
public void write(int b) throws IOException {
outputStream.write(b);
- baos.write(b);
- }
-
- @Override
- public void write(byte[] b) throws IOException {
- outputStream.write(b);
- baos.write(b);
+ if (!bufferExceeded) {
+ if (baos.size() < BodyHandler.MAX_BODY_SIZE) {
+ baos.write(b);
+ } else {
+ bufferExceeded = true;
+ baos.close();
+ baos = null;
+ }
+ }
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
outputStream.write(b, off, len);
- baos.write(b, off, len);
+ if (!bufferExceeded) {
+ if (baos.size() + len <= BodyHandler.MAX_BODY_SIZE) {
+ baos.write(b, off, len);
+ } else {
+ bufferExceeded = true;
+ baos.close();
+ baos = null;
+ }
+ }
}
@Override
public void flush() throws IOException {
outputStream.flush();
- baos.flush();
+ if (!bufferExceeded) {
+ baos.flush();
+ }
}
+ @Override
public void close() throws IOException {
outputStream.close();
- baos.close();
+ if (baos != null) baos.close();
+ }
+
+ public ByteArrayOutputStream getBufferedStream() {
+ return baos;
}
}
}
diff --git a/servlet-example/pom.xml b/servlet-example/pom.xml
index aed3af4..f38fbff 100644
--- a/servlet-example/pom.xml
+++ b/servlet-example/pom.xml
@@ -28,7 +28,7 @@
com.moesif.servlet
moesif-servlet
- 1.8.1
+ 1.8.3