View Javadoc
1   /*
2    * Copyright (c) 2002-2017, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.webappcontainer.web;
35  
36  import java.io.IOException;
37  import java.io.OutputStream;
38  import java.util.HashMap;
39  import java.util.Map;
40  import java.util.Map.Entry;
41  
42  import javax.servlet.ServletException;
43  import javax.servlet.http.HttpServlet;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.servlet.http.HttpServletResponse;
46  
47  import org.apache.commons.fileupload.FileItem;
48  import org.apache.commons.fileupload.RequestContext;
49  import org.apache.commons.fileupload.servlet.ServletFileUpload;
50  import org.apache.commons.fileupload.servlet.ServletRequestContext;
51  import org.apache.commons.httpclient.URI;
52  
53  import fr.paris.lutece.plugins.webappcontainer.business.Site;
54  import fr.paris.lutece.plugins.webappcontainer.business.WebappResponse;
55  import fr.paris.lutece.plugins.webappcontainer.util.HttpAccess;
56  import fr.paris.lutece.plugins.webappcontainer.util.HttpAccessException;
57  import fr.paris.lutece.plugins.webappcontainer.util.UrlUtils;
58  import fr.paris.lutece.portal.service.util.AppLogService;
59  import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
60  import fr.paris.lutece.util.url.UrlItem;
61  
62  /**
63   * Servlet serving document file resources
64   */
65  @SuppressWarnings( "serial" )
66  public class WebappcontainerResourceServlet extends HttpServlet
67  {
68  	private static final String METHOD_POST = "POST";
69  
70  	private static final String SESSION_ATTRIBUTE_COOKIES = "HttpWrapper_cookies_";
71  
72  	/**
73  	 * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
74  	 * @param request servlet request
75  	 * @param response servlet response
76  	 * @throws ServletException the servlet Exception
77  	 * @throws IOException the io exception
78  	 */
79  	protected void processRequest( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
80  	{
81  		OutputStream out = response.getOutputStream();
82  		String strRequestedUrl = WebappcontainerApp.getRequestUrl( request );
83  		Site site = WebappcontainerApp.getSite( request );
84  
85  		if ( ( strRequestedUrl == null ) || strRequestedUrl.equals( "" ) )
86  		{
87  			strRequestedUrl = site.getUrl();
88  		}
89  
90  		WebappResponse webappResponse = null;
91  
92  		try
93  		{
94  			webappResponse = getWebappResponse( request, strRequestedUrl, site );
95  		}
96  		catch ( HttpAccessException e )
97  		{
98  			out.write( ( "Error : " + e ).getBytes() );
99  			AppLogService.error( "Error when retrieving external site content (site : " + site.getCode() + ", url : " + strRequestedUrl + ")", e );
100 		}
101 
102 		if ( webappResponse != null )
103 		{
104 			out.write( webappResponse.getContent() );
105 		}
106 
107 		out.flush();
108 		out.close();
109 	}
110 
111 	/**
112 	 * Get the webapp response
113 	 * 
114 	 * @param request The {@link HttpServletRequest} object
115 	 * @param strRequestedUrl The requested url
116 	 * @param site The site requested
117 	 * @return The {@link WebappResponse} object (contain response content, headers, cookies, ...)
118 	 * @throws HttpAccessException if process cannot access to external site
119 	 */
120 	public static WebappResponse getWebappResponse( HttpServletRequest request, String strRequestedUrl, Site site ) throws HttpAccessException
121 	{
122 		// Get the site content
123 		HttpAccess httpAccess = new HttpAccess();
124 		WebappResponse webappResponse = null;
125 		RequestContext requestContext = new ServletRequestContext( request );
126 		Map<String, FileItem> fileMap = null;
127 		Map<String, String[]> parametersMap = null;
128 
129 		if ( ServletFileUpload.isMultipartContent( requestContext ) )
130 		{
131 			// Multipart
132 			MultipartHttpServletRequest multipartRequest = ( MultipartHttpServletRequest ) request;
133 			fileMap = multipartRequest.getFileMap();
134 
135 			parametersMap = getParameterMap( multipartRequest );
136 		}
137 		else
138 		{
139 			parametersMap = getParameterMap( request );
140 		}
141 
142 		// Get the cookies for the specified site
143 		org.apache.commons.httpclient.Cookie[] cookies = ( org.apache.commons.httpclient.Cookie[] ) request.getSession().getAttribute( SESSION_ATTRIBUTE_COOKIES + site.getCode() );
144 
145 		httpAccess.initializeState( cookies, site );
146 
147 		if ( !UrlUtils.hostsEquals( site.getUrl(), strRequestedUrl ) )
148 		{
149 			throw new HttpAccessException( "Error : The requested Url does not corresponding with the specified external site.", null );
150 		}
151 
152 		try
153 		{
154 			if ( request.getMethod().equals( METHOD_POST ) )
155 			{
156 				URI uri = new URI( strRequestedUrl, false );
157 				webappResponse = httpAccess.doPost( uri.getEscapedURI(), parametersMap, fileMap );
158 			}
159 			else
160 			{
161 				// Set the parameters
162 				UrlItem requestedUrl = new UrlItem( strRequestedUrl );
163 
164 				for ( Entry<String, String[]> entry : parametersMap.entrySet() )
165 				{
166 					requestedUrl.addParameter( entry.getKey(), entry.getValue()[0] );
167 				}
168 
169 				URI uri = new URI( requestedUrl.getUrl(), true );
170 
171 				webappResponse = httpAccess.doGet( uri.getEscapedURI() );
172 			}
173 		}
174 		catch ( Exception e )
175 		{
176 			AppLogService.error( e.getMessage(), e );
177 			throw new HttpAccessException( e.getMessage(), e );
178 		}
179 
180 		// Set the cookies for the specified site
181 		request.getSession().setAttribute( SESSION_ATTRIBUTE_COOKIES + site.getCode(), webappResponse.getCookies() );
182 
183 		return webappResponse;
184 	}
185 
186 	/**
187 	 * Delete the webappcontainer specifics informations (siteCode and requested url) in the parameter map request
188 	 * @param request The request
189 	 * @return The map parameters
190 	 */
191 	private static Map<String, String[]> getParameterMap( HttpServletRequest request )
192 	{
193 		// Set the parameters
194 		Map<String, String[]> parametersMap = request.getParameterMap();
195 		Map<String, String[]> parametersWithoutContainerInformations = new HashMap<String, String[]>();
196 
197 		for ( Entry<String, String[]> entry : parametersMap.entrySet() )
198 		{
199 			if ( !entry.getKey().equals( WebappcontainerApp.PARAMETER_CODE ) && !entry.getKey().equals( WebappcontainerApp.PARAMETER_PAGE )
200 					&& !entry.getKey().equals( WebappcontainerApp.PARAMETER_WEBAPP_URL ) )
201 			{
202 				if ( entry.getKey().startsWith( WebappcontainerApp.PARAMETER_PAGE_HACK ) )
203 				{
204 					parametersWithoutContainerInformations.put( entry.getKey().substring( WebappcontainerApp.PARAMETER_PAGE_HACK.length() ), entry.getValue() );
205 				}
206 				else
207 				{
208 					parametersWithoutContainerInformations.put( entry.getKey(), entry.getValue() );
209 				}
210 			}
211 		}
212 
213 		return parametersWithoutContainerInformations;
214 	}
215 
216 	/**
217 	 * Handles the HTTP <code>GET</code> method.
218 	 * @param request servlet request
219 	 * @param response servlet response
220 	 * @throws ServletException the servlet Exception
221 	 * @throws IOException the io exception
222 	 */
223 	protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
224 	{
225 		processRequest( request, response );
226 	}
227 
228 	/**
229 	 * Handles the HTTP <code>POST</code> method.
230 	 * @param request servlet request
231 	 * @param response servlet response
232 	 * @throws ServletException the servlet Exception
233 	 * @throws IOException the io exception
234 	 */
235 	protected void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
236 	{
237 		processRequest( request, response );
238 	}
239 
240 	/**
241 	 * Returns a short description of the servlet.
242 	 * @return message
243 	 */
244 	public String getServletInfo()
245 	{
246 		return "Servlet serving file resources of webappcontainer";
247 	}
248 }