Skip to content

Commit

Permalink
Issue appserver-io#183: Echo directive parser in SSI Module
Browse files Browse the repository at this point in the history
  • Loading branch information
shmygol committed Apr 27, 2016
1 parent 13e8de4 commit 52630bf
Show file tree
Hide file tree
Showing 4 changed files with 370 additions and 0 deletions.
55 changes: 55 additions & 0 deletions src/AppserverIo/WebServer/Modules/SsiModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ class SsiModule implements HttpModuleInterface, ModuleConfigurationAwareInterfac
*/
protected $moduleConfiguration;

protected function _parseDirectiveEcho($tag, $variables)
{
$tagParts = explode(' ', $tag);
if (count($tagParts) !== 3) {
return false;
}
$varName = substr($tagParts[1], 5, strlen($tagParts[1]) - 6);
return (isset($variables[$varName])) ? $variables[$varName] : false;
}

/**
* Initiates the module
*
Expand Down Expand Up @@ -163,9 +173,54 @@ public function process(RequestInterface $request, ResponseInterface $response,
return false;
}

$response->appendBodyStream('SSI Module');

return true;
}

/**
* Parse the give string
*
* @param string $data The content data to parse
* @return string Parsed string
*/
public function parseContent($data, $variables = array())
{
$matches = array();

$directiveNameRule = '[a-zA-Z_]*';
$paramNameRule = '[a-zA-Z_]*';
$paramValueRule = '"[^"]*"';

preg_match_all('/<!--#(' . $directiveNameRule . ') ((' . $paramNameRule . '=' . $paramValueRule . ' )*)-->/', $data, $matches, PREG_OFFSET_CAPTURE);
$directiveTags = $matches[0];
$directiveNames = $matches[1];

$cursor = 0;
$parsedContent = '';
foreach ($directiveNames as $index => $directiveNameInfo) {
$directiveTag = $directiveTags[$index][0];
$directivePosition = $directiveTags[$index][1];
$directiveName = $directiveNameInfo[0];

$directiveMethodName = '_parseDirective' . $directiveName;
$directiveParsedResult = false;
if (method_exists($this, $directiveMethodName)) {
$directiveParsedResult = $this->$directiveMethodName($directiveTag, $variables);
}

if ($directiveParsedResult !== false) {
$parsedContent .= substr($data, $cursor, $directivePosition - $cursor);
$parsedContent .= $directiveParsedResult;
$cursor = $directivePosition + strlen($directiveTag);
}
}
if (strlen($parsedContent) > 0) {
$parsedContent .= substr($data, $cursor);
}
return $parsedContent;
}

/**
* Returns an array of module names which should be executed first
*
Expand Down
57 changes: 57 additions & 0 deletions tests/AppserverIo/WebServer/Mock/MockModuleXmlConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/**
* \AppserverIo\WebServer\Mock\MockServerConfig
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* PHP version 5
*
* @author Bernhard Wick <bw@appserver.io>
* @copyright 2015 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/

namespace AppserverIo\WebServer\Mock;

use AppserverIo\Server\Configuration\ModuleXmlConfiguration;

/**
* Class MockServerConfig
*
* Mock class for a module configuration
*
* @author Ilya Shmygol <i.shmygol@techdivision.com>
* @copyright 2016 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/
class MockModuleXmlConfiguration extends ModuleXmlConfiguration
{
/**
* Default constructor to eliminate the need for a node.
*
* @param \SimpleXMLElement $node Node to create config from
*/
public function __construct($node)
{
}

/**
* Only functionality we need overwritten is the getRewrites method.
* It will always return an empty array.
*
* @return array
*/
public function getRewrites()
{
return array();
}
}
51 changes: 51 additions & 0 deletions tests/AppserverIo/WebServer/Mock/MockSsiModule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/**
* \AppserverIo\WebServer\Mock\MockSsiModule
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* PHP version 5
*
* @author Bernhard Wick <bw@appserver.io>
* @copyright 2015 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/

namespace AppserverIo\WebServer\Mock;

use AppserverIo\WebServer\Modules\SsiModule;
use AppserverIo\Server\Interfaces\RequestContextInterface;

/**
* Class MockSsiModule
*
* Mocks the SsiModule class to expose additional and hidden functionality
*
* @author Ilya Shmygol <i.shmygol@techdivision.com>
* @copyright 2016 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/
class MockSsiModule extends SsiModule
{

/**
* Needed for simple tests the getRequestContext() method
*
* @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext The request context
*
* @return void
*/
public function setRequestContext(RequestContextInterface $requestContext)
{
$this->requestContext = $requestContext;
}
}
207 changes: 207 additions & 0 deletions tests/AppserverIo/WebServer/Modules/SsiModuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?php

