Skip to content

Commit

Permalink
refactor subdomain processing and add test to it (#204)
Browse files Browse the repository at this point in the history
* refactor subdomain processing and add test to it

* add other envs to deployment
  • Loading branch information
microstudi authored and davidbeig committed Sep 29, 2021
1 parent 0676f38 commit 1bc591c
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 70 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/deployer.yml
Expand Up @@ -6,6 +6,8 @@ on:
- live
- staging
- beta
- alpha
- edge

jobs:
deployer:
Expand Down
90 changes: 20 additions & 70 deletions src/Goteo/Application/EventListener/SessionListener.php
Expand Up @@ -23,6 +23,7 @@
use Goteo\Application\Currency;
use Goteo\Library\Text;
use Goteo\Model\Image;
use Goteo\Util\Parsers\UrlLang;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -34,24 +35,6 @@

class SessionListener extends AbstractListener {

/**
* Chechsk if any of the elements in array $prefixes starts with the same chars as $full_str
* @param [type] $full_str full string
* @param [type] $prefixes array of prexixes
* @return boolean found or not
*/
protected function matchPrefix($full_str, $prefixes) {
if(!is_array($prefixes)) {
$prefixes = [$prefixes];
}
foreach($prefixes as $str) {
if(strpos($full_str, $str) === 0) {
return true;
}
}
return false;
}

public function onRequest(GetResponseEvent $event) {

//not need to do anything on sub-requests
Expand All @@ -60,14 +43,15 @@ public function onRequest(GetResponseEvent $event) {
}

$request = $event->getRequest();
$path = $request->getPathInfo();

$parser = new UrlLang($request);

//non cookies for notifyAction on investController
$skip = Config::get('session.skip');
if ($this->matchPrefix($path, $skip)) {
if($parser->skipSessionManagement()) {
return;
}


// clean all caches if requested
// TODO: replace by some controller
if ($request->query->has('cleancache')) {
Expand Down Expand Up @@ -105,66 +89,32 @@ public function onRequest(GetResponseEvent $event) {

// Set lang
$lang = Lang::setFromGlobals($request);
// Cookie
// the stupid cookie EU law
if (!Cookie::exists('goteo_cookies')) {
// print_r($_COOKIE);die('cooki');
Cookie::store('goteo_cookies', 'ok');
// print_r($_COOKIE);die('cooki');
Message::info(Text::get('message-cookies'));
}


$url = $request->getHttpHost();
// Routes to leave as they are
$skip = Config::get('url.redirect.skip');
// Routes to alway reditect to the main url
$fixed = Config::get('url.redirect.fixed');
// Redirect to proper URL if url_lang is defined
if (Config::get('url.url_lang') && !$this->matchPrefix($path, $skip)) {
$parts = explode('.', $url);
$sub_lang = $parts[0];
if($sub_lang == 'www') $sub_lang = Config::get('lang');
if (Lang::exists($sub_lang)) {
// reduce url: ca.goteo.org => goteo.org
array_shift($parts);
$url = implode('.', $parts);
}
// if reduced URL is the main domain, redirect to sub-level lang
if(count($parts) == 2) {
if($request->query->has('lang')) {
$request->query->remove('lang');
}
// Login controller should mantaing always the same URL to help browser
if($this->matchPrefix($path, $fixed)) {
// $url = "$url";
$request->query->set('lang', $lang);
}
else {
$url = preg_replace('!https?://|/$!i', '', Lang::getUrl($lang));
}

}
// print_r($parts);echo "$url [$sub_lang=>$lang] ";die;
}

$host = $parser->getHost($lang);
// Mantain user in secure enviroment if logged and ssl config on
if (Config::get('ssl') && Session::isLogged() && !$request->isSecure()) {
// Force HTTPS redirection
$url = 'https://' . $url;
$host = 'https://' . $host;
} else {
// Conserve the current scheme
$url = $request->getScheme() . '://' . $url;
$host = $request->getScheme() . '://' . $host;
}

// Redirect if needed
if ($url != $request->getScheme() . '://' . $request->getHttpHost()) {
if ($host != $request->getScheme() . '://' . $request->getHttpHost()) {
$query = http_build_query($request->query->all());
// die($url . $request->getPathInfo() . ($query ? "?$query" : ''));
$event->setResponse(new RedirectResponse($url . $request->getPathInfo() . ($query ? "?$query" : '')));
// die($host . $request->getPathInfo() . ($query ? "?$query" : ''));
$event->setResponse(new RedirectResponse($host . $request->getPathInfo() . ($query ? "?$query" : '')));
return;
}
// die("[$url] - " .$request->getScheme() . '://' . $request->getHttpHost());
// die("[$host] - " .$request->getScheme() . '://' . $request->getHttpHost());

// the stupid cookie EU law
if (!Cookie::exists('goteo_cookies')) {
// print_r($_COOKIE);die('cooki');
Cookie::store('goteo_cookies', 'ok');
// print_r($_COOKIE);die('cooki');
Message::info(Text::get('message-cookies'));
}

// set currency
$currency = $request->query->get('currency');
Expand Down
100 changes: 100 additions & 0 deletions src/Goteo/Util/Parsers/UrlLang.php
@@ -0,0 +1,100 @@
<?php
/*
* This file is part of the Goteo Package.
*
* (c) Platoniq y Fundación Goteo <fundacion@goteo.org>
*
* For the full copyright and license information, please view the README.md
* and LICENSE files that was distributed with this source code.
*/

namespace Goteo\Util\Parsers;

use Goteo\Application\Config;
use Goteo\Application\Lang;
use Symfony\Component\HttpFoundation\Request;

class UrlLang {
public $request;
protected $path;
protected $host;

public function __construct(Request $request) {
$this->request = $request;
$this->path = $request->getPathInfo();
$this->host = $request->getHttpHost();
}

/**
* Returns false if the requests is configured to skip any cookie setting
*/
public function skipSessionManagement() {
$skip = Config::get('session.skip');
if ($this->matchPrefix($this->path, $skip)) {
return true;
}
return false;
}

/**
* Returns the proper URL after processing url_lang configurations (adds subdomain lang if needed)
*/
public function getHost($lang) {
$host = $this->host;
if(empty($lang)) {
return $host;
}

// Routes to leave as they are
$skip = Config::get('url.redirect.skip');
// Redirect to proper URL if url_lang is defined
if (!Config::get('url.url_lang') || $this->matchPrefix($this->path, $skip)) {
return $host;
}

// Routes to alway reditect to the main url
$fixed = Config::get('url.redirect.fixed');
$parts = explode('.', $host);
$sub_lang = $parts[0];
if($sub_lang == 'www') $sub_lang = Config::get('lang');
if (Lang::exists($sub_lang)) {
// reduce url: ca.goteo.org => goteo.org
array_shift($parts);
$host = implode('.', $parts);
}
// if reduced URL is the main domain, redirect to sub-level lang
if($host === Config::get("url.url_lang")) {
if($this->request->query->has('lang')) {
$this->request->query->remove('lang');
}
// Login controller should mantaing always the same URL to help browser password management
if($this->matchPrefix($this->path, $fixed)) {
// $host = "$host";
$this->request->query->set('lang', $lang);
}
else {
$host = preg_replace('!https?://|/$!i', '', Lang::getUrl($lang));
}

}
return $host;
}

/**
* Chechsk if any of the elements in array $prefixes starts with the same chars as $full_str
* @param string $full_str full string
* @param array $prefixes array of prexixes
* @return boolean found or not
*/
protected function matchPrefix($full_str, $prefixes) {
if(!is_array($prefixes)) {
$prefixes = [$prefixes];
}
foreach($prefixes as $str) {
if(strpos($full_str, $str) === 0) {
return true;
}
}
return false;
}
}
118 changes: 118 additions & 0 deletions tests/Goteo/Util/Parsers/UrlLangTest.php
@@ -0,0 +1,118 @@
<?php

namespace Goteo\Util\Tests;

use Goteo\Util\Parsers\UrlLang;
use Goteo\Application\Config;
use Symfony\Component\HttpFoundation\Request;

class UrlLangTest extends \PHPUnit\Framework\TestCase {

protected function getParser($url, $host="http://example.com") {
$request = Request::create("$host$url");
return new UrlLang($request);
}

public function testInstance() {
$parser = $this->getParser("/");

$this->assertInstanceOf('\Goteo\Util\Parsers\UrlLang', $parser);

return $parser;
}

/**
* @depends testInstance
* */
public function testSkipSessionManagement($parser) {
$this->assertFalse($parser->skipSessionManagement());

$parser = $this->getParser("/test/something");
$this->assertFalse($parser->skipSessionManagement());

Config::set('session.skip', "/test");
$this->assertTrue($parser->skipSessionManagement());

Config::set('session.skip', ["/test"]);
$this->assertTrue($parser->skipSessionManagement());

}

/**
* @depends testInstance
* */
public function testDomainLang($parser) {
$this->assertEquals("example.com", $parser->getHost(""));

$parser = $this->getParser("/test/something");
$this->assertEquals("example.com", $parser->getHost(""));

Config::set('url.url_lang', "example.com");
$this->assertEquals("example.com", $parser->getHost(""));
$this->assertEquals("en.example.com", $parser->getHost("en"));

Config::set("lang", "es");
$this->assertEquals("www.example.com", $parser->getHost("es"));
$this->assertEquals("en.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.example.com");
$this->assertEquals("en.example.com", $parser->getHost("en"));

return $parser;
}

/**
* @depends testDomainLang
* */
public function testRedirectSkip($parser) {
$parser = $this->getParser("/api");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/api", "http://www.example.com");
$this->assertEquals("www.example.com", $parser->getHost("en"));

$parser = $this->getParser("/password-recovery", "http://ca.example.com");
$this->assertEquals("ca.example.com", $parser->getHost("en"));
}

/**
* @depends testDomainLang
* */
public function testFixedRedirection($parser) {
$parser = $this->getParser("/login");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/login", "http://www.example.com");
$this->assertEquals("example.com", $parser->getHost("en"));

$parser = $this->getParser("/password-reset", "http://ca.example.com");
$this->assertEquals("example.com", $parser->getHost("en"));
}

/**
* @depends testDomainLang
* */
public function testSubdomains($parser) {
$parser = $this->getParser("/api", "http://www.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("en"));
$parser = $this->getParser("/login", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

Config::set('url.url_lang', "sub.example.com");

$parser = $this->getParser("/api", "http://www.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("en"));
$parser = $this->getParser("/login", "http://www.sub.example.com");
$this->assertEquals("sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/", "http://www.sub.example.com");
$this->assertEquals("en.sub.example.com", $parser->getHost("en"));

$parser = $this->getParser("/test/something", "http://en.sub.example.com");
$this->assertEquals("www.sub.example.com", $parser->getHost("es"));
$this->assertEquals("ca.sub.example.com", $parser->getHost("ca"));
}
}

0 comments on commit 1bc591c

Please sign in to comment.