diff --git a/config/schema/redirect.schema.yml b/config/schema/redirect.schema.yml index 263e0ae..82d230c 100644 --- a/config/schema/redirect.schema.yml +++ b/config/schema/redirect.schema.yml @@ -59,11 +59,13 @@ redirect.domain: type: sequence label: 'Domain redirects' sequence: - type: mapping - mapping: - from: - type: string - label: 'From domain' - to: - type: string - label: 'To domain' + type: sequence + sequence: + type: mapping + mapping: + sub_path: + type: string + label: 'Sub path' + to_domain: + type: string + label: 'To domain' diff --git a/src/EventSubscriber/RedirectRequestSubscriber.php b/src/EventSubscriber/RedirectRequestSubscriber.php index ec549a6..81b2292 100644 --- a/src/EventSubscriber/RedirectRequestSubscriber.php +++ b/src/EventSubscriber/RedirectRequestSubscriber.php @@ -137,29 +137,28 @@ class RedirectRequestSubscriber implements EventSubscriberInterface { if (!empty($domains)) { $host = $request->getHost(); $path = $request->getRequestUri(); - $from_domain = $request->getHost() . $request->getRequestUri(); $to_domain = NULL; // Checks if there is a redirect domain in the configuration. - foreach ($domains as $domain) { - if (strpos($domain['from'], $from_domain) !== FALSE) { - $to_domain = $domain['to']; - break; - } - // Check for a wildcard in the domains. - if (strpos($domain['from'], '*')) { - $replace_path = substr($domain['from'], strpos($domain['from'], '/')); - $domain_base_uri = substr($domain['from'], 0, -2); - if (strpos($from_domain, $domain_base_uri) !== FALSE) { - $sub_path = substr($path, strlen($replace_path) - 2); - $to_domain = $domain['to'] . $sub_path; + if (isset($domains[str_replace('.', ':', $host)])) { + foreach ($domains[str_replace('.', ':', $host)] as $item) { + if ($path === $item['sub_path']) { + $to_domain = $item['to_domain']; break; } + // Check for a wildcard in the domains. + else if (strpos($item['sub_path'], '*') !== FALSE) { + $sub_path = substr($item['sub_path'], 0, -1); + if (strpos($path, $sub_path) !== FALSE) { + $to_domain = $item['to_domain'] . '/' . substr($path, strlen($sub_path)); + break; + } + } + } + if ($to_domain) { + $response = new TrustedRedirectResponse($to_domain); + $event->setResponse($response); + return; } - } - if ($to_domain) { - $response = new TrustedRedirectResponse($to_domain); - $event->setResponse($response); - return; } } } diff --git a/src/Form/RedirectDomainForm.php b/src/Form/RedirectDomainForm.php index ac02587..b9b6944 100644 --- a/src/Form/RedirectDomainForm.php +++ b/src/Form/RedirectDomainForm.php @@ -41,6 +41,7 @@ class RedirectDomainForm extends ConfigFormBase { '#tree' => TRUE, '#header' => [ $this->t('From domain'), + $this->t('Sub path'), $this->t('To domain') ], '#prefix' => '
', @@ -50,17 +51,23 @@ class RedirectDomainForm extends ConfigFormBase { $rows = []; // Obtain domain redirects from configuration. if ($domain_redirects = $this->config('redirect.domain')->get('domain_redirects')) { - foreach ($domain_redirects as $domain_redirect) { - $form['redirects'][] = [ - 'from' => [ - '#type' => 'textfield', - '#value' => $domain_redirect['from'], - ], - 'to' => [ - '#type' => 'textfield', - '#value' => $domain_redirect['to'], - ], - ]; + foreach ($domain_redirects as $key => $value) { + foreach ($value as $item) { + $form['redirects'][] = [ + 'from' => [ + '#type' => 'textfield', + '#value' => str_replace(':','.',$key), + ], + 'sub_path' => [ + '#type' => 'textfield', + '#value' => $item['sub_path'], + ], + 'to' => [ + '#type' => 'textfield', + '#value' => $item['to_domain'], + ], + ]; + } } } @@ -70,6 +77,10 @@ class RedirectDomainForm extends ConfigFormBase { 'from' => [ '#type' => 'textfield', ], + 'sub_path' => [ + '#type' => 'textfield', + '#value' => '/', + ], 'to' => [ '#type' => 'textfield', ], @@ -123,7 +134,7 @@ class RedirectDomainForm extends ConfigFormBase { parent::validateForm($form, $form_state); if ($redirects = $form_state->getValue('redirects')) { foreach ($redirects as $redirect) { - if (strpos($redirect['from'], '://') !== FALSE || strpos($redirect['to'], '://') !== FALSE) { + if (strpos($redirect['from'], '://') !== FALSE) { $form_state->setErrorByName('redirects', t('No protocol should be included in the redirect domain.')); } } @@ -140,9 +151,11 @@ class RedirectDomainForm extends ConfigFormBase { if ($redirects = $form_state->getValue('redirects')) { foreach ($redirects as $redirect) { if (!empty($redirect['from']) && !empty($redirect['to'])) { - $domain_redirects[] = [ - 'from' => $redirect['from'], - 'to' => $redirect['to'], + // Replace '.' with ':' for an eligible key. + $redirect['from'] = str_replace('.',':',$redirect['from']); + $domain_redirects[$redirect['from']][] = [ + 'sub_path' => $redirect['sub_path']? : '/', + 'to_domain' => $redirect['to'] ]; } } diff --git a/src/Tests/GlobalRedirectTest.php b/src/Tests/GlobalRedirectTest.php index 711a36e..a0fb275 100644 --- a/src/Tests/GlobalRedirectTest.php +++ b/src/Tests/GlobalRedirectTest.php @@ -226,6 +226,7 @@ class GlobalRedirectTest extends WebTestBase { // Assert that there are 2 domain redirect fields. $this->assertFieldByName('redirects[0][from]'); + $this->assertFieldByName('redirects[0][sub_path]'); $this->assertFieldByName('redirects[0][to]'); // Add another field for new domain redirect. diff --git a/tests/src/Unit/RedirectRequestSubscriberTest.php b/tests/src/Unit/RedirectRequestSubscriberTest.php index 6b161cf..976e58b 100644 --- a/tests/src/Unit/RedirectRequestSubscriberTest.php +++ b/tests/src/Unit/RedirectRequestSubscriberTest.php @@ -104,6 +104,80 @@ class RedirectRequestSubscriberTest extends UnitTestCase { } /** + * Tests redirect between domains. + */ + public function testDomainRedirect() { + $redirect = $this->getMockBuilder('Drupal\redirect\Entity\Redirect') + ->disableOriginalConstructor() + ->getMock(); + + // Make a request to http://foo.com/example and get the response. + $event = $this->getGetResponseEventStub('http://foo.com/example', http_build_query([])); + $request = $event->getRequest(); + + $checker = $this->getMockBuilder('Drupal\redirect\RedirectChecker') + ->disableOriginalConstructor() + ->getMock(); + $checker->expects($this->any()) + ->method('canRedirect') + ->will($this->returnValue(TRUE)); + $checker->expects($this->any()) + ->method('isLoop') + ->will($this->returnValue(FALSE)); + $context = $this->getMock('Symfony\Component\Routing\RequestContext'); + + $inbound_path_processor = $this->getMockBuilder('Drupal\Core\PathProcessor\InboundPathProcessorInterface') + ->disableOriginalConstructor() + ->getMock(); + $inbound_path_processor->expects($this->any()) + ->method('processInbound') + ->with($request->getPathInfo(), $request) + ->will($this->returnValue($request->getPathInfo())); + + $alias_manager = $this->getMockBuilder('Drupal\Core\Path\AliasManager') + ->disableOriginalConstructor() + ->getMock(); + $module_handler = $this->getMockBuilder('Drupal\Core\Extension\ModuleHandlerInterface') + ->getMock(); + $entity_manager = $this->getMockBuilder('Drupal\Core\Entity\EntityManagerInterface') + ->getMock(); + + // Set up the configuration for the requested domain. + $config_factory = $this->getConfigFactoryStub([ + 'redirect.domain' => [ + 'domain_redirects' => [ + 'foo:com' => [ + [ + 'sub_path' => '/*', + 'to_domain' => 'bar.com' + ], + ] + ] + ] + ]); + $subscriber = new RedirectRequestSubscriber( + $this->getRedirectRepositoryStub('findMatchingRedirect', $redirect), + $this->getLanguageManagerStub(), + $config_factory, + $alias_manager, + $module_handler, + $entity_manager, + $checker, + $context, + $inbound_path_processor + ); + + // Run the main redirect method. + $subscriber->onKernelRequestCheckRedirect($event); + + $this->assertTrue($event->getResponse() instanceof RedirectResponse); + $response = $event->getResponse(); + // Make sure that the response is properly redirected. + $this->assertEquals('bar.com/example', $response->getTargetUrl()); + $this->assertEquals(302, $response->getStatusCode()); + } + + /** * Instantiates the subscriber and runs onKernelRequestCheckRedirect() * * @param $redirect