Skip to content

Commit

Permalink
Save body only if it is under the max limit otherwise add an error me…
Browse files Browse the repository at this point in the history
…ssage explaining this
  • Loading branch information
bakennedy committed Nov 16, 2024
1 parent b46f8f3 commit ff992d2
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 79 deletions.
2 changes: 1 addition & 1 deletion jersey-servlet-example-annotations/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
<dependency>
<groupId>com.moesif.servlet</groupId>
<artifactId>moesif-servlet</artifactId>
<version>1.8.1</version>
<version>1.8.3</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
)
Expand Down
24 changes: 3 additions & 21 deletions moesif-servlet/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@
<maven.compiler.target>1.8</maven.compiler.target>
<commons-io.version>2.17.0</commons-io.version>
<commons-lang3.version>3.4</commons-lang3.version>
<logback.version>1.1.3</logback.version>
<java.version>1.8</java.version>
</properties>

<dependencies>
Expand All @@ -69,16 +67,6 @@
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.2</version>
</dependency>

<!-- testing -->
<dependency>
Expand All @@ -87,12 +75,6 @@
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand All @@ -115,8 +97,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -161,7 +143,7 @@
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
<!-- <goal>sign</goal>-->
</goals>
<configuration>
<!-- This is necessary for gpg to not try to use the pinentry programs -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
20 changes: 15 additions & 5 deletions moesif-servlet/src/main/java/com/moesif/servlet/MoesifFilter.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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.

Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, String> getLargeBodyError(long contentLength) {
Map<String, String> error = new HashMap<>();
error.put("msg", "request.body.length " + contentLength + " exceeded requestMaxBodySize of " + MAX_BODY_SIZE + " bytes");
return error;
}

}
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -19,15 +20,14 @@
public class LoggingHttpServletRequestWrapper extends HttpServletRequestWrapper {

private static final List<String> 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<String, String[]> 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;
Expand All @@ -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)) {
Expand Down Expand Up @@ -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<String, String[]> parameterMap) {

List<String> result = new ArrayList<String>();
Expand Down
Loading

0 comments on commit ff992d2

Please sign in to comment.