001
014
015 package com.liferay.portal.servlet.filters.virtualhost;
016
017 import com.liferay.portal.LayoutFriendlyURLException;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.struts.LastPath;
021 import com.liferay.portal.kernel.util.CharPool;
022 import com.liferay.portal.kernel.util.StringBundler;
023 import com.liferay.portal.kernel.util.StringPool;
024 import com.liferay.portal.kernel.util.StringUtil;
025 import com.liferay.portal.kernel.util.Validator;
026 import com.liferay.portal.model.Group;
027 import com.liferay.portal.model.LayoutSet;
028 import com.liferay.portal.model.impl.LayoutImpl;
029 import com.liferay.portal.service.GroupLocalServiceUtil;
030 import com.liferay.portal.servlet.I18nServlet;
031 import com.liferay.portal.servlet.filters.BasePortalFilter;
032 import com.liferay.portal.util.PortalInstances;
033 import com.liferay.portal.util.PortalUtil;
034 import com.liferay.portal.util.PropsValues;
035 import com.liferay.portal.util.WebKeys;
036 import com.liferay.portal.webserver.WebServerServlet;
037
038 import java.util.Set;
039
040 import javax.servlet.FilterChain;
041 import javax.servlet.FilterConfig;
042 import javax.servlet.RequestDispatcher;
043 import javax.servlet.ServletContext;
044 import javax.servlet.http.HttpServletRequest;
045 import javax.servlet.http.HttpServletResponse;
046
047
057 public class VirtualHostFilter extends BasePortalFilter {
058
059 @Override
060 public void init(FilterConfig filterConfig) {
061 super.init(filterConfig);
062
063 _servletContext = filterConfig.getServletContext();
064
065 _slashedKeywords =
066 new String[PropsValues.LAYOUT_FRIENDLY_URL_KEYWORDS.length];
067
068 for (int i = 0; i < PropsValues.LAYOUT_FRIENDLY_URL_KEYWORDS.length;
069 i++) {
070
071 String keyword = PropsValues.LAYOUT_FRIENDLY_URL_KEYWORDS[i];
072
073 if (keyword.contains(StringPool.PERIOD) ||
074 keyword.equals("_vti_") || keyword.equals("api") ||
075 keyword.equals("display_chart") ||
076 keyword.equals("sharepoint") ||
077 keyword.equals("software_catalog")) {
078
079 keyword = StringPool.SLASH + keyword;
080 }
081 else {
082 keyword = StringPool.SLASH + keyword + StringPool.SLASH;
083 }
084
085 _slashedKeywords[i] = keyword.toLowerCase();
086 }
087 }
088
089 @Override
090 public boolean isFilterEnabled(
091 HttpServletRequest request, HttpServletResponse response) {
092
093 StringBuffer requestURL = request.getRequestURL();
094
095 if (isValidRequestURL(requestURL)) {
096 return true;
097 }
098 else {
099 return false;
100 }
101 }
102
103 protected boolean isValidFriendlyURL(String friendlyURL) {
104 friendlyURL = friendlyURL.toLowerCase();
105
106 if (PortalInstances.isVirtualHostsIgnorePath(friendlyURL) ||
107 friendlyURL.startsWith(_PRIVATE_GROUP_SERVLET_MAPPING_SLASH) ||
108 friendlyURL.startsWith(_PRIVATE_USER_SERVLET_MAPPING_SLASH) ||
109 friendlyURL.startsWith(_PUBLIC_GROUP_SERVLET_MAPPING_SLASH)) {
110
111 return false;
112 }
113
114 for (String keyword : _slashedKeywords) {
115 if (friendlyURL.startsWith(keyword)) {
116 return false;
117 }
118 }
119
120 int code = LayoutImpl.validateFriendlyURL(friendlyURL);
121
122 if ((code > -1) &&
123 (code != LayoutFriendlyURLException.ENDS_WITH_SLASH)) {
124
125 return false;
126 }
127
128 return true;
129 }
130
131 protected boolean isValidRequestURL(StringBuffer requestURL) {
132 if (requestURL == null) {
133 return false;
134 }
135
136 String url = requestURL.toString();
137
138 for (String extension : PropsValues.VIRTUAL_HOSTS_IGNORE_EXTENSIONS) {
139 if (url.endsWith(extension)) {
140 return false;
141 }
142 }
143
144 return true;
145 }
146
147 @Override
148 protected void processFilter(
149 HttpServletRequest request, HttpServletResponse response,
150 FilterChain filterChain)
151 throws Exception {
152
153 long companyId = PortalInstances.getCompanyId(request);
154
155 String contextPath = PortalUtil.getPathContext();
156
157 String originalFriendlyURL = request.getRequestURI();
158
159 String friendlyURL = originalFriendlyURL;
160
161 if ((Validator.isNotNull(contextPath)) &&
162 (friendlyURL.indexOf(contextPath) != -1)) {
163
164 friendlyURL = friendlyURL.substring(contextPath.length());
165 }
166
167 int pos = friendlyURL.indexOf(StringPool.SEMICOLON);
168
169 if (pos != -1) {
170 friendlyURL = friendlyURL.substring(0, pos);
171 }
172
173 friendlyURL = StringUtil.replace(
174 friendlyURL, StringPool.DOUBLE_SLASH, StringPool.SLASH);
175
176 String i18nLanguageId = null;
177
178 Set<String> languageIds = I18nServlet.getLanguageIds();
179
180 for (String languageId : languageIds) {
181 if (StringUtil.startsWith(friendlyURL, languageId)) {
182 pos = friendlyURL.indexOf(CharPool.SLASH, 1);
183
184 if (((pos != -1) && (pos != languageId.length())) ||
185 ((pos == -1) &&
186 !friendlyURL.equalsIgnoreCase(languageId))) {
187
188 continue;
189 }
190
191 if (pos == -1) {
192 i18nLanguageId = languageId;
193 friendlyURL = StringPool.SLASH;
194 }
195 else {
196 i18nLanguageId = languageId.substring(0, pos);
197 friendlyURL = friendlyURL.substring(pos);
198 }
199
200 break;
201 }
202 }
203
204 friendlyURL = StringUtil.replace(
205 friendlyURL, PropsValues.WIDGET_SERVLET_MAPPING, StringPool.BLANK);
206
207 if (_log.isDebugEnabled()) {
208 _log.debug("Friendly URL " + friendlyURL);
209 }
210
211 if (!friendlyURL.equals(StringPool.SLASH) &&
212 !isValidFriendlyURL(friendlyURL)) {
213
214 _log.debug("Friendly URL is not valid");
215
216 processFilter(
217 VirtualHostFilter.class, request, response, filterChain);
218
219 return;
220 }
221 else if (friendlyURL.startsWith(_PATH_DOCUMENTS)) {
222 if (WebServerServlet.hasFiles(request)) {
223 processFilter(
224 VirtualHostFilter.class, request, response, filterChain);
225
226 return;
227 }
228 }
229
230 LayoutSet layoutSet = (LayoutSet)request.getAttribute(
231 WebKeys.VIRTUAL_HOST_LAYOUT_SET);
232
233 if (_log.isDebugEnabled()) {
234 _log.debug("Layout set " + layoutSet);
235 }
236
237 if (layoutSet == null) {
238 processFilter(
239 VirtualHostFilter.class, request, response, filterChain);
240
241 return;
242 }
243
244 try {
245 LastPath lastPath = new LastPath(
246 contextPath, friendlyURL, request.getParameterMap());
247
248 request.setAttribute(WebKeys.LAST_PATH, lastPath);
249
250 StringBundler forwardURL = new StringBundler(5);
251
252 if (i18nLanguageId != null) {
253 forwardURL.append(i18nLanguageId);
254 }
255
256 if (originalFriendlyURL.startsWith(
257 PropsValues.WIDGET_SERVLET_MAPPING)) {
258
259 forwardURL.append(PropsValues.WIDGET_SERVLET_MAPPING);
260
261 friendlyURL = StringUtil.replaceFirst(
262 friendlyURL, PropsValues.WIDGET_SERVLET_MAPPING,
263 StringPool.BLANK);
264 }
265
266 long plid = PortalUtil.getPlidFromFriendlyURL(
267 companyId, friendlyURL);
268
269 if (plid <= 0) {
270 Group group = GroupLocalServiceUtil.getGroup(
271 layoutSet.getGroupId());
272
273 if (group.isGuest() && friendlyURL.equals(StringPool.SLASH)) {
274 String homeURL = PortalUtil.getRelativeHomeURL(request);
275
276 if (Validator.isNotNull(homeURL)) {
277 friendlyURL = homeURL;
278 }
279 }
280 else {
281 if (layoutSet.isPrivateLayout()) {
282 if (group.isUser()) {
283 forwardURL.append(_PRIVATE_USER_SERVLET_MAPPING);
284 }
285 else {
286 forwardURL.append(_PRIVATE_GROUP_SERVLET_MAPPING);
287 }
288 }
289 else {
290 forwardURL.append(_PUBLIC_GROUP_SERVLET_MAPPING);
291 }
292
293 forwardURL.append(group.getFriendlyURL());
294 }
295 }
296
297 forwardURL.append(friendlyURL);
298
299 if (_log.isDebugEnabled()) {
300 _log.debug("Forward to " + forwardURL);
301 }
302
303 RequestDispatcher requestDispatcher =
304 _servletContext.getRequestDispatcher(forwardURL.toString());
305
306 requestDispatcher.forward(request, response);
307 }
308 catch (Exception e) {
309 _log.error(e, e);
310
311 processFilter(
312 VirtualHostFilter.class, request, response, filterChain);
313 }
314 }
315
316 private static final String _PATH_DOCUMENTS = "/documents/";
317
318 private static final String _PRIVATE_GROUP_SERVLET_MAPPING =
319 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING;
320
321 private static final String _PRIVATE_GROUP_SERVLET_MAPPING_SLASH =
322 _PRIVATE_GROUP_SERVLET_MAPPING + StringPool.SLASH;
323
324 private static final String _PRIVATE_USER_SERVLET_MAPPING =
325 PropsValues.LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING;
326
327 private static final String _PRIVATE_USER_SERVLET_MAPPING_SLASH =
328 _PRIVATE_USER_SERVLET_MAPPING + StringPool.SLASH;
329
330 private static final String _PUBLIC_GROUP_SERVLET_MAPPING =
331 PropsValues.LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING;
332
333 private static final String _PUBLIC_GROUP_SERVLET_MAPPING_SLASH =
334 _PUBLIC_GROUP_SERVLET_MAPPING + StringPool.SLASH;
335
336 private static Log _log = LogFactoryUtil.getLog(VirtualHostFilter.class);
337
338 private ServletContext _servletContext;
339 private String[] _slashedKeywords;
340
341 }