package com.github.bjuvensjo.rsimulator.recorder; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Record proxy traffic to file * * @author Anders Bälter */ public class Recorder implements Filter { private Logger log = LoggerFactory.getLogger(Recorder.class); private static final Pattern ACCEPT_PATTERN = Pattern.compile("([^;]+)"); private static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile("([^;]+)"); private static final Pattern CHARSET_PATTERN = Pattern.compile("charset=([0-9A-Z-]+)"); private static final String ENCODING = "UTF-8"; private Map<String, String> contentTypes = new HashMap<String, String>(); private Map<String, String> accepts = new HashMap<String, String>(); private Config config; private RecorderScriptRunner recorderScriptRunner; { contentTypes.put("application/json", "json"); contentTypes.put("application/xml", "xml"); contentTypes.put("application/soap+xml", "xml"); contentTypes.put("text/xml", "xml"); contentTypes.put("default", "txt"); accepts.put("application/json", "json"); accepts.put("default", "txt"); } @Override public void init(FilterConfig filterConfig) throws ServletException { config = new Config(); recorderScriptRunner = new RecorderScriptRunner(config); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; if (recorderIsOn()) { log.debug("Recording request"); RecorderServletRequestWrapper recorderRequest = new RecorderServletRequestWrapper(httpServletRequest); RecorderServletResponseWrapper recorderResponse = new RecorderServletResponseWrapper(httpServletResponse); String contentType = recorderRequest.getContentType(); String encoding = getEncoding(contentType); recorderScriptRunner.runRequestScript(recorderRequest, recorderResponse, encoding); String path = buildPath(recorderRequest); log.debug("Creating directory: {}", path); (new File(path)).mkdirs(); String fileType = fileType(contentType, recorderRequest.getHeader("Accept")); log.debug("Content-Type: {}", contentType); String filePrefix = (String)recorderRequest.getAttribute(Constants.FILE_PREFIX); String fileURI = buildFileURI(path, filePrefix, Constants.REQUEST_FILENAME, fileType); log.debug("Writing request file: {}", fileURI); String requestData = (String)recorderRequest.getAttribute(Constants.REQUEST_BODY_TO_RECORD); FileUtils.writeStringToFile(new File(fileURI), requestData, ENCODING); chain.doFilter(recorderRequest, recorderResponse); log.debug("Recording response"); recorderScriptRunner.runResponseScript(recorderRequest, recorderResponse, encoding); fileURI = buildFileURI(path, filePrefix, Constants.RESPONSE_FILENAME, fileType); String responseData = (String)recorderRequest.getAttribute(Constants.RESPONSE_BODY_TO_RECORD); log.debug("Writing response file: {}", fileURI); FileUtils.writeStringToFile(new File(fileURI), responseData, ENCODING); response.getOutputStream().write(recorderResponse.getBytes()); } else { chain.doFilter(request, response); } } @Override public void destroy() { } private String buildFileURI(String path, String filePrefix, String fileSuffix, String fileType) { return new StringBuilder(path).append(File.separator).append(filePrefix).append(fileSuffix) .append(".").append(fileType).toString(); } private String fileType(String contentType, String accept) { String result = null; if (contentType != null) { Matcher m = CONTENT_TYPE_PATTERN.matcher(contentType); if (m.find()) { result = contentTypes.get(m.group(1)); } } if (result == null) { if (accept != null) { Matcher m = ACCEPT_PATTERN.matcher(accept); if (m.find()) { String[] split = m.group(1).split(" *, *"); for (int i = 0; result == null && i < split.length; i++) { result = accepts.get(split[i]); } } } } if (result == null) { result = contentTypes.get("default"); } return result; } private String getEncoding(String contentType) { String result = ENCODING; if (contentType != null) { Matcher m = CHARSET_PATTERN.matcher(contentType); if (m.find()) { result = m.group(1); } } return result; } private boolean recorderIsOn() { return config.getBoolean(Config.RECORDER_IS_ON); } private String buildPath(HttpServletRequest request) { String requestedUriWithoutContext = (String)request.getAttribute(Constants.RELATIVE_RECORD_PATH); String basePath = (String)request.getAttribute(Constants.BASE_PATH); return new StringBuilder(basePath).append(File.separator).append(requestedUriWithoutContext).toString(); } }