localhost-back/src/main/java/io/company/localhost/common/wrapper/CachedBodyRequestWrapper.java
2024-12-09 12:45:15 +09:00

133 lines
4.2 KiB
Java

package io.company.localhost.common.wrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import io.company.localhost.utils.JacksonUtil;
import io.netty.handler.codec.ValueConverter;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
// body 읽어서 cash로 만듬
// 필요하면 filter로 사용
@Slf4j
public class CachedBodyRequestWrapper extends HttpServletRequestWrapper {
private final Charset encoding;
private final byte[] cachedBody;
private ValueConverter targetConvert;
public CachedBodyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String characterEncoding = request.getCharacterEncoding();
if (StringUtils.hasText(characterEncoding) == false) {
characterEncoding = StandardCharsets.UTF_8.name();
}
// XSS 방지를 이곳에서 하지 않을 경우 아래주석 해제 후 아래 //XSS 방지 이후 코드 삭제
// InputStream requestInputStream = request.getInputStream();
// this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
this.encoding = Charset.forName(characterEncoding);
// XSS 방지
String requestBody = null;
try {
requestBody = StreamUtils.copyToString(request.getInputStream(), Charset.defaultCharset());
} catch (IOException e) {
log.error("StreamUtil.toString Exception", e);
}
if (requestBody == null) {
InputStream requestInputStream = request.getInputStream();
this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
return;
}
Object bodyObject = null;
if (requestBody.startsWith("[")) { // List
bodyObject = JacksonUtil.fromJson(requestBody, new TypeReference<List<Map<String, Object>>>() {
});
} else { // Map
bodyObject = JacksonUtil.fromJson(requestBody, new TypeReference<Map<String, Object>>() {
});
}
String newRequestBody = JacksonUtil.toJson(bodyObject);
if (Objects.isNull(newRequestBody)) {
newRequestBody = new String("");
}
this.cachedBody = newRequestBody.getBytes(StandardCharsets.UTF_8);
}
/** json body 관련 메소드 START */
@Override
public ServletInputStream getInputStream() throws IOException {
return new CachedBodyServletInputStream(this.cachedBody);
}
@Override
public BufferedReader getReader() throws IOException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody);
return new BufferedReader(new InputStreamReader(byteArrayInputStream, encoding));
}
/** json body 관련 메소드 END */
private class CachedBodyServletInputStream extends ServletInputStream {
private InputStream cachedBodyInputStream;
public CachedBodyServletInputStream(byte[] cachedBody) {
this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody);
}
@Override
public boolean isFinished() {
try {
return this.cachedBodyInputStream.available() == 0;
} catch (IOException e) {
log.error("", e);
return false;
}
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new UnsupportedOperationException();
}
@Override
public int read() throws IOException {
return this.cachedBodyInputStream.read();
}
}
}