001    /**
002     * Copyright (c) 2000-2013 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.resiliency.spi.SPIUtil;
019    import com.liferay.portal.kernel.resiliency.spi.agent.annotation.Direction;
020    import com.liferay.portal.kernel.servlet.PersistentHttpServletRequestWrapper;
021    import com.liferay.portal.kernel.servlet.ServletInputStreamAdapter;
022    import com.liferay.portal.kernel.upload.FileItem;
023    import com.liferay.portal.kernel.upload.UploadServletRequest;
024    import com.liferay.portal.kernel.util.ArrayUtil;
025    import com.liferay.portal.kernel.util.ContentTypes;
026    import com.liferay.portal.kernel.util.CookieUtil;
027    import com.liferay.portal.kernel.util.FileUtil;
028    import com.liferay.portal.kernel.util.SetUtil;
029    import com.liferay.portal.kernel.util.StreamUtil;
030    import com.liferay.portal.kernel.util.StringBundler;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.StringUtil;
033    import com.liferay.portal.model.Portlet;
034    import com.liferay.portal.theme.ThemeDisplay;
035    import com.liferay.portal.upload.UploadServletRequestImpl;
036    import com.liferay.portal.util.WebKeys;
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<String, String[]>(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                                    FileOutputStream fileOutputStream = new FileOutputStream(
163                                            requestBodyFile);
164    
165                                    try {
166                                            StreamUtil.transfer(
167                                                    currentRequest.getInputStream(), fileOutputStream,
168                                                    false);
169                                    }
170                                    finally {
171                                            fileOutputStream.close();
172                                    }
173    
174                                    uploadServletRequest = new UploadServletRequestImpl(
175                                            new AgentHttpServletRequestWrapper(currentRequest));
176                            }
177    
178                            Map<String, FileItem[]> multipartParameterMap =
179                                    uploadServletRequest.getMultipartParameterMap();
180                            Map<String, List<String>> regularParameterMap =
181                                    uploadServletRequest.getRegularParameterMap();
182    
183                            if (!multipartParameterMap.isEmpty()) {
184                                    this.multipartParameterMap = multipartParameterMap;
185                            }
186    
187                            if (!regularParameterMap.isEmpty()) {
188                                    this.regularParameterMap = regularParameterMap;
189                            }
190                    }
191    
192                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
193                            WebKeys.THEME_DISPLAY);
194    
195                    if ((themeDisplay != null) && themeDisplay.isAjax()) {
196                            parameterMap = new HashMap<String, String[]>(parameterMap);
197    
198                            parameterMap.put(
199                                    "portalResiliencyPortletShowFooter",
200                                    new String[] {StringPool.FALSE});
201                    }
202    
203                    originalSessionAttributes = extractSessionAttributes(request);
204    
205                    captureThreadLocals();
206            }
207    
208            public Map<String, Serializable> getOriginalSessionAttributes() {
209                    return originalSessionAttributes;
210            }
211    
212            public HttpServletRequest populateRequest(HttpServletRequest request) {
213                    request = new AgentHttpServletRequestWrapper(request);
214    
215                    for (Map.Entry<String, Serializable> entry :
216                                    distributedRequestAttributes.entrySet()) {
217    
218                            request.setAttribute(entry.getKey(), entry.getValue());
219                    }
220    
221                    if ((multipartParameterMap != null) || (regularParameterMap != null)) {
222                            request = new UploadServletRequestImpl(
223                                    request, multipartParameterMap, regularParameterMap);
224                    }
225    
226                    restoreThreadLocals();
227    
228                    return request;
229            }
230    
231            public void populateSessionAttributes(HttpSession session) {
232                    for (Map.Entry<String, Serializable> entry :
233                                    originalSessionAttributes.entrySet()) {
234    
235                            session.setAttribute(entry.getKey(), entry.getValue());
236                    }
237            }
238    
239            @Override
240            public String toString() {
241                    int length = 20 + parameterMap.size() * 4;
242    
243                    if (cookiesBytes != null) {
244                            length += cookiesBytes.length * 2 - 1;
245                    }
246    
247                    StringBundler sb = new StringBundler(length);
248    
249                    sb.append("{contentType=");
250                    sb.append(contentType);
251                    sb.append(", cookies=[");
252    
253                    if (cookiesBytes != null) {
254                            for (byte[] cookieBytes : cookiesBytes) {
255                                    Cookie cookie = CookieUtil.deserialize(cookieBytes);
256    
257                                    sb.append(CookieUtil.toString(cookie));
258                                    sb.append(", ");
259                            }
260    
261                            sb.setIndex(sb.index() - 1);
262                    }
263    
264                    sb.append("], distributedRequestAttributes=");
265                    sb.append(distributedRequestAttributes);
266                    sb.append(", headerMap=");
267                    sb.append(headerMap);
268                    sb.append(", multipartParameterMap=");
269                    sb.append(multipartParameterMap);
270                    sb.append(", originalSessionAttributes=");
271                    sb.append(originalSessionAttributes);
272                    sb.append(", parameterMap={");
273    
274                    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
275                            sb.append(entry.getKey());
276                            sb.append("=");
277                            sb.append(Arrays.toString(entry.getValue()));
278                            sb.append(", ");
279                    }
280    
281                    sb.setIndex(sb.index() - 1);
282    
283                    sb.append("}, regularParameterMap=");
284                    sb.append(regularParameterMap);
285                    sb.append(", requestBodyFile=");
286                    sb.append(requestBodyFile);
287                    sb.append(", serverName=");
288                    sb.append(serverName);
289                    sb.append(", serverPort=");
290                    sb.append(serverPort);
291                    sb.append("}");
292    
293                    return sb.toString();
294            }
295    
296            protected String contentType;
297            protected byte[][] cookiesBytes;
298            protected Map<String, Serializable> distributedRequestAttributes;
299            protected Map<String, List<String>> headerMap;
300            protected Map<String, FileItem[]> multipartParameterMap;
301            protected Map<String, Serializable> originalSessionAttributes;
302            protected Map<String, String[]> parameterMap;
303            protected Map<String, List<String>> regularParameterMap;
304            protected String remoteAddr;
305            protected String remoteHost;
306            protected int remotePort;
307            protected String remoteUser;
308            protected File requestBodyFile;
309            protected String serverName;
310            protected int serverPort;
311    
312            protected class AgentHttpServletRequestWrapper
313                    extends PersistentHttpServletRequestWrapper {
314    
315                    public AgentHttpServletRequestWrapper(HttpServletRequest request) {
316                            super(request);
317                    }
318    
319                    @Override
320                    public int getContentLength() {
321                            if (requestBodyFile != null) {
322                                    return (int)requestBodyFile.length();
323                            }
324    
325                            return super.getContentLength();
326                    }
327    
328                    @Override
329                    public String getContentType() {
330                            if (contentType != null) {
331                                    return contentType;
332                            }
333    
334                            return super.getContentType();
335                    }
336    
337                    @Override
338                    public Cookie[] getCookies() {
339                            if (cookiesBytes == null) {
340                                    return null;
341                            }
342    
343                            Cookie[] cookies = new Cookie[cookiesBytes.length];
344    
345                            for (int i = 0; i < cookies.length; i++) {
346                                    cookies[i] = CookieUtil.deserialize(cookiesBytes[i]);
347                            }
348    
349                            return cookies;
350                    }
351    
352                    @Override
353                    public String getHeader(String name) {
354                            List<String> values = headerMap.get(StringUtil.toLowerCase(name));
355    
356                            if ((values == null) || values.isEmpty()) {
357                                    return null;
358                            }
359    
360                            return values.get(0);
361                    }
362    
363                    @Override
364                    public Enumeration<String> getHeaderNames() {
365                            return Collections.enumeration(headerMap.keySet());
366                    }
367    
368                    @Override
369                    public Enumeration<String> getHeaders(String name) {
370                            List<String> values = headerMap.get(StringUtil.toLowerCase(name));
371    
372                            if (values == null) {
373                                    values = Collections.emptyList();
374                            }
375    
376                            return Collections.enumeration(values);
377                    }
378    
379                    @Override
380                    public ServletInputStream getInputStream() throws IOException {
381                            if (requestBodyFile != null) {
382                                    return new ServletInputStreamAdapter(
383                                            new AutoDeleteFileInputStream(requestBodyFile));
384                            }
385    
386                            return super.getInputStream();
387                    }
388    
389                    @Override
390                    public String getParameter(String name) {
391                            String[] values = parameterMap.get(name);
392    
393                            if (ArrayUtil.isNotEmpty(values)) {
394                                    return values[0];
395                            }
396                            else {
397                                    return null;
398                            }
399                    }
400    
401                    @Override
402                    public Map<String, String[]> getParameterMap() {
403                            return parameterMap;
404                    }
405    
406                    @Override
407                    public Enumeration<String> getParameterNames() {
408                            return Collections.enumeration(parameterMap.keySet());
409                    }
410    
411                    @Override
412                    public String[] getParameterValues(String name) {
413                            return parameterMap.get(name);
414                    }
415    
416                    @Override
417                    public String getRemoteAddr() {
418                            return remoteAddr;
419                    }
420    
421                    @Override
422                    public String getRemoteHost() {
423                            return remoteHost;
424                    }
425    
426                    @Override
427                    public int getRemotePort() {
428                            return remotePort;
429                    }
430    
431                    @Override
432                    public String getRemoteUser() {
433                            return remoteUser;
434                    }
435    
436                    @Override
437                    public String getServerName() {
438                            return serverName;
439                    }
440    
441                    @Override
442                    public int getServerPort() {
443                            return serverPort;
444                    }
445    
446            }
447    
448    }