diff --git a/app/code/Magento/Store/App/FrontController/Plugin/RequestPreprocessor.php b/app/code/Magento/Store/App/FrontController/Plugin/RequestPreprocessor.php
index ff49a20427f8c..849952eae6218 100644
--- a/app/code/Magento/Store/App/FrontController/Plugin/RequestPreprocessor.php
+++ b/app/code/Magento/Store/App/FrontController/Plugin/RequestPreprocessor.php
@@ -66,26 +66,28 @@ public function aroundDispatch(
\Closure $proceed,
\Magento\Framework\App\RequestInterface $request
) {
- if (!$request->isPost() && $this->getBaseUrlChecker()->isEnabled()) {
+ if ($this->getBaseUrlChecker()->isEnabled()) {
$baseUrl = $this->_storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_WEB,
$this->_storeManager->getStore()->isCurrentlySecure()
);
if ($baseUrl) {
$uri = parse_url($baseUrl);
- if (!$this->getBaseUrlChecker()->execute($uri, $request)) {
- $redirectUrl = $this->_url->getRedirectUrl(
- $this->_url->getUrl(ltrim($request->getPathInfo(), '/'), ['_nosid' => true])
- );
- $redirectCode = (int)$this->_scopeConfig->getValue(
- 'web/url/redirect_to_base',
- \Magento\Store\Model\ScopeInterface::SCOPE_STORE
- ) !== 301 ? 302 : 301;
+ if (!$request->isPost()) {
+ if (!$this->getBaseUrlChecker()->execute($uri, $request)) {
+ $redirectUrl = $this->_url->getRedirectUrl(
+ $this->_url->getUrl(ltrim($request->getPathInfo(), '/'), ['_nosid' => true])
+ );
+ $redirectCode = (int)$this->_scopeConfig->getValue(
+ 'web/url/redirect_to_base',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ ) !== 301 ? 302 : 301;
- $response = $this->_responseFactory->create();
- $response->setRedirect($redirectUrl, $redirectCode);
- $response->setNoCacheHeaders();
- return $response;
+ $response = $this->_responseFactory->create();
+ $response->setRedirect($redirectUrl, $redirectCode);
+ $response->setNoCacheHeaders();
+ return $response;
+ }
}
}
}
diff --git a/app/code/Magento/Store/App/Http/Plugin/StoreHttp.php b/app/code/Magento/Store/App/Http/Plugin/StoreHttp.php
new file mode 100644
index 0000000000000..6c0f7ada75ead
--- /dev/null
+++ b/app/code/Magento/Store/App/Http/Plugin/StoreHttp.php
@@ -0,0 +1,70 @@
+_storeManager = $storeManager;
+ $this->_url = $url;
+ $this->_request = $request;
+ }
+
+ /**
+ * Update the request's pathInfo if we have a store on a url path
+ *
+ * This will make sure we match the correct area and so the requested url
+ * will be routed via the correct path.
+ *
+ * @return void
+ */
+ public function beforeLaunch()
+ {
+ $baseUrl = $this->_storeManager->getStore()->getBaseUrl(
+ UrlInterface::URL_TYPE_WEB,
+ $this->_storeManager->getStore()->isCurrentlySecure()
+ );
+ if ($baseUrl) {
+ $uri = parse_url($baseUrl);
+ if (isset($uri['path']) && '/' !== $uri['path']) {
+ $newPath = str_replace(
+ $uri['path'],
+ '',
+ $this->_request->getPathInfo()
+ );
+ if ('/' !== substr($newPath, 0, 1)) {
+ $newPath = '/' . $newPath;
+ }
+ $this->_request->setPathInfo($newPath);
+ }
+ }
+ }
+}
diff --git a/app/code/Magento/Store/App/Response/Redirect.php b/app/code/Magento/Store/App/Response/Redirect.php
index f214d9ce4369f..f2afdf15b5958 100644
--- a/app/code/Magento/Store/App/Response/Redirect.php
+++ b/app/code/Magento/Store/App/Response/Redirect.php
@@ -8,6 +8,7 @@
namespace Magento\Store\App\Response;
use Magento\Store\Api\StoreResolverInterface;
+use Magento\Store\Api\Data\StoreInterface;
class Redirect implements \Magento\Framework\App\Response\RedirectInterface
{
@@ -208,13 +209,111 @@ protected function _isUrlInternal($url)
{
if (strpos($url, 'http') !== false) {
$directLinkType = \Magento\Framework\UrlInterface::URL_TYPE_DIRECT_LINK;
- $unsecureBaseUrl = $this->_storeManager->getStore()->getBaseUrl($directLinkType, false);
- $secureBaseUrl = $this->_storeManager->getStore()->getBaseUrl($directLinkType, true);
- return (strpos($url, $unsecureBaseUrl) === 0) || (strpos($url, $secureBaseUrl) === 0);
+ $currentStore = $this->_storeManager->getStore();
+ $currentStoreUnsecureBaseUrl = $currentStore
+ ->getBaseUrl($directLinkType, false);
+ $currentStoreSecureBaseUrl = $currentStore
+ ->getBaseUrl($directLinkType, true);
+ $internal = (
+ strpos($url, $currentStoreUnsecureBaseUrl) === 0
+ || strpos($url, $currentStoreSecureBaseUrl) === 0
+ );
+ if (true === $internal) {
+ $internal = ! $this->_isUrlFromOtherStore($url, $currentStore);
+ }
+ return $internal;
}
return false;
}
+ /**
+ * check if an 'internal' url is coming from another store
+ *
+ * @param string $url
+ * @param \Magento\Store\Api\Data\StoreInterface $currentStore
+ * @return bool
+ */
+ protected function _isUrlFromOtherStore($url, \Magento\Store\Api\Data\StoreInterface $currentStore)
+ {
+ /**
+ * check if the referer belongs to another storeview
+ */
+ $linkFromOtherStoreview = false;
+ $stores = $this->_storeManager->getStores(true);
+ foreach ($stores as $store) {
+ if ($currentStore->getId() !== $store->getId()) {
+ $isChildStore = $this->_checkStoreIsChildOfCurrentStore(
+ $url,
+ $currentStore,
+ $store
+ );
+ if (true === $isChildStore
+ && false === $linkFromOtherStoreview) {
+ $linkFromOtherStoreview = true;
+ }
+ }
+ }
+ return $linkFromOtherStoreview;
+ }
+
+ /**
+ * check if a store has a 'child' url of the current store
+ *
+ * example:
+ * - $currentStore has url https://store.com/
+ * - $store has url https://store.com/nl/
+ * Here we should return true since the $store's url is just adding an
+ * extra path to the $currentStore.
+ *
+ * @param string $url
+ * @param \Magento\Store\Api\Data\StoreInterface $currentStore
+ * @param \Magento\Store\Api\Data\StoreInterface $store
+ * @return bool
+ */
+ protected function _checkStoreIsChildOfCurrentStore(
+ $url,
+ \Magento\Store\Api\Data\StoreInterface $currentStore,
+ \Magento\Store\Api\Data\StoreInterface $store
+ ) {
+ $directLinkType = \Magento\Framework\UrlInterface::URL_TYPE_DIRECT_LINK;
+
+ $currentStoreUnsecureBaseUrl = $currentStore
+ ->getBaseUrl($directLinkType, false);
+ $currentStoreSecureBaseUrl = $currentStore
+ ->getBaseUrl($directLinkType, true);
+
+ $unsecureBaseUrl = $store
+ ->getBaseUrl($directLinkType, false);
+ $secureBaseUrl = $store
+ ->getBaseUrl($directLinkType, true);
+ // does the beginning of the url matches another
+ // store in this system
+ // indicating the other store is just an additional
+ // item in the url path
+ //
+ // example:
+ // basestore = http://example.com/
+ // german store = http://example.com/de/
+ $canMatchOtherStoreView = (
+ strpos($url, $unsecureBaseUrl) === 0
+ || strpos($url, $secureBaseUrl) === 0
+ );
+ // check if the other store's baseurl could be the
+ // 'parent' of the current stores baseurl unless the
+ // baseurl is exactly the same.
+ $otherStoreViewSubCurrentStore = (
+ (strpos($unsecureBaseUrl, $currentStoreUnsecureBaseUrl) === 0
+ || strpos($secureBaseUrl, $currentStoreSecureBaseUrl) === 0)
+ && ($currentStoreUnsecureBaseUrl !== $unsecureBaseUrl
+ && $currentStoreSecureBaseUrl !== $secureBaseUrl)
+ );
+ // when the url can also match the other store
+ // and the other store's baseurl is a 'child' of the
+ // current store's baseurl state the link is coming
+ // from external (other store)
+ return $canMatchOtherStoreView && $otherStoreViewSubCurrentStore;
+ }
+
/**
* Normalize path to avoid wrong store change
*
diff --git a/app/code/Magento/Store/Block/Switcher.php b/app/code/Magento/Store/Block/Switcher.php
index d5560b857a2c8..540f4a72a330a 100644
--- a/app/code/Magento/Store/Block/Switcher.php
+++ b/app/code/Magento/Store/Block/Switcher.php
@@ -221,7 +221,7 @@ public function getTargetStorePostData(\Magento\Store\Model\Store $store, $data
{
$data[\Magento\Store\Api\StoreResolverInterface::PARAM_NAME] = $store->getCode();
return $this->_postDataHelper->getPostData(
- $this->getUrl('stores/store/switch'),
+ $this->getUrl('stores/store/switch', ['_scope' => $store]),
$data
);
}
diff --git a/app/code/Magento/Store/Test/Unit/App/Response/RedirectTest.php b/app/code/Magento/Store/Test/Unit/App/Response/RedirectTest.php
index 18b303763a5ac..f8769c23c48ce 100644
--- a/app/code/Magento/Store/Test/Unit/App/Response/RedirectTest.php
+++ b/app/code/Magento/Store/Test/Unit/App/Response/RedirectTest.php
@@ -82,6 +82,8 @@ public function testSuccessUrl($baseUrl, $successUrl)
$this->_requestMock->expects($this->any())->method('getParam')->will($this->returnValue(null));
$this->_storeManagerMock->expects($this->any())->method('getStore')
->will($this->returnValue($testStoreMock));
+ $this->_storeManagerMock->expects($this->any())->method('getStores')
+ ->will($this->returnValue([$testStoreMock]));
$this->assertEquals($baseUrl, $this->_model->success($successUrl));
}
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index 3e9192c24d533..8b44d69585957 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -24,6 +24,9 @@
+
+
+