001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.resiliency.spi.agent;
016    
017    import com.liferay.portal.kernel.io.AutoDeleteFileInputStream;
018    import com.liferay.portal.kernel.model.Portlet;
019    import com.liferay.portal.kernel.resiliency.spi.SPIUtil;
020    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction;
021    import com.liferay.portal.kernel.servlet.PersistentHttpServletRequestWrapper;
022    import com.liferay.portal.kernel.servlet.ServletInputStreamAdapter;
023    import com.liferay.portal.kernel.theme.ThemeDisplay;
024    import com.liferay.portal.kernel.upload.FileItem;
025    import com.liferay.portal.kernel.upload.UploadServletRequest;
026    import com.liferay.portal.kernel.util.ArrayUtil;
027    import com.liferay.portal.kernel.util.ContentTypes;
028    import com.liferay.portal.kernel.util.CookieUtil;
029    import com.liferay.portal.kernel.util.FileUtil;
030    import com.liferay.portal.kernel.util.SetUtil;
031    import com.liferay.portal.kernel.util.StreamUtil;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.StringUtil;
035    import com.liferay.portal.kernel.util.WebKeys;
036    import com.liferay.portal.upload.UploadServletRequestImpl;
037    
038    import java.io.File;
039    import java.io.FileOutputStream;
040    import java.io.IOException;
041    import java.io.Serializable;
042    
043    import java.util.Arrays;
044    import java.util.Collections;
045    import java.util.Enumeration;
046    import java.util.HashMap;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Set;
050    
051    import javax.servlet.ServletInputStream;
052    import javax.servlet.http.Cookie;
053    import javax.servlet.http.HttpServletRequest;
054    import javax.servlet.http.HttpServletRequestWrapper;
055    import javax.servlet.http.HttpSession;
056    
057    /**
058     * @author Shuyang Zhou
059     */
060    public class SPIAgentRequest extends SPIAgentSerializable {
061    
062            public static void populatePortletSessionAttributes(
063                    HttpServletRequest request, HttpSession session) {
064    
065                    if (!SPIUtil.isSPI()) {
066                            return;
067                    }
068    
069                    if (request.getAttribute(WebKeys.PORTLET_SESSION) != null) {
070                            return;
071                    }
072    
073                    SPIAgentRequest spiAgentRequest = (SPIAgentRequest)request.getAttribute(
074                            WebKeys.SPI_AGENT_REQUEST);
075    
076                    if (spiAgentRequest == null) {
077                            return;
078                    }
079    
080                    request.setAttribute(WebKeys.PORTLET_SESSION, session);
081    
082                    Map<String, Serializable> originalSessionAttributes =
083                            spiAgentRequest.originalSessionAttributes;
084    
085                    Map<String, Serializable> portletSessionAttributes =
086                            (Map<String, Serializable>)originalSessionAttributes.remove(
087                                    WebKeys.PORTLET_SESSION_ATTRIBUTES.concat(
088                                            spiAgentRequest.servletContextName));
089    
090                    Set<String> sessionAttributeNames = SetUtil.fromEnumeration(
091                            session.getAttributeNames());
092    
093                    if (portletSessionAttributes != null) {
094                            for (Map.Entry<String, Serializable> entry :
095                                            portletSessionAttributes.entrySet()) {
096    
097                                    session.setAttribute(entry.getKey(), entry.getValue());
098                            }
099    
100                            sessionAttributeNames.removeAll(portletSessionAttributes.keySet());
101                    }
102    
103                    for (String sessionAttributeName : sessionAttributeNames) {
104                            session.removeAttribute(sessionAttributeName);
105                    }
106            }
107    
108            public SPIAgentRequest(HttpServletRequest request) throws IOException {
109                    super(
110                            ((Portlet)request.getAttribute(
111                                    WebKeys.SPI_AGENT_PORTLET)).getContextName());
112    
113                    Cookie[] cookies = request.getCookies();
114    
115                    if (cookies != null) {
116                            cookiesBytes = new byte[cookies.length][];
117    
118                            for (int i = 0; i < cookies.length; i++) {
119                                    cookiesBytes[i] = CookieUtil.serialize(cookies[i]);
120                            }
121                    }
122    
123                    distributedRequestAttributes = extractDistributedRequestAttributes(
124                            request, Direction.REQUEST);
125                    headerMap = extractRequestHeaders(request);
126                    parameterMap = new HashMap<>(request.getParameterMap());
127                    remoteAddr = request.getRemoteAddr();
128                    remoteHost = request.getRemoteHost();
129                    remotePort = request.getRemotePort();
130                    remoteUser = request.getRemoteUser();
131                    serverName = request.getServerName();
132                    serverPort = request.getServerPort();
133    
134                    String contentType = request.getContentType();
135    
136                    if ((contentType != null) &&
137                            contentType.startsWith(ContentTypes.MULTIPART)) {
138    
139                            HttpServletRequest currentRequest = request;
140    
141                            UploadServletRequest uploadServletRequest = null;
142    
143                            while (currentRequest instanceof HttpServletRequestWrapper) {
144                                    if (currentRequest instanceof UploadServletRequest) {
145                                            uploadServletRequest = (UploadServletRequest)currentRequest;
146    
147                                            break;
148                                    }
149    
150                                    HttpServletRequestWrapper httpServletRequestWrapper =
151                                            (HttpServletRequestWrapper)currentRequest;
152    
153                                    currentRequest =
154                                            (HttpServletRequest)httpServletRequestWrapper.getRequest();
155                            }
156    
157                            if (uploadServletRequest == null) {
158                                    this.contentType = contentType;
159    
160                                    requestBodyFile = FileUtil.createTempFile();
161    
162                                    StreamUtil.transfer(
163                                            StreamUtil.uncloseable(currentRequest.getInputStream()),
164                                            new FileOutputStream(requestBodyFile));
165    
166                                    uploadServletRequest = new UploadServletRequestImpl(
167                                            new AgentHttpServletRequestWrapper(currentRequest));
168                            }
169    
170                            Map<String, FileItem[]> multipartParameterMap =
171                                    uploadServletRequest.getMultipartParameterMap();
172                            Map<String, List<String>> regularParameterMap =
173                                    uploadServletRequest.getRegularParameterMap();
174    
175                            if (!multipartParameterMap.isEmpty()) {
176                                    this.multipartParameterMap = multipartParameterMap;
177                            }
178    
179                            if (!regularParameterMap.isEmpty()) {
180                                    this.regularParameterMap = regularParameterMap;
181                            }
182                    }
183    
184                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
185                            WebKeys.THEME_DISPLAY);
186    
187                    if ((themeDisplay != null) && themeDisplay.isAjax()) {
188                            parameterMap = new HashMap<>(parameterMap);
189    
190                            parameterMap.put(
191                                    "portalResiliencyPortletShowFooter",
192                                    new String[] {StringPool.FALSE});
193                    }
194    
195                    originalSessionAttributes = extractSessionAttributes(request);
196    
197                    captureThreadLocals();
198            }
199    
200            public Map<String, Serializable> getOriginalSessionAttributes() {
201                    return originalSessionAttributes;
202            }
203    
204            public HttpServletRequest populateRequest(HttpServletRequest request) {
205                    request = new AgentHttpServletRequestWrapper(request);
206    
207                    for (Map.Entry<String, Serializable> entry :
208                                    distributedRequestAttributes.entrySet()) {
209    
210                            request.setAttribute(entry.getKey(), entry.getValue());
211                    }
212    
213                    if ((multipartParameterMap != null) || (regularParameterMap != null)) {
214                            request = new UploadServletRequestImpl(
215                                    request, multipartParameterMap, regularParameterMap);
216                    }
217    
218                    restoreThreadLocals();
219    
220                    return request;
221            }
222    
223            public void populateSessionAttributes(HttpSession session) {
224                    for (Map.Entry<String, Serializable> entry :
225                                    originalSessionAttributes.entrySet()) {
226    
227                            session.setAttribute(entry.getKey(), entry.getValue());
228                    }
229            }
230    
231            @Override
232            public String toString() {
233                    int length = 20 + parameterMap.size() * 4;
234    
235                    if (cookiesBytes != null) {
236                            length += cookiesBytes.length * 2 - 1;
237                    }
238    
239                    StringBundler sb = new StringBundler(length);
240    
241                    sb.append("{contentType=");
242                    sb.append(contentType);
243                    sb.append(", cookies=[");
244    
245                    if (cookiesBytes != null) {
246                            for (byte[] cookieBytes : cookiesBytes) {
247                                    Cookie cookie = CookieUtil.deserialize(cookieBytes);
248    
249                                    sb.append(CookieUtil.toString(cookie));
250                                    sb.append(", ");
251                            }
252    
253                            sb.setIndex(sb.index() - 1);
254                    }
255    
256                    sb.append("], distributedRequestAttributes=");
257                    sb.append(distributedRequestAttributes);
258                    sb.append(", headerMap=");
259                    sb.append(headerMap);
260                    sb.append(", multipartParameterMap=");
261                    sb.append(multipartParameterMap);
262                    sb.append(", originalSessionAttributes=");
263                    sb.append(originalSessionAttributes);
264                    sb.append(", parameterMap={");
265    
266                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
267                            sb.append(entry.getKey());
268                            sb.append("=");
269                            sb.append(Arrays.toString(entry.getValue()));
270                            sb.append(", ");
271                    }
272    
273                    sb.setIndex(sb.index() - 1);
274    
275                    sb.append("}, regularParameterMap=");
276                    sb.append(regularParameterMap);
277                    sb.append(", requestBodyFile=");
278                    sb.append(requestBodyFile);
279                    sb.append(", serverName=");
280                    sb.append(serverName);
281                    sb.append(", serverPort=");
282                    sb.append(serverPort);
283                    sb.append("}");
284    
285                    return sb.toString();
286            }
287    
288            protected String contentType;
289            protected byte[][] cookiesBytes;
290            protected Map<String, Serializable> distributedRequestAttributes;
291            protected Map<String, List<String>> headerMap;
292            protected Map<String, FileItem[]> multipartParameterMap;
293            protected Map<String, Serializable> originalSessionAttributes;
294            protected Map<String, String[]> parameterMap;
295            protected Map<String, List<String>> regularParameterMap;
296            protected String remoteAddr;
297            protected String remoteHost;
298            protected int remotePort;
299            protected String remoteUser;
300            protected File requestBodyFile;
301            protected String serverName;
302            protected int serverPort;
303    
304            protected class AgentHttpServletRequestWrapper
305                    extends PersistentHttpServletRequestWrapper {
306    
307                    public AgentHttpServletRequestWrapper(HttpServletRequest request) {
308                            super(request);
309                    }
310    
311                    @Override
312                    public int getContentLength() {
313                            if (requestBodyFile != null) {
314                                    return (int)requestBodyFile.length();
315                            }
316    
317                            return super.getContentLength();
318                    }
319    
320                    @Override
321                    public String getContentType() {
322                            if (contentType != null) {
323                                    return contentType;
324                            }
325    
326                            return super.getContentType();
327                    }
328    
329                    @Override
330                    public Cookie[] getCookies() {
331                            if (cookiesBytes == null) {
332                                    return null;
333                            }
334    
335                            Cookie[] cookies = new Cookie[cookiesBytes.length];
336    
337                            for (int i = 0; i < cookies.length; i++) {
338                                    cookies[i] = CookieUtil.deserialize(cookiesBytes[i]);
339                            }
340    
341                            return cookies;
342                    }
343    
344                    @Override
345                    public String getHeader(String name) {
346                            List<String> values = headerMap.get(StringUtil.toLowerCase(name));
347    
348                            if ((values == null) || values.isEmpty()) {
349                                    return null;
350                            }
351    
352                            return values.get(0);
353                    }
354    
355                    @Override
356                    public Enumeration<String> getHeaderNames() {
357                            return Collections.enumeration(headerMap.keySet());
358                    }
359    
360                    @Override
361                    public Enumeration<String> getHeaders(String name) {
362                            List<String> values = headerMap.get(StringUtil.toLowerCase(name));
363    
364                            if (values == null) {
365                                    values = Collections.emptyList();
366                            }
367    
368                            return Collections.enumeration(values);
369                    }
370    
371                    @Override
372                    public ServletInputStream getInputStream() throws IOException {
373                            if (requestBodyFile != null) {
374                                    return new ServletInputStreamAdapter(
375                                            new AutoDeleteFileInputStream(requestBodyFile));
376                            }
377    
378                            return super.getInputStream();
379                    }
380    
381                    @Override
382                    public String getParameter(String name) {
383                            String[] values = parameterMap.get(name);
384    
385                            if (ArrayUtil.isNotEmpty(values)) {
386                                    return values[0];
387                            }
388                            else {
389                                    return null;
390                            }
391                    }
392    
393                    @Override
394                    public Map<String, String[]> getParameterMap() {
395                            return parameterMap;
396                    }
397    
398                    @Override
399                    public Enumeration<String> getParameterNames() {
400                            return Collections.enumeration(parameterMap.keySet());
401                    }
402    
403                    @Override
404                    public String[] getParameterValues(String name) {
405                            return parameterMap.get(name);
406                    }
407    
408                    @Override
409                    public String getRemoteAddr() {
410                            return remoteAddr;
411                    }
412    
413                    @Override
414                    public String getRemoteHost() {
415                            return remoteHost;
416                    }
417    
418                    @Override
419                    public int getRemotePort() {
420                            return remotePort;
421                    }
422    
423                    @Override
424                    public String getRemoteUser() {
425                            return remoteUser;
426                    }
427    
428                    @Override
429                    public String getServerName() {
430                            return serverName;
431                    }
432    
433                    @Override
434                    public int getServerPort() {
435                            return serverPort;
436                    }
437    
438            }
439    
440    }