/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.resiliency.spi.agent; import com.liferay.portal.kernel.io.AutoDeleteFileInputStream; import com.liferay.portal.kernel.model.Portlet; import com.liferay.portal.kernel.resiliency.spi.SPIUtil; import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction; import com.liferay.portal.kernel.servlet.PersistentHttpServletRequestWrapper; import com.liferay.portal.kernel.servlet.ServletInputStreamAdapter; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.upload.FileItem; import com.liferay.portal.kernel.upload.UploadServletRequest; import com.liferay.portal.kernel.util.ArrayUtil; import com.liferay.portal.kernel.util.ContentTypes; import com.liferay.portal.kernel.util.CookieUtil; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.SetUtil; import com.liferay.portal.kernel.util.StreamUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.WebKeys; import com.liferay.portal.upload.UploadServletRequestImpl; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.Serializable; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.ServletInputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; /** * @author Shuyang Zhou */ public class SPIAgentRequest extends SPIAgentSerializable { public static void populatePortletSessionAttributes( HttpServletRequest request, HttpSession session) { if (!SPIUtil.isSPI()) { return; } if (request.getAttribute(WebKeys.PORTLET_SESSION) != null) { return; } SPIAgentRequest spiAgentRequest = (SPIAgentRequest)request.getAttribute( WebKeys.SPI_AGENT_REQUEST); if (spiAgentRequest == null) { return; } request.setAttribute(WebKeys.PORTLET_SESSION, session); Map<String, Serializable> originalSessionAttributes = spiAgentRequest.originalSessionAttributes; Map<String, Serializable> portletSessionAttributes = (Map<String, Serializable>)originalSessionAttributes.remove( WebKeys.PORTLET_SESSION_ATTRIBUTES.concat( spiAgentRequest.servletContextName)); Set<String> sessionAttributeNames = SetUtil.fromEnumeration( session.getAttributeNames()); if (portletSessionAttributes != null) { for (Map.Entry<String, Serializable> entry : portletSessionAttributes.entrySet()) { session.setAttribute(entry.getKey(), entry.getValue()); } sessionAttributeNames.removeAll(portletSessionAttributes.keySet()); } for (String sessionAttributeName : sessionAttributeNames) { session.removeAttribute(sessionAttributeName); } } public SPIAgentRequest(HttpServletRequest request) throws IOException { super( ((Portlet)request.getAttribute( WebKeys.SPI_AGENT_PORTLET)).getContextName()); Cookie[] cookies = request.getCookies(); if (cookies != null) { cookiesBytes = new byte[cookies.length][]; for (int i = 0; i < cookies.length; i++) { cookiesBytes[i] = CookieUtil.serialize(cookies[i]); } } distributedRequestAttributes = extractDistributedRequestAttributes( request, Direction.REQUEST); headerMap = extractRequestHeaders(request); parameterMap = new HashMap<>(request.getParameterMap()); remoteAddr = request.getRemoteAddr(); remoteHost = request.getRemoteHost(); remotePort = request.getRemotePort(); remoteUser = request.getRemoteUser(); serverName = request.getServerName(); serverPort = request.getServerPort(); String contentType = request.getContentType(); if ((contentType != null) && contentType.startsWith(ContentTypes.MULTIPART)) { HttpServletRequest currentRequest = request; UploadServletRequest uploadServletRequest = null; while (currentRequest instanceof HttpServletRequestWrapper) { if (currentRequest instanceof UploadServletRequest) { uploadServletRequest = (UploadServletRequest)currentRequest; break; } HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper)currentRequest; currentRequest = (HttpServletRequest)httpServletRequestWrapper.getRequest(); } if (uploadServletRequest == null) { this.contentType = contentType; requestBodyFile = FileUtil.createTempFile(); StreamUtil.transfer( StreamUtil.uncloseable(currentRequest.getInputStream()), new FileOutputStream(requestBodyFile)); uploadServletRequest = new UploadServletRequestImpl( new AgentHttpServletRequestWrapper(currentRequest)); } Map<String, FileItem[]> multipartParameterMap = uploadServletRequest.getMultipartParameterMap(); Map<String, List<String>> regularParameterMap = uploadServletRequest.getRegularParameterMap(); if (!multipartParameterMap.isEmpty()) { this.multipartParameterMap = multipartParameterMap; } if (!regularParameterMap.isEmpty()) { this.regularParameterMap = regularParameterMap; } } ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( WebKeys.THEME_DISPLAY); if ((themeDisplay != null) && themeDisplay.isAjax()) { parameterMap = new HashMap<>(parameterMap); parameterMap.put( "portalResiliencyPortletShowFooter", new String[] {StringPool.FALSE}); } originalSessionAttributes = extractSessionAttributes(request); captureThreadLocals(); } public Map<String, Serializable> getOriginalSessionAttributes() { return originalSessionAttributes; } public HttpServletRequest populateRequest(HttpServletRequest request) { request = new AgentHttpServletRequestWrapper(request); for (Map.Entry<String, Serializable> entry : distributedRequestAttributes.entrySet()) { request.setAttribute(entry.getKey(), entry.getValue()); } if ((multipartParameterMap != null) || (regularParameterMap != null)) { request = new UploadServletRequestImpl( request, multipartParameterMap, regularParameterMap); } restoreThreadLocals(); return request; } public void populateSessionAttributes(HttpSession session) { for (Map.Entry<String, Serializable> entry : originalSessionAttributes.entrySet()) { session.setAttribute(entry.getKey(), entry.getValue()); } } @Override public String toString() { int length = 20 + parameterMap.size() * 4; if (cookiesBytes != null) { length += cookiesBytes.length * 2 - 1; } StringBundler sb = new StringBundler(length); sb.append("{contentType="); sb.append(contentType); sb.append(", cookies=["); if (cookiesBytes != null) { for (byte[] cookieBytes : cookiesBytes) { Cookie cookie = CookieUtil.deserialize(cookieBytes); sb.append(CookieUtil.toString(cookie)); sb.append(", "); } sb.setIndex(sb.index() - 1); } sb.append("], distributedRequestAttributes="); sb.append(distributedRequestAttributes); sb.append(", headerMap="); sb.append(headerMap); sb.append(", multipartParameterMap="); sb.append(multipartParameterMap); sb.append(", originalSessionAttributes="); sb.append(originalSessionAttributes); sb.append(", parameterMap={"); for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) { sb.append(entry.getKey()); sb.append("="); sb.append(Arrays.toString(entry.getValue())); sb.append(", "); } sb.setIndex(sb.index() - 1); sb.append("}, regularParameterMap="); sb.append(regularParameterMap); sb.append(", requestBodyFile="); sb.append(requestBodyFile); sb.append(", serverName="); sb.append(serverName); sb.append(", serverPort="); sb.append(serverPort); sb.append("}"); return sb.toString(); } protected String contentType; protected byte[][] cookiesBytes; protected Map<String, Serializable> distributedRequestAttributes; protected Map<String, List<String>> headerMap; protected Map<String, FileItem[]> multipartParameterMap; protected Map<String, Serializable> originalSessionAttributes; protected Map<String, String[]> parameterMap; protected Map<String, List<String>> regularParameterMap; protected String remoteAddr; protected String remoteHost; protected int remotePort; protected String remoteUser; protected File requestBodyFile; protected String serverName; protected int serverPort; protected class AgentHttpServletRequestWrapper extends PersistentHttpServletRequestWrapper { public AgentHttpServletRequestWrapper(HttpServletRequest request) { super(request); } @Override public int getContentLength() { if (requestBodyFile != null) { return (int)requestBodyFile.length(); } return super.getContentLength(); } @Override public String getContentType() { if (contentType != null) { return contentType; } return super.getContentType(); } @Override public Cookie[] getCookies() { if (cookiesBytes == null) { return null; } Cookie[] cookies = new Cookie[cookiesBytes.length]; for (int i = 0; i < cookies.length; i++) { cookies[i] = CookieUtil.deserialize(cookiesBytes[i]); } return cookies; } @Override public String getHeader(String name) { List<String> values = headerMap.get(StringUtil.toLowerCase(name)); if ((values == null) || values.isEmpty()) { return null; } return values.get(0); } @Override public Enumeration<String> getHeaderNames() { return Collections.enumeration(headerMap.keySet()); } @Override public Enumeration<String> getHeaders(String name) { List<String> values = headerMap.get(StringUtil.toLowerCase(name)); if (values == null) { values = Collections.emptyList(); } return Collections.enumeration(values); } @Override public ServletInputStream getInputStream() throws IOException { if (requestBodyFile != null) { return new ServletInputStreamAdapter( new AutoDeleteFileInputStream(requestBodyFile)); } return super.getInputStream(); } @Override public String getParameter(String name) { String[] values = parameterMap.get(name); if (ArrayUtil.isNotEmpty(values)) { return values[0]; } else { return null; } } @Override public Map<String, String[]> getParameterMap() { return parameterMap; } @Override public Enumeration<String> getParameterNames() { return Collections.enumeration(parameterMap.keySet()); } @Override public String[] getParameterValues(String name) { return parameterMap.get(name); } @Override public String getRemoteAddr() { return remoteAddr; } @Override public String getRemoteHost() { return remoteHost; } @Override public int getRemotePort() { return remotePort; } @Override public String getRemoteUser() { return remoteUser; } @Override public String getServerName() { return serverName; } @Override public int getServerPort() { return serverPort; } } }