001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.staticexport; 029 030import org.opencms.ade.configuration.CmsDetailNameCache; 031import org.opencms.ade.detailpage.I_CmsDetailPageHandler; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsResource; 034import org.opencms.file.CmsResourceFilter; 035import org.opencms.file.CmsVfsException; 036import org.opencms.file.CmsVfsResourceNotFoundException; 037import org.opencms.file.types.CmsResourceTypeImage; 038import org.opencms.file.types.I_CmsResourceType; 039import org.opencms.loader.CmsLoaderException; 040import org.opencms.main.CmsException; 041import org.opencms.main.CmsLog; 042import org.opencms.main.CmsStaticResourceHandler; 043import org.opencms.main.OpenCms; 044import org.opencms.site.CmsSite; 045import org.opencms.site.CmsSiteMatcher; 046import org.opencms.util.CmsFileUtil; 047import org.opencms.util.CmsPair; 048import org.opencms.util.CmsStringUtil; 049import org.opencms.util.CmsUUID; 050import org.opencms.util.CmsUriSplitter; 051import org.opencms.workplace.CmsWorkplace; 052 053import java.net.URI; 054import java.util.List; 055import java.util.Locale; 056 057import org.apache.commons.logging.Log; 058 059/** 060 * Default link substitution behavior.<p> 061 * 062 * @since 7.0.2 063 * 064 * @see CmsLinkManager#substituteLink(org.opencms.file.CmsObject, String, String, boolean) 065 * for the method where this handler is used. 066 */ 067public class CmsDefaultLinkSubstitutionHandler implements I_CmsLinkSubstitutionHandler { 068 069 /** 070 * Request context attribute name to make the link substitution handler treat the link like an image link.<p> 071 */ 072 public static final String ATTR_IS_IMAGE_LINK = "IS_IMAGE_LINK"; 073 074 /** Key for a request context attribute to control whether the getRootPath method uses the current site root for workplace requests. 075 * The getRootPath method clears this attribute when called. 076 */ 077 public static final String DONT_USE_CURRENT_SITE_FOR_WORKPLACE_REQUESTS = "DONT_USE_CURRENT_SITE_FOR_WORKPLACE_REQUESTS"; 078 079 /** The log object for this class. */ 080 private static final Log LOG = CmsLog.getLog(CmsDefaultLinkSubstitutionHandler.class); 081 082 /** Prefix used for request context attributes to control whether a different site root should be used in appendServerPrefix. */ 083 public static final String OVERRIDE_SITEROOT_PREFIX = "OVERRIDE_SITEROOT:"; 084 085 /** 086 * Returns the resource root path in the OpenCms VFS for the given link, or <code>null</code> in 087 * case the link points to an external site.<p> 088 * 089 * If the target URI contains no site information, but starts with the opencms context, the context is removed:<pre> 090 * /opencms/opencms/system/further_path -> /system/further_path</pre> 091 * 092 * If the target URI contains no site information, the path will be prefixed with the current site 093 * from the provided OpenCms user context:<pre> 094 * /folder/page.html -> /sites/mysite/folder/page.html</pre> 095 * 096 * If the path of the target URI is relative, i.e. does not start with "/", 097 * the path will be prefixed with the current site and the given relative path, 098 * then normalized. 099 * If no relative path is given, <code>null</code> is returned. 100 * If the normalized path is outsite a site, null is returned.<pre> 101 * page.html -> /sites/mysite/page.html 102 * ../page.html -> /sites/mysite/page.html 103 * ../../page.html -> null</pre> 104 * 105 * If the target URI contains a scheme/server name that denotes an opencms site, 106 * it is replaced by the appropriate site path:<pre> 107 * http://www.mysite.de/folder/page.html -> /sites/mysite/folder/page.html</pre><p> 108 * 109 * If the target URI contains a scheme/server name that does not match with any site, 110 * or if the URI is opaque or invalid, 111 * <code>null</code> is returned:<pre> 112 * http://www.elsewhere.com/page.html -> null 113 * mailto:someone@elsewhere.com -> null</pre> 114 * 115 * @see org.opencms.staticexport.I_CmsLinkSubstitutionHandler#getLink(org.opencms.file.CmsObject, java.lang.String, java.lang.String, boolean) 116 */ 117 public String getLink(CmsObject cms, String link, String siteRoot, boolean forceSecure) { 118 119 return getLink(cms, link, siteRoot, null, forceSecure); 120 } 121 122 /** 123 * @see org.opencms.staticexport.I_CmsLinkSubstitutionHandler#getLink(org.opencms.file.CmsObject, java.lang.String, java.lang.String, java.lang.String, boolean) 124 */ 125 public String getLink(CmsObject cms, String link, String siteRoot, String targetDetailPage, boolean forceSecure) { 126 127 if (CmsStringUtil.isEmpty(link)) { 128 // not a valid link parameter, return an empty String 129 return ""; 130 } 131 132 if (CmsStaticResourceHandler.isStaticResourceUri(link)) { 133 return CmsWorkplace.getStaticResourceUri(link); 134 } 135 136 // make sure we have an absolute link 137 String absoluteLink = CmsLinkManager.getAbsoluteUri(link, cms.getRequestContext().getUri()); 138 String overrideSiteRoot = null; 139 140 String vfsName; 141 142 CmsUriSplitter splitter = new CmsUriSplitter(absoluteLink, true); 143 String parameters = null; 144 if (splitter.getQuery() != null) { 145 parameters = "?" + splitter.getQuery(); 146 } 147 String anchor = null; 148 if (splitter.getAnchor() != null) { 149 anchor = "#" + splitter.getAnchor(); 150 } 151 vfsName = splitter.getPrefix(); 152 153 String resultLink = null; 154 String uriBaseName = null; 155 boolean useRelativeLinks = false; 156 157 // determine the target site of the link 158 CmsSite currentSite = OpenCms.getSiteManager().getCurrentSite(cms); 159 CmsSite targetSite = null; 160 if (CmsStringUtil.isNotEmpty(siteRoot)) { 161 targetSite = OpenCms.getSiteManager().getSiteForSiteRoot(siteRoot); 162 } 163 if (targetSite == null) { 164 targetSite = currentSite; 165 } 166 167 String targetSiteRoot = targetSite.getSiteRoot(); 168 String originalVfsName = vfsName; 169 String detailPage = null; 170 CmsResource detailContent = null; 171 try { 172 String rootVfsName; 173 if (!vfsName.startsWith(targetSiteRoot) 174 && !vfsName.startsWith(CmsResource.VFS_FOLDER_SYSTEM + "/") 175 && !OpenCms.getSiteManager().startsWithShared(vfsName)) { 176 rootVfsName = CmsStringUtil.joinPaths(targetSiteRoot, vfsName); 177 } else { 178 rootVfsName = vfsName; 179 } 180 if (!rootVfsName.startsWith(CmsWorkplace.VFS_PATH_WORKPLACE)) { 181 // never use the ADE manager for workplace links, to be sure the workplace stays usable in case of configuration errors 182 I_CmsDetailPageHandler finder = OpenCms.getADEManager().getDetailPageHandler(); 183 detailPage = finder.getDetailPage(cms, rootVfsName, cms.getRequestContext().getUri(), targetDetailPage); 184 } 185 if (detailPage != null) { 186 CmsSite detailPageSite = OpenCms.getSiteManager().getSiteForRootPath(detailPage); 187 if (detailPageSite != null) { 188 targetSite = detailPageSite; 189 overrideSiteRoot = targetSiteRoot = targetSite.getSiteRoot(); 190 detailPage = detailPage.substring(targetSiteRoot.length()); 191 if (!detailPage.startsWith("/")) { 192 detailPage = "/" + detailPage; 193 } 194 } 195 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 196 try { 197 cms.getRequestContext().setSiteRoot(""); 198 CmsResource element = cms.readResource(rootVfsName, CmsResourceFilter.IGNORE_EXPIRATION); 199 detailContent = element; 200 Locale locale = cms.getRequestContext().getLocale(); 201 List<Locale> defaultLocales = OpenCms.getLocaleManager().getDefaultLocales(); 202 vfsName = CmsStringUtil.joinPaths( 203 detailPage, 204 cms.getDetailName(element, locale, defaultLocales), 205 "/"); 206 207 } catch (CmsVfsException e) { 208 if (LOG.isWarnEnabled()) { 209 LOG.warn(e.getLocalizedMessage(), e); 210 } 211 } finally { 212 cms.getRequestContext().setSiteRoot(originalSiteRoot); 213 214 } 215 } 216 } catch (CmsVfsResourceNotFoundException e) { 217 LOG.info(e.getLocalizedMessage(), e); 218 } catch (CmsException e) { 219 LOG.error(e.getLocalizedMessage(), e); 220 } 221 222 // if the link points to another site, there needs to be a server prefix 223 String serverPrefix; 224 if ((targetSite != currentSite) || cms.getRequestContext().isForceAbsoluteLinks()) { 225 serverPrefix = targetSite.getUrl(); 226 } else { 227 serverPrefix = ""; 228 } 229 230 // in the online project, check static export and secure settings 231 if (cms.getRequestContext().getCurrentProject().isOnlineProject()) { 232 // first check if this link needs static export 233 CmsStaticExportManager exportManager = OpenCms.getStaticExportManager(); 234 String oriUri = cms.getRequestContext().getUri(); 235 // check if we need relative links in the exported pages 236 if (exportManager.relativeLinksInExport(cms.getRequestContext().getSiteRoot() + oriUri)) { 237 // try to get base URI from cache 238 String cacheKey = exportManager.getCacheKey(targetSiteRoot, oriUri); 239 uriBaseName = exportManager.getCachedOnlineLink(cacheKey); 240 if (uriBaseName == null) { 241 // base not cached, check if we must export it 242 if (exportManager.isExportLink(cms, oriUri)) { 243 // base URI must also be exported 244 uriBaseName = exportManager.getRfsName(cms, oriUri); 245 } else { 246 // base URI dosn't need to be exported 247 CmsPair<String, String> uriParamPair = addVfsPrefix(cms, oriUri, targetSite, parameters); 248 uriBaseName = uriParamPair.getFirst(); 249 parameters = uriParamPair.getSecond(); 250 } 251 // cache export base URI 252 exportManager.cacheOnlineLink(cacheKey, uriBaseName); 253 } 254 // use relative links only on pages that get exported 255 useRelativeLinks = uriBaseName.startsWith( 256 exportManager.getRfsPrefix(cms.getRequestContext().getSiteRoot() + oriUri)); 257 } 258 259 String detailPagePart = detailPage == null ? "" : detailPage + ":"; 260 // check if we have the absolute VFS name for the link target cached 261 // (We really need the target site root in the cache key, because different resources with the same site paths 262 // but in different sites may have different export settings. It seems we don't really need the site root 263 // from the request context as part of the key, but we'll leave it in to make sure we don't break anything.) 264 String cacheKey = generateCacheKey(cms, siteRoot, targetSiteRoot, detailPagePart, absoluteLink); 265 resultLink = exportManager.getCachedOnlineLink(cacheKey); 266 if (resultLink == null) { 267 String storedSiteRoot = cms.getRequestContext().getSiteRoot(); 268 try { 269 cms.getRequestContext().setSiteRoot(targetSite.getSiteRoot()); 270 // didn't find the link in the cache 271 if (exportManager.isExportLink(cms, vfsName)) { 272 parameters = prepareExportParameters(cms, vfsName, parameters); 273 // export required, get export name for target link 274 resultLink = exportManager.getRfsName(cms, vfsName, parameters, targetDetailPage); 275 // now set the parameters to null, we do not need them anymore 276 parameters = null; 277 } else { 278 // no export required for the target link 279 CmsPair<String, String> uriParamPair = addVfsPrefix(cms, vfsName, targetSite, parameters); 280 resultLink = uriParamPair.getFirst(); 281 parameters = uriParamPair.getSecond(); 282 // add cut off parameters if required 283 if (parameters != null) { 284 resultLink = resultLink.concat(parameters); 285 } 286 } 287 } finally { 288 cms.getRequestContext().setSiteRoot(storedSiteRoot); 289 } 290 // cache the result 291 exportManager.cacheOnlineLink(cacheKey, resultLink); 292 } 293 294 // now check for the secure settings 295 296 // check if either the current site or the target site does have a secure server configured 297 if (targetSite.hasSecureServer() || currentSite.hasSecureServer()) { 298 299 if (!vfsName.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) { 300 // don't make a secure connection to the "/system" folder (why ?) 301 int linkType = -1; 302 try { 303 // read the linked resource 304 linkType = cms.readResource(originalVfsName).getTypeId(); 305 } catch (CmsException e) { 306 // the resource could not be read 307 if (LOG.isInfoEnabled()) { 308 String message = Messages.get().getBundle().key( 309 Messages.LOG_RESOURCE_ACESS_ERROR_3, 310 vfsName, 311 cms.getRequestContext().getCurrentUser().getName(), 312 cms.getRequestContext().getSiteRoot()); 313 if (LOG.isDebugEnabled()) { 314 LOG.debug(message, e); 315 } else { 316 LOG.info(message); 317 } 318 } 319 } 320 321 // images are always referenced without a server prefix 322 int imageId; 323 try { 324 imageId = OpenCms.getResourceManager().getResourceType( 325 CmsResourceTypeImage.getStaticTypeName()).getTypeId(); 326 } catch (CmsLoaderException e1) { 327 // should really never happen 328 LOG.warn(e1.getLocalizedMessage(), e1); 329 imageId = CmsResourceTypeImage.getStaticTypeId(); 330 } 331 boolean hasIsImageLinkAttr = Boolean.parseBoolean( 332 "" + cms.getRequestContext().getAttribute(ATTR_IS_IMAGE_LINK)); 333 if ((linkType != imageId) && !hasIsImageLinkAttr) { 334 // check the secure property of the link 335 boolean secureRequest = cms.getRequestContext().isSecureRequest() 336 || exportManager.isSecureLink(cms, oriUri); 337 338 boolean secureLink; 339 if (detailContent == null) { 340 secureLink = isSecureLink(cms, vfsName, targetSite, secureRequest); 341 } else { 342 secureLink = isDetailPageLinkSecure( 343 cms, 344 detailPage, 345 detailContent, 346 targetSite, 347 secureRequest); 348 349 } 350 // if we are on a normal server, and the requested resource is secure, 351 // the server name has to be prepended 352 if (secureLink && (forceSecure || !secureRequest)) { 353 serverPrefix = targetSite.getSecureUrl(); 354 } else if (!secureLink && secureRequest) { 355 serverPrefix = targetSite.getUrl(); 356 } 357 } 358 } 359 } 360 // make absolute link relative, if relative links in export are required 361 // and if the link does not point to another server 362 if (useRelativeLinks && CmsStringUtil.isEmpty(serverPrefix)) { 363 // in case the current page is a detailpage, append another path level 364 if (cms.getRequestContext().getDetailContentId() != null) { 365 uriBaseName = CmsStringUtil.joinPaths( 366 CmsResource.getFolderPath(uriBaseName), 367 cms.getRequestContext().getDetailContentId().toString() + "/index.html"); 368 } 369 resultLink = CmsLinkManager.getRelativeUri(uriBaseName, resultLink); 370 } 371 372 } else { 373 // offline project, no export or secure handling required 374 if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) { 375 // in unit test this code would fail otherwise 376 CmsPair<String, String> uriParamPair = addVfsPrefix(cms, vfsName, targetSite, parameters); 377 resultLink = uriParamPair.getFirst(); 378 parameters = uriParamPair.getSecond(); 379 } 380 381 // add cut off parameters and return the result 382 if ((parameters != null) && (resultLink != null)) { 383 resultLink = resultLink.concat(parameters); 384 } 385 } 386 387 if ((anchor != null) && (resultLink != null)) { 388 resultLink = resultLink.concat(anchor); 389 } 390 if (overrideSiteRoot != null) { 391 cms.getRequestContext().setAttribute(OVERRIDE_SITEROOT_PREFIX + resultLink, overrideSiteRoot); 392 } 393 394 return serverPrefix.concat(resultLink); 395 } 396 397 /** 398 * @see org.opencms.staticexport.I_CmsLinkSubstitutionHandler#getRootPath(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 399 */ 400 public String getRootPath(CmsObject cms, String targetUri, String basePath) { 401 402 String result = getSimpleRootPath(cms, targetUri, basePath); 403 String detailRootPath = getDetailRootPath(cms, result); 404 if (detailRootPath != null) { 405 result = detailRootPath; 406 } 407 return result; 408 409 } 410 411 /** 412 * Adds the VFS prefix to the VFS name and potentially adjusts request parameters<p> 413 * This method is required as a hook used in {@link CmsLocalePrefixLinkSubstitutionHandler}.<p> 414 * 415 * @param cms the cms context 416 * @param vfsName the VFS name 417 * @param targetSite the target site 418 * @param parameters the request parameters 419 * 420 * @return the path and the (adjusted) request parameters. 421 */ 422 protected CmsPair<String, String> addVfsPrefix( 423 CmsObject cms, 424 String vfsName, 425 CmsSite targetSite, 426 String parameters) { 427 428 return new CmsPair<String, String>(OpenCms.getStaticExportManager().getVfsPrefix().concat(vfsName), parameters); 429 } 430 431 /** 432 * Generates the cache key for Online links. 433 * @param cms the current CmsObject 434 * @param sourceSiteRoot the source site root (where the content linked to is located) 435 * @param targetSiteRoot the target site root 436 * @param detailPagePart the detail page part 437 * @param absoluteLink the absolute (site-relative) link to the resource 438 * @return the cache key 439 */ 440 protected String generateCacheKey( 441 CmsObject cms, 442 String sourceSiteRoot, 443 String targetSiteRoot, 444 String detailPagePart, 445 String absoluteLink) { 446 447 return "" 448 + cms.getRequestContext().getCurrentUser().getId() 449 + ":" 450 + cms.getRequestContext().getSiteRoot() 451 + ":" 452 + sourceSiteRoot 453 + ":" 454 + targetSiteRoot 455 + ":" 456 + detailPagePart 457 + absoluteLink; 458 } 459 460 /** 461 * Returns the root path for given site.<p> 462 * This method is required as a hook used in {@link CmsLocalePrefixLinkSubstitutionHandler}.<p> 463 * @param cms the cms context 464 * @param path the path 465 * @param siteRoot the site root, will be null in case of the root site 466 * @param isRootPath in case the path is already a root path 467 * 468 * @return the root path 469 */ 470 protected String getRootPathForSite(CmsObject cms, String path, String siteRoot, boolean isRootPath) { 471 472 if (isRootPath || (siteRoot == null)) { 473 return CmsStringUtil.joinPaths("/", path); 474 } else { 475 CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(siteRoot); 476 if (site != null) { 477 if (site.matchAlternativeSiteRoot(path)) { 478 siteRoot = site.getAlternativeSiteRootMapping().get().getSiteRoot().asString(); 479 } 480 } 481 return cms.getRequestContext().addSiteRoot(siteRoot, path); 482 } 483 } 484 485 /** 486 * Gets the root path without taking into account detail page links.<p> 487 * 488 * @param cms - see the getRootPath() method 489 * @param targetUri - see the getRootPath() method 490 * @param basePath - see the getRootPath() method 491 * @return - see the getRootPath() method 492 */ 493 protected String getSimpleRootPath(CmsObject cms, String targetUri, String basePath) { 494 495 if (cms == null) { 496 // required by unit test cases 497 return targetUri; 498 } 499 500 URI uri; 501 String path; 502 String suffix = ""; 503 504 // malformed uri 505 try { 506 uri = new URI(targetUri); 507 path = uri.getPath(); 508 suffix = getSuffix(uri); 509 } catch (Exception e) { 510 if (LOG.isWarnEnabled()) { 511 LOG.warn(Messages.get().getBundle().key(Messages.LOG_MALFORMED_URI_1, targetUri), e); 512 } 513 return null; 514 } 515 // opaque URI 516 if (uri.isOpaque()) { 517 return null; 518 } 519 520 // in case the target is the workplace UI 521 if (CmsLinkManager.isWorkplaceUri(uri)) { 522 return null; 523 } 524 525 // in case the target is a static resource served from the class path 526 if (CmsStaticResourceHandler.isStaticResourceUri(uri)) { 527 return CmsStringUtil.joinPaths( 528 CmsStaticResourceHandler.STATIC_RESOURCE_PREFIX, 529 CmsStaticResourceHandler.removeStaticResourcePrefix(path)); 530 } 531 532 CmsStaticExportManager exportManager = OpenCms.getStaticExportManager(); 533 if (exportManager.isValidRfsName(path)) { 534 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 535 String vfsName = null; 536 try { 537 cms.getRequestContext().setSiteRoot(""); 538 vfsName = exportManager.getVfsName(cms, path); 539 if (vfsName != null) { 540 return vfsName; 541 } 542 } finally { 543 cms.getRequestContext().setSiteRoot(originalSiteRoot); 544 } 545 } 546 547 // absolute URI (i.e. URI has a scheme component like http:// ...) 548 if (uri.isAbsolute()) { 549 CmsSiteMatcher targetMatcher = new CmsSiteMatcher(targetUri); 550 if (OpenCms.getSiteManager().isMatching(targetMatcher) 551 || targetMatcher.equalsIgnoreScheme(cms.getRequestContext().getRequestMatcher())) { 552 553 path = CmsLinkManager.removeOpenCmsContext(path); 554 boolean isWorkplaceServer = OpenCms.getSiteManager().isWorkplaceRequest(targetMatcher) 555 || targetMatcher.equalsIgnoreScheme(cms.getRequestContext().getRequestMatcher()); 556 if (isWorkplaceServer) { 557 String selectedPath; 558 String targetSiteRoot = OpenCms.getSiteManager().getSiteRoot(path); 559 if (targetSiteRoot != null) { 560 selectedPath = getRootPathForSite(cms, path, targetSiteRoot, true); 561 } else { 562 // set selectedPath with the path for the current site 563 selectedPath = getRootPathForSite(cms, path, cms.getRequestContext().getSiteRoot(), false); 564 String pathForMatchedSite = getRootPathForSite( 565 cms, 566 path, 567 OpenCms.getSiteManager().matchSite(targetMatcher).getSiteRoot(), 568 false); 569 String originalSiteRoot = cms.getRequestContext().getSiteRoot(); 570 try { 571 cms.getRequestContext().setSiteRoot(""); 572 // the path for the current site normally is preferred, but if it doesn't exist and the path for the matched site 573 // does exist, then use the path for the matched site 574 if (!cms.existsResource(selectedPath, CmsResourceFilter.ALL) 575 && cms.existsResource(pathForMatchedSite, CmsResourceFilter.ALL)) { 576 selectedPath = pathForMatchedSite; 577 } 578 } finally { 579 cms.getRequestContext().setSiteRoot(originalSiteRoot); 580 } 581 } 582 return selectedPath + suffix; 583 } else { 584 // add the site root of the matching site 585 return getRootPathForSite( 586 cms, 587 path + suffix, 588 OpenCms.getSiteManager().matchSite(targetMatcher).getSiteRoot(), 589 false); 590 } 591 } else { 592 return null; 593 } 594 } 595 596 // relative URI (i.e. no scheme component, but filename can still start with "/") 597 String context = OpenCms.getSystemInfo().getOpenCmsContext(); 598 String vfsPrefix = OpenCms.getStaticExportManager().getVfsPrefix(); 599 if ((context != null) && (path.startsWith(context + "/") || (path.startsWith(vfsPrefix + "/")))) { 600 // URI is starting with opencms context 601 602 // cut context from path 603 path = CmsLinkManager.removeOpenCmsContext(path); 604 605 String targetSiteRoot = getTargetSiteRoot(cms, path, basePath); 606 607 return getRootPathForSite( 608 cms, 609 path + suffix, 610 targetSiteRoot, 611 (targetSiteRoot != null) && path.startsWith(targetSiteRoot)); 612 } 613 614 // URI with relative path is relative to the given relativePath if available and in a site, 615 // otherwise invalid 616 if (CmsStringUtil.isNotEmpty(path) && (path.charAt(0) != '/')) { 617 if (basePath != null) { 618 String absolutePath; 619 int pos = path.indexOf("../../galleries/pics/"); 620 if (pos >= 0) { 621 // HACK: mixed up editor path to system gallery image folder 622 return CmsWorkplace.VFS_PATH_SYSTEM + path.substring(pos + 6) + suffix; 623 } 624 absolutePath = CmsLinkManager.getAbsoluteUri(path, cms.getRequestContext().addSiteRoot(basePath)); 625 if (OpenCms.getSiteManager().getSiteRoot(absolutePath) != null) { 626 return absolutePath + suffix; 627 } 628 // HACK: some editor components (e.g. HtmlArea) mix up the editor URL with the current request URL 629 absolutePath = CmsLinkManager.getAbsoluteUri( 630 path, 631 cms.getRequestContext().getSiteRoot() + CmsWorkplace.VFS_PATH_EDITORS); 632 if (OpenCms.getSiteManager().getSiteRoot(absolutePath) != null) { 633 return absolutePath + suffix; 634 } 635 // HACK: same as above, but XmlContent editor has one path element more 636 absolutePath = CmsLinkManager.getAbsoluteUri( 637 path, 638 cms.getRequestContext().getSiteRoot() + CmsWorkplace.VFS_PATH_EDITORS + "xmlcontent/"); 639 if (OpenCms.getSiteManager().getSiteRoot(absolutePath) != null) { 640 return absolutePath + suffix; 641 } 642 } 643 644 return null; 645 } 646 647 if (CmsStringUtil.isNotEmpty(path)) { 648 String targetSiteRoot = getTargetSiteRoot(cms, path, basePath); 649 650 return getRootPathForSite( 651 cms, 652 path + suffix, 653 targetSiteRoot, 654 (targetSiteRoot != null) && path.startsWith(targetSiteRoot)); 655 } 656 657 // URI without path (typically local link) 658 return suffix; 659 } 660 661 /** 662 * Checks whether a link to a detail page should be secure.<p> 663 * 664 * @param cms the current CMS context 665 * @param detailPage the detail page path 666 * @param detailContent the detail content resource 667 * @param targetSite the target site containing the detail page 668 * @param secureRequest true if the currently running request is secure 669 * 670 * @return true if the link should be a secure link 671 */ 672 protected boolean isDetailPageLinkSecure( 673 CmsObject cms, 674 String detailPage, 675 CmsResource detailContent, 676 CmsSite targetSite, 677 boolean secureRequest) { 678 679 boolean result = false; 680 CmsStaticExportManager exportManager = OpenCms.getStaticExportManager(); 681 try { 682 cms = OpenCms.initCmsObject(cms); 683 if (targetSite.getSiteRoot() != null) { 684 cms.getRequestContext().setSiteRoot(targetSite.getSiteRoot()); 685 } 686 CmsResource defaultFile = cms.readDefaultFile(detailPage); 687 if (defaultFile != null) { 688 result = exportManager.isSecureLink(cms, defaultFile.getRootPath(), "", secureRequest); 689 } 690 } catch (Exception e) { 691 LOG.error("Error while checking whether detail page link should be secure: " + e.getLocalizedMessage(), e); 692 } 693 return result; 694 } 695 696 /** 697 * Checks if the link target is a secure link.<p 698 * 699 * @param cms the current CMS context 700 * @param vfsName the path of the link target 701 * @param targetSite the target site containing the detail page 702 * @param secureRequest true if the currently running request is secure 703 * 704 * @return true if the link should be a secure link 705 */ 706 protected boolean isSecureLink(CmsObject cms, String vfsName, CmsSite targetSite, boolean secureRequest) { 707 708 return OpenCms.getStaticExportManager().isSecureLink(cms, vfsName, targetSite.getSiteRoot(), secureRequest); 709 } 710 711 /** 712 * Prepares the request parameters for the given resource.<p> 713 * This method is required as a hook used in {@link CmsLocalePrefixLinkSubstitutionHandler}.<p> 714 * 715 * @param cms the cms context 716 * @param vfsName the vfs name 717 * @param parameters the parameters to prepare 718 * 719 * @return the root path 720 */ 721 protected String prepareExportParameters(CmsObject cms, String vfsName, String parameters) { 722 723 return parameters; 724 } 725 726 /** 727 * Gets the suffix (query + fragment) of the URI.<p> 728 * 729 * @param uri the URI 730 * @return the suffix of the URI 731 */ 732 String getSuffix(URI uri) { 733 734 String fragment = uri.getFragment(); 735 if (fragment != null) { 736 fragment = "#" + fragment; 737 } else { 738 fragment = ""; 739 } 740 741 String query = uri.getRawQuery(); 742 if (query != null) { 743 query = "?" + query; 744 } else { 745 query = ""; 746 } 747 return query.concat(fragment); 748 } 749 750 /** 751 * Tries to interpret the given URI as a detail page URI and returns the detail content's root path if possible.<p> 752 * 753 * If the given URI is not a detail URI, null will be returned.<p> 754 * 755 * @param cms the CMS context to use 756 * @param result the detail root path, or null if the given uri is not a detail page URI 757 * 758 * @return the detail content root path 759 */ 760 private String getDetailRootPath(CmsObject cms, String result) { 761 762 if (result == null) { 763 return null; 764 } 765 try { 766 URI uri = new URI(result); 767 String path = uri.getPath(); 768 if (CmsStringUtil.isEmptyOrWhitespaceOnly(path) || !OpenCms.getADEManager().isInitialized()) { 769 return null; 770 } 771 String name = CmsFileUtil.removeTrailingSeparator(CmsResource.getName(path)); 772 CmsUUID detailId = null; 773 if (cms.getRequestContext().getAttribute(CmsDetailNameCache.ATTR_BYPASS) != null) { 774 detailId = cms.readIdForUrlName(name); 775 } else { 776 if (CmsUUID.isValidUUID(name)) { 777 detailId = new CmsUUID(name); 778 } else { 779 detailId = OpenCms.getADEManager().getDetailIdCache( 780 cms.getRequestContext().getCurrentProject().isOnlineProject()).getDetailId(name); 781 } 782 } 783 if (detailId == null) { 784 return null; 785 } 786 String origSiteRoot = cms.getRequestContext().getSiteRoot(); 787 try { 788 cms.getRequestContext().setSiteRoot(""); 789 // real root paths have priority over detail contents 790 if (cms.existsResource(path)) { 791 return null; 792 } 793 } finally { 794 cms.getRequestContext().setSiteRoot(origSiteRoot); 795 } 796 CmsResource detailResource = cms.readResource(detailId, CmsResourceFilter.ALL); 797 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(detailResource); 798 if (!OpenCms.getADEManager().getDetailPageTypes(cms).contains(type.getTypeName())) { 799 return null; 800 } 801 return detailResource.getRootPath() + getSuffix(uri); 802 } catch (Exception e) { 803 LOG.error(e.getLocalizedMessage(), e); 804 return null; 805 } 806 } 807 808 /** 809 * Returns the target site for the given path.<p> 810 * 811 * @param cms the cms context 812 * @param path the path 813 * @param basePath the base path 814 * 815 * @return the target site 816 */ 817 private String getTargetSiteRoot(CmsObject cms, String path, String basePath) { 818 819 if (OpenCms.getSiteManager().startsWithShared(path) || path.startsWith(CmsWorkplace.VFS_PATH_SYSTEM)) { 820 return null; 821 } 822 String targetSiteRoot = OpenCms.getSiteManager().getSiteRoot(path); 823 if ((targetSiteRoot == null) && (basePath != null)) { 824 targetSiteRoot = OpenCms.getSiteManager().getSiteRoot(basePath); 825 } 826 if (targetSiteRoot == null) { 827 targetSiteRoot = cms.getRequestContext().getSiteRoot(); 828 } 829 return targetSiteRoot; 830 } 831 832}