/**
* \AppserverIo\WebServer\Modules\RewriteModuleTest
* \AppserverIo\WebServer\Modules\SsiModuleTest
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
*
* PHP version 5
*
* @author Bernhard Wick <bw@appserver.io>
* @copyright 2015 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/

namespace AppserverIo\WebServer\Modules;

use AppserverIo\Http\HttpRequest;
use AppserverIo\Http\HttpResponse;
use AppserverIo\WebServer\Mock\MockFaultyRequestContext;
use AppserverIo\WebServer\Mock\MockSsiModule;
use AppserverIo\WebServer\Mock\MockServerConfig;
use AppserverIo\WebServer\Mock\MockRequestContext;
use AppserverIo\WebServer\Mock\MockServerContext;
use AppserverIo\Server\Configuration\ModuleXmlConfiguration;
use AppserverIo\Server\Contexts\ServerContext;
use AppserverIo\Server\Dictionaries\EnvVars;
use AppserverIo\Server\Dictionaries\ModuleHooks;

/**
* Class RewriteModuleTest
*
* Basic test class for the SsiModule class.
*
* @author Ilya Shmygol <i.shmygol@techdivision.com>
* @copyright 2016 TechDivision GmbH <info@appserver.io>
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* @link https://github.com/appserver-io/webserver
* @link http://www.appserver.io/
*/
class SsiModuleTest extends \PHPUnit_Framework_TestCase
{
/**
* @var SsiModule
*/
protected $instance;

public function setUp()
{
parent::setUp();
$this->instance = new MockSsiModule();
}

/**
* Tests the init() method
*
* @return void
*/
public function testInitWithException()
{
$mockServerContext = new MockServerContext();
$this->assertTrue($this->instance->init($mockServerContext));
$this->assertSame($mockServerContext, $this->instance->getServerContext());
}

/**
* Tests the getDependencies() method
*
* @return void
*/
public function testGetDependencies()
{
$this->assertEmpty($this->instance->getDependencies());
}

/**
* Tests the getModuleName() method
*
* @return void
*/
public function testGetModuleName()
{
$this->assertEquals('ssi', $this->instance->getModuleName());
}

/**
* Tests the getRequestContext() method
*
* @return void
*/
public function testGetRequestContext()
{
// Prepare mocks required objects
$mockRequestContext = new MockRequestContext();
// Set the request context using mock method MockSsiModule::setRequestContext()
$this->instance->setRequestContext($mockRequestContext);

// Test the method
$this->assertSame($mockRequestContext, $this->instance->getRequestContext());
}

public function testInjectModuleConfiguration()
{
// Prepare mocks required objects
$emptyXml = new \SimpleXMLElement('<config></config>');
$mockModuleConfiguration = new ModuleXmlConfiguration($emptyXml);

// Test the method
$this->instance->injectModuleConfiguration($mockModuleConfiguration);
$this->assertSame($mockModuleConfiguration, $this->instance->getModuleConfiguration());
}

/**
* Tests that module proceed only for the right hook
*
* @return void
*/
public function testProcessWithWrongHook()
{
// Prepare mocks required objects
$request = new HttpRequest();
$response = new HttpResponse();
$mockRequestContext = new MockRequestContext();

// Test the method
$this->assertFalse(
$this->instance->process($request, $response, $mockRequestContext, ModuleHooks::REQUEST_PRE)
);
$this->assertFalse(
$this->instance->process($request, $response, $mockRequestContext, ModuleHooks::REQUEST_POST)
);
$this->assertFalse(
$this->instance->process($request, $response, $mockRequestContext, ModuleHooks::RESPONSE_POST)
);
}

/**
* Tests 'echo' directive with server vars
*
* @return void
*/
public function testParseEchoServerVariables()
{
$data = 'Server var: <!--#echo var="SCRIPT_FILENAME" -->; <!--#echo var="REQUEST_TIME" -->; <!--#echo var="MISSING_VARIABLE" -->;';

$expected = 'Server var: index.html; 1461700219; <!--#echo var="MISSING_VARIABLE" -->;';
$actual = $this->instance->parseContent($data, array('SCRIPT_FILENAME' => 'index.html', 'REQUEST_TIME' => '1461700219'));
$this->assertEquals($expected, $actual);
}

/**
* Tests data without directives to parse
*
* @return void
*/
public function testParseEchoMissingVariables()
{
$data = 'Nothing to parse here';

$expected = '';
$actual = $this->instance->parseContent($data);
$this->assertEquals($expected, $actual);
}

/**
* Tests wrong directive names and formats
*
* @return void
*/
public function testParseUnexpectedNestedDirectives()
{
$data = 'Foo <!--#echo var="SCRIPT_FILENAME" <!--#echo var="SCRIPT_FILENAME" --> -->';

$expected = 'Foo <!--#echo var="SCRIPT_FILENAME" index.html -->';
$actual = $this->instance->parseContent($data, array('SCRIPT_FILENAME' => 'index.html', 'REQUEST_TIME' => '1461700219'));
$this->assertEquals($expected, $actual);
}

/**
* Tests wrong directive names and formats
*
* @return void
*/
public function testParseWrongDirectives()
{
$data = 'This part should be correct parsed: <!--#echo var="SCRIPT_FILENAME" -->';
$data .= 'Not existing directive: <!--#foo var="SCRIPT_FILENAME" -->; ';
$data .= 'Single quotes instead of double ones: <!--#foo var=\'SCRIPT_FILENAME\' -->';
$data .= 'The space before #: <!-- #echo var="SCRIPT_FILENAME" -->';
$data .= 'Not closed tag: <!--#echo var="SCRIPT_FILENAME"';

$expected = 'This part should be correct parsed: index.html';
$expected .= 'Not existing directive: <!--#foo var="SCRIPT_FILENAME" -->; ';
$expected .= 'Single quotes instead of double ones: <!--#foo var=\'SCRIPT_FILENAME\' -->';
$expected .= 'The space before #: <!-- #echo var="SCRIPT_FILENAME" -->';
$expected .= 'Not closed tag: <!--#echo var="SCRIPT_FILENAME"';

$actual = $this->instance->parseContent($data, array('SCRIPT_FILENAME' => 'index.html', 'REQUEST_TIME' => '1461700219'));
$this->assertEquals($expected, $actual);
}
}

0 comments on commit 52630bf

Please sign in to comment.